diff --git a/BUILD.gn b/BUILD.gn
index 2f5e693..ed615866 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1014,15 +1014,6 @@
   }
 }
 
-# For compatibility with GYP. The linux_chromium_chromeos_rel_ng and
-# linux_chromium_chromeos_compile_rel_ng bots reference this target as
-# something to build, but all targets for those bots to compile are set
-# up differently.
-# TODO bug 601920: Remove reference to aura_builder on bot config and delete
-# this group.
-group("aura_builder") {
-}
-
 if (is_android) {
   group("optimize_gn_gen") {
     deps = [
diff --git a/DEPS b/DEPS
index 1f18b40f..dea6d526 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': 'baf41bd1c8d9d3741349d6cc531d0bfc3df96f92',
+  'skia_revision': 'c6912f712f3423b2a09a6e96c999b65a1fd86062',
   # 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': '35b77a36bca2291526a697cd4dec93d63f13508c',
+  'v8_revision': '4bb4a24ef43b3cad1288c7f4299af118c13db4c8',
   # 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.
@@ -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': '5be0b291bce26e1a12c9a7becb7c9a9e7857a456',
+  'pdfium_revision': 'a64cd6c86438636b031e1204057b27a8b9673296',
   # 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': '861d4a17413608f1a3f93f3dc503c7d2f3305cfa',
+  'catapult_revision': 'c294424b587eb0a331556f215cacb5b22e066438',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -154,7 +154,7 @@
     Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '42bc671f47b122fad36db5eccbc06868afdf7862',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'c844075aa0f1758d04f9192825f1b1e7e607992e',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ae18d60831126f902d778541495194380ff77fd8',
 
   'src/third_party/hunspell_dictionaries':
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'dc6e7c25bf47cbfb466e0701fd2728b4a12e79d5',
diff --git a/android_webview/browser/aw_web_contents_view_delegate.cc b/android_webview/browser/aw_web_contents_view_delegate.cc
index c42bcac1..ac878b8 100644
--- a/android_webview/browser/aw_web_contents_view_delegate.cc
+++ b/android_webview/browser/aw_web_contents_view_delegate.cc
@@ -38,7 +38,7 @@
   content::ContentViewCore* content_view_core =
       content::ContentViewCore::FromWebContents(web_contents_);
   if (content_view_core)
-    content_view_core->ShowPastePopup(params);
+    content_view_core->ShowSelectionMenu(params);
 }
 
 }  // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index e397fb0ba..9944a1eb 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -848,6 +848,7 @@
     "//components/quirks",
     "//components/session_manager:base",
     "//components/signin/core/account_id",
+    "//components/strings:components_strings",
     "//components/ui_devtools",
     "//components/user_manager",
     "//components/vector_icons",
diff --git a/ash/DEPS b/ash/DEPS
index b667574..9be21a84 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -6,6 +6,7 @@
   "+components/quirks",
   "+components/session_manager",
   "+components/signin/core/account_id",
+  "+components/strings",
   "+components/ui_devtools",
   "+components/user_manager",
   "+components/vector_icons",
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
index 4b4e5e28..00dd3bc 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "ash/ash_layout_constants.h"
 #include "ash/frame/caption_buttons/frame_caption_button.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index b60873c..0ca88d9 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -7,7 +7,6 @@
 #include "ash/ash_layout_constants.h"
 #include "ash/frame/caption_buttons/frame_caption_button.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
diff --git a/ash/strings/BUILD.gn b/ash/strings/BUILD.gn
index b6c7fe1..8225c4b 100644
--- a/ash/strings/BUILD.gn
+++ b/ash/strings/BUILD.gn
@@ -77,6 +77,7 @@
     # Each input pak file should also have a deps line for completeness.
     sources = [
       "$root_gen_dir/ash/strings/ash_strings_${locale}.pak",
+      "$root_gen_dir/components/strings/components_strings_${locale}.pak",
       "$root_gen_dir/device/bluetooth/strings/bluetooth_strings_${locale}.pak",
       "$root_gen_dir/ui/chromeos/strings/ui_chromeos_strings_${locale}.pak",
       "$root_gen_dir/ui/strings/app_locale_settings_${locale}.pak",
@@ -85,6 +86,7 @@
 
     deps = [
       "//ash/strings",
+      "//components/strings:components_strings",
       "//device/bluetooth/strings",
       "//ui/chromeos/strings",
       "//ui/strings:app_locale_settings",
diff --git a/ash/system/bluetooth/tray_bluetooth.cc b/ash/system/bluetooth/tray_bluetooth.cc
index c5a70d2..222f4cd 100644
--- a/ash/system/bluetooth/tray_bluetooth.cc
+++ b/ash/system/bluetooth/tray_bluetooth.cc
@@ -9,7 +9,6 @@
 #include <set>
 #include <string>
 
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
diff --git a/ash/system/brightness/tray_brightness.cc b/ash/system/brightness/tray_brightness.cc
index 9560b45..c79eab5 100644
--- a/ash/system/brightness/tray_brightness.cc
+++ b/ash/system/brightness/tray_brightness.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/shell_observer.h"
diff --git a/ash/system/ime/tray_ime_chromeos.cc b/ash/system/ime/tray_ime_chromeos.cc
index 0b3d22c..85165a6 100644
--- a/ash/system/ime/tray_ime_chromeos.cc
+++ b/ash/system/ime/tray_ime_chromeos.cc
@@ -26,8 +26,10 @@
 #include "ash/system/tray_accessibility.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/strings/grit/components_strings.h"
 #include "ui/accessibility/ax_enums.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/image/image.h"
@@ -38,6 +40,8 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/widget/widget.h"
 
+using chromeos::input_method::InputMethodManager;
+
 namespace ash {
 namespace tray {
 
@@ -270,7 +274,11 @@
   delegate->GetCurrentIME(&current_ime_);
   delegate->GetAvailableIMEList(&ime_list_);
   delegate->GetCurrentIMEProperties(&property_list_);
-  ime_managed_message_ = delegate->GetIMEManagedMessage();
+  auto ime_state = InputMethodManager::Get()->GetActiveIMEState();
+  ime_managed_message_ =
+      ime_state->GetAllowedInputMethods().empty()
+          ? base::string16()
+          : l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY);
 
   Update();
 }
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc
index d93455a..8f2e655f 100644
--- a/ash/system/ime_menu/ime_list_view.cc
+++ b/ash/system/ime_menu/ime_list_view.cc
@@ -5,7 +5,6 @@
 #include "ash/system/ime_menu/ime_list_view.h"
 
 #include "ash/ime/ime_switch_type.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index 8ce57888..b0c7fde 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -6,7 +6,6 @@
 
 #include "ash/accessibility_delegate.h"
 #include "ash/ash_constants.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc
index 10ea62d8..ceb41df 100644
--- a/ash/system/ime_menu/ime_menu_tray_unittest.cc
+++ b/ash/system/ime_menu/ime_menu_tray_unittest.cc
@@ -25,6 +25,8 @@
 #include "ui/views/controls/label.h"
 
 using base::UTF8ToUTF16;
+using chromeos::input_method::InputMethodManager;
+using chromeos::input_method::MockInputMethodManager;
 
 namespace ash {
 
@@ -32,10 +34,38 @@
   return StatusAreaWidgetTestHelper::GetStatusAreaWidget()->ime_menu_tray();
 }
 
+// An InputMethodManager that always returns an active IME state.
+class TestInputMethodManager : public MockInputMethodManager {
+ public:
+  TestInputMethodManager() : state_(new MockInputMethodManager::State) {}
+  ~TestInputMethodManager() override = default;
+
+  // MockInputMethodManager:
+  scoped_refptr<InputMethodManager::State> GetActiveIMEState() override {
+    return state_;
+  }
+
+  scoped_refptr<MockInputMethodManager::State> state_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestInputMethodManager);
+};
+
 class ImeMenuTrayTest : public test::AshTestBase {
  public:
-  ImeMenuTrayTest() {}
-  ~ImeMenuTrayTest() override {}
+  ImeMenuTrayTest() = default;
+  ~ImeMenuTrayTest() override = default;
+
+  // test::AshTestBase:
+  void SetUp() override {
+    test::AshTestBase::SetUp();
+    // Takes ownership.
+    InputMethodManager::Initialize(new TestInputMethodManager);
+  }
+  void TearDown() override {
+    InputMethodManager::Shutdown();
+    test::AshTestBase::TearDown();
+  }
 
  protected:
   // Returns true if the IME menu tray is visible.
@@ -304,21 +334,23 @@
 }
 
 TEST_F(ImeMenuTrayTest, ShowEmojiHandwritingVoiceButtons) {
-  FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT);
-  EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons());
+  InputMethodManager* input_method_manager = InputMethodManager::Get();
+  ASSERT_TRUE(input_method_manager);
+  // Feature is enabled.
+  ASSERT_TRUE(input_method_manager->IsEmojiHandwritingVoiceOnImeMenuEnabled());
 
-  chromeos::input_method::InputMethodManager* input_method_manager =
-      chromeos::input_method::InputMethodManager::Get();
-  EXPECT_FALSE(input_method_manager);
-  chromeos::input_method::InputMethodManager::Initialize(
-      new chromeos::input_method::MockInputMethodManager);
-  input_method_manager = chromeos::input_method::InputMethodManager::Get();
-  EXPECT_TRUE(input_method_manager &&
-              input_method_manager->IsEmojiHandwritingVoiceOnImeMenuEnabled());
+  // Text fields should show the buttons.
+  FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT);
   EXPECT_TRUE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons());
 
+  // Password fields should not show the buttons.
   FocusInInputContext(ui::TEXT_INPUT_TYPE_PASSWORD);
   EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons());
+
+  // Lock screen should not show the buttons.
+  BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
+  FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT);
+  EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons());
 }
 
 }  // namespace ash
diff --git a/ash/system/palette/common_palette_tool.cc b/ash/system/palette/common_palette_tool.cc
index 7aae0ed..bf38481e 100644
--- a/ash/system/palette/common_palette_tool.cc
+++ b/ash/system/palette/common_palette_tool.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/palette/common_palette_tool.h"
 
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/system/palette/palette_ids.h"
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 5a6209d8..e82b4e7 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/palette/palette_tray.h"
 
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
diff --git a/ash/system/session/tray_session_length_limit.cc b/ash/system/session/tray_session_length_limit.cc
index a8bcaf58..73014ec 100644
--- a/ash/system/session/tray_session_length_limit.cc
+++ b/ash/system/session/tray_session_length_limit.cc
@@ -8,7 +8,6 @@
 #include <memory>
 #include <utility>
 
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/system/tray/hover_highlight_view.cc b/ash/system/tray/hover_highlight_view.cc
index 00523642..7f7da58 100644
--- a/ash/system/tray/hover_highlight_view.cc
+++ b/ash/system/tray/hover_highlight_view.cc
@@ -12,12 +12,10 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/resources/grit/ui_resources.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/resources/grit/views_resources.h"
 
 namespace ash {
 
diff --git a/ash/system/tray/label_tray_view.cc b/ash/system/tray/label_tray_view.cc
index 8e3ec37..b8cd13d 100644
--- a/ash/system/tray/label_tray_view.cc
+++ b/ash/system/tray/label_tray_view.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/tray/label_tray_view.h"
 
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/tray_constants.h"
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc
index a825be2..5553ad05 100644
--- a/ash/system/tray/system_tray_delegate.cc
+++ b/ash/system/tray/system_tray_delegate.cc
@@ -22,10 +22,6 @@
 
 void SystemTrayDelegate::GetCurrentIMEProperties(IMEPropertyInfoList* list) {}
 
-base::string16 SystemTrayDelegate::GetIMEManagedMessage() {
-  return base::string16();
-}
-
 NetworkingConfigDelegate* SystemTrayDelegate::GetNetworkingConfigDelegate()
     const {
   return nullptr;
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index c0e26de..45d701d0 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -53,9 +53,6 @@
   // Returns a list of properties for the currently selected IME.
   virtual void GetCurrentIMEProperties(IMEPropertyInfoList* list);
 
-  // Returns a non-empty string if IMEs are managed by policy.
-  virtual base::string16 GetIMEManagedMessage();
-
   // Returns NetworkingConfigDelegate. May return nullptr.
   virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() const;
 
diff --git a/ash/system/tray/tray_details_view_unittest.cc b/ash/system/tray/tray_details_view_unittest.cc
index cd13603..45a497d 100644
--- a/ash/system/tray/tray_details_view_unittest.cc
+++ b/ash/system/tray/tray_details_view_unittest.cc
@@ -5,7 +5,6 @@
 #include "ash/system/tray/tray_details_view.h"
 
 #include "ash/ash_view_ids.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_item.h"
diff --git a/ash/system/tray_accessibility.cc b/ash/system/tray_accessibility.cc
index 8f714d0..2f59baa1 100644
--- a/ash/system/tray_accessibility.cc
+++ b/ash/system/tray_accessibility.cc
@@ -30,7 +30,6 @@
 #include "ui/gfx/vector_icon_types.h"
 #include "ui/message_center/message_center.h"
 #include "ui/native_theme/native_theme.h"
-#include "ui/resources/grit/ui_resources.h"
 #include "ui/views/controls/separator.h"
 #include "ui/views/widget/widget.h"
 
diff --git a/ash/system/tray_caps_lock.cc b/ash/system/tray_caps_lock.cc
index 7e6b2b4..8bbd3e8b 100644
--- a/ash/system/tray_caps_lock.cc
+++ b/ash/system/tray_caps_lock.cc
@@ -5,7 +5,6 @@
 #include "ash/system/tray_caps_lock.h"
 
 #include "ash/accessibility_delegate.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
diff --git a/ash/system/user/user_view.cc b/ash/system/user/user_view.cc
index 9ace6f6..c7294b8 100644
--- a/ash/system/user/user_view.cc
+++ b/ash/system/user/user_view.cc
@@ -9,7 +9,6 @@
 
 #include "ash/multi_profile_uma.h"
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index a0d0251f2..9154a43 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -10,7 +10,6 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shell.h"
-#include "ash/strings/grit/ash_strings.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 46b9696..0cf23cc 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -12,7 +12,6 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell_port.h"
-#include "ash/strings/grit/ash_strings.h"
 #include "ash/wm/overview/cleanup_animation_observer.h"
 #include "ash/wm/overview/overview_animation_type.h"
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
@@ -33,7 +32,6 @@
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/transform_util.h"
-#include "ui/strings/grit/ui_strings.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/layout/box_layout.h"
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 7d37750..a265f98 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -37,11 +37,6 @@
   # details and the expected format.
   override_build_date = "N/A"
 
-  # Turn on memory profiling in the task profiler when the heap shim is
-  # available. Profiling can then be enabled at runtime by passing the command
-  # line flag --enable-heap-profiling=task-profiler.
-  enable_memory_task_profiler = use_allocator_shim
-
   # Partition alloc is included by default except iOS.
   use_partition_alloc = !is_ios
 }
@@ -1684,7 +1679,6 @@
   header_dir = "base/debug"
   flags = [
     "ENABLE_PROFILING=$enable_profiling",
-    "ENABLE_MEMORY_TASK_PROFILER=$enable_memory_task_profiler",
     "CAN_UNWIND_WITH_FRAME_POINTERS=$can_unwind_with_frame_pointers",
   ]
 }
diff --git a/base/allocator/allocator_check.cc b/base/allocator/allocator_check.cc
index cae3d2a8..fba38d15 100644
--- a/base/allocator/allocator_check.cc
+++ b/base/allocator/allocator_check.cc
@@ -23,7 +23,7 @@
 namespace allocator {
 
 bool IsAllocatorInitialized() {
-#if defined(OS_WIN) && defined(USE_ALLOCATOR_SHIM)
+#if defined(OS_WIN) && BUILDFLAG(USE_ALLOCATOR_SHIM)
   // Set by allocator_shim_override_ucrt_symbols_win.h when the
   // shimmed _set_new_mode() is called.
   return g_is_win_shim_layer_initialized;
diff --git a/base/base_paths_fuchsia.cc b/base/base_paths_fuchsia.cc
index 6b11bf3..6660823f 100644
--- a/base/base_paths_fuchsia.cc
+++ b/base/base_paths_fuchsia.cc
@@ -9,14 +9,23 @@
 namespace base {
 
 bool PathProviderFuchsia(int key, FilePath* result) {
+  // TODO(fuchsia): There's no API to retrieve these on Fuchsia. The app name
+  // itself should be dynamic (i.e. not always "chrome") but other paths are
+  // correct as fixed paths like this. See https://crbug.com/726124.
   switch (key) {
     case FILE_EXE:
-    case FILE_MODULE: {
-      // TODO(fuchsia): There's no API to retrieve this on Fuchsia currently.
-      // See https://crbug.com/726124.
-      *result = FilePath("/system/chrome");
+      *result = FilePath("/pkg/bin/chrome");
       return true;
-    }
+    case FILE_MODULE:
+      *result = FilePath("/pkg/lib/chrome");
+      return true;
+    case DIR_SOURCE_ROOT:
+      // This is only used for tests, so we return the binary location for now.
+      *result = FilePath("/system");
+      return true;
+    case DIR_CACHE:
+      *result = FilePath("/data");
+      return true;
   }
 
   return false;
diff --git a/base/timer/timer.cc b/base/timer/timer.cc
index 31eec1b..abcd70a 100644
--- a/base/timer/timer.cc
+++ b/base/timer/timer.cc
@@ -11,16 +11,14 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
 #include "base/threading/platform_thread.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/tick_clock.h"
 
 namespace base {
 
-// BaseTimerTaskInternal is a simple delegate for scheduling a callback to
-// Timer in the thread's default task runner. It also handles the following
-// edge cases:
+// BaseTimerTaskInternal is a simple delegate for scheduling a callback to Timer
+// on the current sequence. It also handles the following edge cases:
 // - deleted by the task runner.
 // - abandoned (orphaned) by Timer.
 class BaseTimerTaskInternal {
@@ -34,33 +32,31 @@
     // destructed.  If so, don't leave Timer with a dangling pointer
     // to this.
     if (timer_)
-      timer_->StopAndAbandon();
+      timer_->AbandonAndStop();
   }
 
   void Run() {
-    // timer_ is NULL if we were abandoned.
+    // |timer_| is nullptr if we were abandoned.
     if (!timer_)
       return;
 
-    // *this will be deleted by the task runner, so Timer needs to
-    // forget us:
-    timer_->scheduled_task_ = NULL;
+    // |this| will be deleted by the task runner, so Timer needs to forget us:
+    timer_->scheduled_task_ = nullptr;
 
-    // Although Timer should not call back into *this, let's clear
-    // the timer_ member first to be pedantic.
+    // Although Timer should not call back into |this|, let's clear |timer_|
+    // first to be pedantic.
     Timer* timer = timer_;
-    timer_ = NULL;
+    timer_ = nullptr;
     timer->RunScheduledTask();
   }
 
-  // The task remains in the MessageLoop queue, but nothing will happen when it
-  // runs.
-  void Abandon() {
-    timer_ = NULL;
-  }
+  // The task remains in the queue, but nothing will happen when it runs.
+  void Abandon() { timer_ = nullptr; }
 
  private:
   Timer* timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(BaseTimerTaskInternal);
 };
 
 Timer::Timer(bool retain_user_task, bool is_repeating)
@@ -68,11 +64,16 @@
 
 Timer::Timer(bool retain_user_task, bool is_repeating, TickClock* tick_clock)
     : scheduled_task_(nullptr),
-      thread_id_(0),
       is_repeating_(is_repeating),
       retain_user_task_(retain_user_task),
       tick_clock_(tick_clock),
-      is_running_(false) {}
+      is_running_(false) {
+  // It is safe for the timer to be created on a different thread/sequence than
+  // the one from which the timer APIs are called. The first call to the
+  // checker's CalledOnValidSequence() method will re-bind the checker, and
+  // later calls will verify that the same task runner is used.
+  origin_sequence_checker_.DetachFromSequence();
+}
 
 Timer::Timer(const tracked_objects::Location& posted_from,
              TimeDelta delay,
@@ -89,44 +90,68 @@
       posted_from_(posted_from),
       delay_(delay),
       user_task_(user_task),
-      thread_id_(0),
       is_repeating_(is_repeating),
       retain_user_task_(true),
       tick_clock_(tick_clock),
-      is_running_(false) {}
+      is_running_(false) {
+  // See comment in other constructor.
+  origin_sequence_checker_.DetachFromSequence();
+}
 
 Timer::~Timer() {
-  StopAndAbandon();
+  // TODO(gab): Enable this once Stop() properly detaches from sequence.
+  // DCHECK(origin_sequence_checker_.CalledOnValidSequence());
+  AbandonAndStop();
 }
 
 bool Timer::IsRunning() const {
+  DCHECK(origin_sequence_checker_.CalledOnValidSequence());
   return is_running_;
 }
 
 TimeDelta Timer::GetCurrentDelay() const {
+  DCHECK(origin_sequence_checker_.CalledOnValidSequence());
   return delay_;
 }
 
-void Timer::SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
-  // Do not allow changing the task runner once something has been scheduled.
-  DCHECK_EQ(thread_id_, 0);
+void Timer::SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
+  // Do not allow changing the task runner when the Timer is running.
+  // Don't check for |origin_sequence_checker_.CalledOnValidSequence()| here to
+  // allow the use case of constructing the Timer and immediatetly invoking
+  // SetTaskRunner() before starting it (CalledOnValidSequence() would undo the
+  // DetachFromSequence() from the constructor). The |!is_running| check kind of
+  // verifies the same thing (and TSAN should catch callers that do it wrong but
+  // somehow evade all debug checks).
+  DCHECK(!is_running_);
   task_runner_.swap(task_runner);
 }
 
 void Timer::Start(const tracked_objects::Location& posted_from,
                   TimeDelta delay,
                   const base::Closure& user_task) {
-  SetTaskInfo(posted_from, delay, user_task);
+  DCHECK(origin_sequence_checker_.CalledOnValidSequence());
+
+  posted_from_ = posted_from;
+  delay_ = delay;
+  user_task_ = user_task;
+
   Reset();
 }
 
 void Timer::Stop() {
+  // TODO(gab): Enable this when it's no longer called racily from
+  // RunScheduledTask(): https://crbug.com/587199.
+  // DCHECK(origin_sequence_checker_.CalledOnValidSequence());
+
   is_running_ = false;
   if (!retain_user_task_)
     user_task_.Reset();
+  // No more member accesses here: |this| could be deleted after freeing
+  // |user_task_|.
 }
 
 void Timer::Reset() {
+  DCHECK(origin_sequence_checker_.CalledOnValidSequence());
   DCHECK(!user_task_.is_null());
 
   // If there's no pending task, start one up and return.
@@ -135,41 +160,41 @@
     return;
   }
 
-  // Set the new desired_run_time_.
+  // Set the new |desired_run_time_|.
   if (delay_ > TimeDelta::FromMicroseconds(0))
     desired_run_time_ = Now() + delay_;
   else
     desired_run_time_ = TimeTicks();
 
   // We can use the existing scheduled task if it arrives before the new
-  // desired_run_time_.
+  // |desired_run_time_|.
   if (desired_run_time_ >= scheduled_run_time_) {
     is_running_ = true;
     return;
   }
 
-  // We can't reuse the scheduled_task_, so abandon it and post a new one.
+  // We can't reuse the |scheduled_task_|, so abandon it and post a new one.
   AbandonScheduledTask();
   PostNewScheduledTask(delay_);
 }
 
 TimeTicks Timer::Now() const {
+  // TODO(gab): Enable this when it's no longer called racily from
+  // RunScheduledTask(): https://crbug.com/587199.
+  // DCHECK(origin_sequence_checker_.CalledOnValidSequence());
   return tick_clock_ ? tick_clock_->NowTicks() : TimeTicks::Now();
 }
 
-void Timer::SetTaskInfo(const tracked_objects::Location& posted_from,
-                        TimeDelta delay,
-                        const base::Closure& user_task) {
-  posted_from_ = posted_from;
-  delay_ = delay;
-  user_task_ = user_task;
-}
-
 void Timer::PostNewScheduledTask(TimeDelta delay) {
-  DCHECK(scheduled_task_ == NULL);
+  // TODO(gab): Enable this when it's no longer called racily from
+  // RunScheduledTask(): https://crbug.com/587199.
+  // DCHECK(origin_sequence_checker_.CalledOnValidSequence());
+  DCHECK(!scheduled_task_);
   is_running_ = true;
   scheduled_task_ = new BaseTimerTaskInternal(this);
   if (delay > TimeDelta::FromMicroseconds(0)) {
+    // TODO(gab): Posting BaseTimerTaskInternal::Run to another sequence makes
+    // this code racy. https://crbug.com/587199
     GetTaskRunner()->PostDelayedTask(
         posted_from_,
         base::BindOnce(&BaseTimerTaskInternal::Run,
@@ -182,26 +207,27 @@
                                              base::Owned(scheduled_task_)));
     scheduled_run_time_ = desired_run_time_ = TimeTicks();
   }
-  // Remember the thread ID that posts the first task -- this will be verified
-  // later when the task is abandoned to detect misuse from multiple threads.
-  if (!thread_id_)
-    thread_id_ = static_cast<int>(PlatformThread::CurrentId());
 }
 
-scoped_refptr<SingleThreadTaskRunner> Timer::GetTaskRunner() {
-  return task_runner_.get() ? task_runner_ : ThreadTaskRunnerHandle::Get();
+scoped_refptr<SequencedTaskRunner> Timer::GetTaskRunner() {
+  return task_runner_.get() ? task_runner_ : SequencedTaskRunnerHandle::Get();
 }
 
 void Timer::AbandonScheduledTask() {
-  DCHECK(thread_id_ == 0 ||
-         thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
+  // TODO(gab): Enable this when it's no longer called racily from
+  // RunScheduledTask() -> Stop(): https://crbug.com/587199.
+  // DCHECK(origin_sequence_checker_.CalledOnValidSequence());
   if (scheduled_task_) {
     scheduled_task_->Abandon();
-    scheduled_task_ = NULL;
+    scheduled_task_ = nullptr;
   }
 }
 
 void Timer::RunScheduledTask() {
+  // TODO(gab): Enable this when it's no longer called racily:
+  // https://crbug.com/587199.
+  // DCHECK(origin_sequence_checker_.CalledOnValidSequence());
+
   // Task may have been disabled.
   if (!is_running_)
     return;
@@ -209,10 +235,10 @@
   // First check if we need to delay the task because of a new target time.
   if (desired_run_time_ > scheduled_run_time_) {
     // Now() can be expensive, so only call it if we know the user has changed
-    // the desired_run_time_.
+    // the |desired_run_time_|.
     TimeTicks now = Now();
     // Task runner may have called us late anyway, so only post a continuation
-    // task if the desired_run_time_ is in the future.
+    // task if the |desired_run_time_| is in the future.
     if (desired_run_time_ > now) {
       // Post a new task to span the remaining time.
       PostNewScheduledTask(desired_run_time_ - now);
@@ -221,7 +247,7 @@
   }
 
   // Make a local copy of the task to run. The Stop method will reset the
-  // user_task_ member if retain_user_task_ is false.
+  // |user_task_| member if |retain_user_task_| is false.
   base::Closure task = user_task_;
 
   if (is_repeating_)
@@ -231,7 +257,7 @@
 
   task.Run();
 
-  // No more member accesses here: *this could be deleted at this point.
+  // No more member accesses here: |this| could be deleted at this point.
 }
 
 }  // namespace base
diff --git a/base/timer/timer.h b/base/timer/timer.h
index 8aac279..88958d4 100644
--- a/base/timer/timer.h
+++ b/base/timer/timer.h
@@ -35,11 +35,17 @@
 // Both OneShotTimer and RepeatingTimer also support a Reset method, which
 // allows you to easily defer the timer event until the timer delay passes once
 // again.  So, in the above example, if 0.5 seconds have already passed,
-// calling Reset on timer_ would postpone DoStuff by another 1 second.  In
+// calling Reset on |timer_| would postpone DoStuff by another 1 second.  In
 // other words, Reset is shorthand for calling Stop and then Start again with
 // the same arguments.
 //
-// NOTE: These APIs are not thread safe. Always call from the same thread.
+// These APIs are not thread safe. All methods must be called from the same
+// sequence (not necessarily the construction sequence), except for the
+// destructor and SetTaskRunner() which may be called from any sequence when the
+// timer is not running (i.e. when Start() has never been called or Stop() has
+// been called since the last Start()). By default, the scheduled tasks will be
+// run on the same sequence that the Timer was *started on*, but this can be
+// changed *prior* to Start() via SetTaskRunner().
 
 #ifndef BASE_TIMER_TIMER_H_
 #define BASE_TIMER_TIMER_H_
@@ -57,26 +63,29 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/sequence_checker_impl.h"
+#include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
 
 namespace base {
 
 class BaseTimerTaskInternal;
-class SingleThreadTaskRunner;
 class TickClock;
 
+// TODO(gab): Removing this fwd-decl causes IWYU failures in other headers,
+// remove it in a follow- up CL.
+class SingleThreadTaskRunner;
+
 //-----------------------------------------------------------------------------
-// This class wraps MessageLoop::PostDelayedTask to manage delayed and repeating
-// tasks. It must be destructed on the same thread that starts tasks. There are
-// DCHECKs in place to verify this.
+// This class wraps TaskRunner::PostDelayedTask to manage delayed and repeating
+// tasks. See meta comment above for thread-safety requirements.
 //
 class BASE_EXPORT Timer {
  public:
-  // Construct a timer in repeating or one-shot mode. Start or SetTaskInfo must
-  // be called later to set task info. |retain_user_task| determines whether the
-  // user_task is retained or reset when it runs or stops. If |tick_clock| is
-  // provided, it is used instead of TimeTicks::Now() to get TimeTicks when
-  // scheduling tasks.
+  // Construct a timer in repeating or one-shot mode. Start must be called later
+  // to set task info. |retain_user_task| determines whether the user_task is
+  // retained or reset when it runs or stops. If |tick_clock| is provided, it is
+  // used instead of TimeTicks::Now() to get TimeTicks when scheduling tasks.
   Timer(bool retain_user_task, bool is_repeating);
   Timer(bool retain_user_task, bool is_repeating, TickClock* tick_clock);
 
@@ -101,9 +110,11 @@
   virtual TimeDelta GetCurrentDelay() const;
 
   // Set the task runner on which the task should be scheduled. This method can
-  // only be called before any tasks have been scheduled. The task runner must
-  // run tasks on the same thread the timer is used on.
-  virtual void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
+  // only be called before any tasks have been scheduled. If |task_runner| runs
+  // tasks on a different sequence than the sequence owning this Timer,
+  // |user_task_| will be posted to it when the Timer fires (note that this
+  // means |user_task_| can run after ~Timer() and should support that).
+  void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner);
 
   // Start the timer to run at the given |delay| from now. If the timer is
   // already running, it will be replaced to call the given |user_task|.
@@ -115,7 +126,7 @@
   // is not running.
   virtual void Stop();
 
-  // Call this method to reset the timer delay. The user_task_ must be set. If
+  // Call this method to reset the timer delay. The |user_task_| must be set. If
   // the timer is not running, this will start it by posting a task.
   virtual void Reset();
 
@@ -126,12 +137,6 @@
   // Returns the current tick count.
   TimeTicks Now() const;
 
-  // Used to initiate a new delayed task.  This has the side-effect of disabling
-  // scheduled_task_ if it is non-null.
-  void SetTaskInfo(const tracked_objects::Location& posted_from,
-                   TimeDelta delay,
-                   const base::Closure& user_task);
-
   void set_user_task(const Closure& task) { user_task_ = task; }
   void set_desired_run_time(TimeTicks desired) { desired_run_time_ = desired; }
   void set_is_running(bool running) { is_running_ = running; }
@@ -144,74 +149,74 @@
  private:
   friend class BaseTimerTaskInternal;
 
-  // Allocates a new scheduled_task_ and posts it on the current MessageLoop
-  // with the given |delay|. scheduled_task_ must be NULL. scheduled_run_time_
-  // and desired_run_time_ are reset to Now() + delay.
+  // Allocates a new |scheduled_task_| and posts it on the current sequence with
+  // the given |delay|. |scheduled_task_| must be null. |scheduled_run_time_|
+  // and |desired_run_time_| are reset to Now() + delay.
   void PostNewScheduledTask(TimeDelta delay);
 
   // Returns the task runner on which the task should be scheduled. If the
-  // corresponding task_runner_ field is null, the task runner for the current
-  // thread is returned.
-  scoped_refptr<SingleThreadTaskRunner> GetTaskRunner();
+  // corresponding |task_runner_| field is null, the task runner for the current
+  // sequence is returned.
+  scoped_refptr<SequencedTaskRunner> GetTaskRunner();
 
-  // Disable scheduled_task_ and abandon it so that it no longer refers back to
-  // this object.
+  // Disable |scheduled_task_| and abandon it so that it no longer refers back
+  // to this object.
   void AbandonScheduledTask();
 
-  // Called by BaseTimerTaskInternal when the MessageLoop runs it.
+  // Called by BaseTimerTaskInternal when the delayed task fires.
   void RunScheduledTask();
 
   // Stop running task (if any) and abandon scheduled task (if any).
-  void StopAndAbandon() {
+  void AbandonAndStop() {
     AbandonScheduledTask();
 
     Stop();
     // No more member accesses here: |this| could be deleted at this point.
   }
 
-  // When non-NULL, the scheduled_task_ is waiting in the MessageLoop to call
-  // RunScheduledTask() at scheduled_run_time_.
+  // When non-null, the |scheduled_task_| was posted to call RunScheduledTask()
+  // at |scheduled_run_time_|.
   BaseTimerTaskInternal* scheduled_task_;
 
   // The task runner on which the task should be scheduled. If it is null, the
-  // task runner for the current thread should be used.
-  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+  // task runner for the current sequence will be used.
+  scoped_refptr<SequencedTaskRunner> task_runner_;
 
   // Location in user code.
   tracked_objects::Location posted_from_;
   // Delay requested by user.
   TimeDelta delay_;
-  // user_task_ is what the user wants to be run at desired_run_time_.
+  // |user_task_| is what the user wants to be run at |desired_run_time_|.
   base::Closure user_task_;
 
-  // The estimated time that the MessageLoop will run the scheduled_task_ that
-  // will call RunScheduledTask(). This time can be a "zero" TimeTicks if the
-  // task must be run immediately.
+  // The time at which |scheduled_task_| is expected to fire. This time can be a
+  // "zero" TimeTicks if the task must be run immediately.
   TimeTicks scheduled_run_time_;
 
-  // The desired run time of user_task_. The user may update this at any time,
-  // even if their previous request has not run yet. If desired_run_time_ is
-  // greater than scheduled_run_time_, a continuation task will be posted to
+  // The desired run time of |user_task_|. The user may update this at any time,
+  // even if their previous request has not run yet. If |desired_run_time_| is
+  // greater than |scheduled_run_time_|, a continuation task will be posted to
   // wait for the remaining time. This allows us to reuse the pending task so as
-  // not to flood the MessageLoop with orphaned tasks when the user code
+  // not to flood the delayed queues with orphaned tasks when the user code
   // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks
   // if the task must be run immediately.
   TimeTicks desired_run_time_;
 
-  // Thread ID of current MessageLoop for verifying single-threaded usage.
-  int thread_id_;
+  // Timer isn't thread-safe and must only be used on its origin sequence
+  // (sequence on which it was started).
+  SequenceChecker origin_sequence_checker_;
 
   // Repeating timers automatically post the task again before calling the task
   // callback.
   const bool is_repeating_;
 
-  // If true, hold on to the user_task_ closure object for reuse.
+  // If true, hold on to the |user_task_| closure object for reuse.
   const bool retain_user_task_;
 
   // The tick clock used to calculate the run time for scheduled tasks.
   TickClock* const tick_clock_;
 
-  // If true, user_task_ is scheduled to run sometime in the future.
+  // If true, |user_task_| is scheduled to run sometime in the future.
   bool is_running_;
 
   DISALLOW_COPY_AND_ASSIGN(Timer);
@@ -266,8 +271,8 @@
 
 //-----------------------------------------------------------------------------
 // A Delay timer is like The Button from Lost. Once started, you have to keep
-// calling Reset otherwise it will call the given method in the MessageLoop
-// thread.
+// calling Reset otherwise it will call the given method on the sequence it was
+// initially Reset() from.
 //
 // Once created, it is inactive until Reset is called. Once |delay| seconds have
 // passed since the last call to Reset, the callback is made. Once the callback
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
index 69338eb2..fd1fff5 100644
--- a/base/timer/timer_unittest.cc
+++ b/base/timer/timer_unittest.cc
@@ -17,14 +17,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/sequenced_worker_pool_owner.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -108,14 +106,14 @@
 
   ~OneShotTimerTester() override = default;
 
-  void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
     timer_->SetTaskRunner(std::move(task_runner));
 
     // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure
     // needs to run on this thread (where the MessageLoop lives).
-    quit_closure_ =
-        Bind(IgnoreResult(&SingleThreadTaskRunner::PostTask),
-             ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure());
+    quit_closure_ = Bind(IgnoreResult(&SequencedTaskRunner::PostTask),
+                         SequencedTaskRunnerHandle::Get(), FROM_HERE,
+                         run_loop_.QuitClosure());
   }
 
   // Blocks until Run() executes and confirms that Run() didn't fire before
@@ -668,6 +666,8 @@
   EXPECT_TRUE(timer.IsRunning());
 }
 
+//-----------------------------------------------------------------------------
+
 namespace {
 
 bool g_callback_happened1 = false;
@@ -721,4 +721,206 @@
   }
 }
 
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Fixture for tests requiring a worker pool. Includes a WaitableEvent so
+// that cases may Wait() on one thread and Signal() (explicitly, or implicitly
+// via helper methods) on another.
+class TimerSequenceTest : public testing::Test {
+ public:
+  TimerSequenceTest()
+      : event_(WaitableEvent::ResetPolicy::AUTOMATIC,
+               WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+  void SetUp() override {
+    pool1_owner_.reset(
+        new SequencedWorkerPoolOwner(kNumWorkerThreads, "test1"));
+    pool2_owner_.reset(
+        new SequencedWorkerPoolOwner(kNumWorkerThreads, "test2"));
+  }
+
+  // Block until Signal() is called on another thread.
+  void Wait() { event_.Wait(); }
+
+  void Signal() { event_.Signal(); }
+
+  // Helper to augment a task with a subsequent call to Signal().
+  Closure TaskWithSignal(const Closure& task) {
+    return Bind(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), task);
+  }
+
+  // Create the timer.
+  void CreateTimer() { timer_.reset(new OneShotTimer); }
+
+  // Schedule an event on the timer.
+  void StartTimer(TimeDelta delay, const Closure& task) {
+    timer_->Start(FROM_HERE, delay, task);
+  }
+
+  void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) {
+    timer_->SetTaskRunner(std::move(task_runner));
+  }
+
+  // Tell the timer to abandon the task.
+  void AbandonTask() {
+    EXPECT_TRUE(timer_->IsRunning());
+    // Reset() to call Timer::AbandonScheduledTask()
+    timer_->Reset();
+    EXPECT_TRUE(timer_->IsRunning());
+    timer_->Stop();
+    EXPECT_FALSE(timer_->IsRunning());
+  }
+
+  static void VerifyAffinity(const SequencedTaskRunner* task_runner) {
+    EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+  }
+
+  // Delete the timer.
+  void DeleteTimer() { timer_.reset(); }
+
+ protected:
+  const scoped_refptr<SequencedWorkerPool>& pool1() {
+    return pool1_owner_->pool();
+  }
+  const scoped_refptr<SequencedWorkerPool>& pool2() {
+    return pool2_owner_->pool();
+  }
+
+ private:
+  void RunTaskAndSignal(const Closure& task) {
+    task.Run();
+    Signal();
+  }
+
+  WaitableEvent event_;
+
+  MessageLoop message_loop_;
+  std::unique_ptr<SequencedWorkerPoolOwner> pool1_owner_;
+  std::unique_ptr<SequencedWorkerPoolOwner> pool2_owner_;
+
+  std::unique_ptr<OneShotTimer> timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest);
+};
+
+}  // namespace
+
+TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) {
+  scoped_refptr<SequencedTaskRunner> task_runner =
+      pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+
+  base::RunLoop run_loop_;
+
+  // Timer is created on this thread.
+  CreateTimer();
+
+  // Task will execute on a pool thread.
+  SetTaskRunnerForTimer(task_runner);
+  StartTimer(TimeDelta::FromMilliseconds(1),
+             Bind(IgnoreResult(&SequencedTaskRunner::PostTask),
+                  SequencedTaskRunnerHandle::Get(), FROM_HERE,
+                  run_loop_.QuitClosure()));
+
+  // Spin the loop so that the delayed task fires on it, which will forward it
+  // to |task_runner|. And since the Timer's task is one that posts back to this
+  // MessageLoop to quit, we finally unblock.
+  run_loop_.Run();
+
+  // Timer will be destroyed on this thread.
+  DeleteTimer();
+}
+
+TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) {
+  scoped_refptr<SequencedTaskRunner> task_runner =
+      pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+
+  // Timer is created on this thread.
+  CreateTimer();
+
+  // Task will be scheduled from a pool thread.
+  task_runner->PostTask(
+      FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this),
+                      TimeDelta::FromMilliseconds(1),
+                      Bind(&TimerSequenceTest::Signal, Unretained(this))));
+  Wait();
+
+  // Timer must be destroyed on pool thread, too.
+  task_runner->PostTask(
+      FROM_HERE,
+      TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this))));
+  Wait();
+}
+
+TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) {
+  scoped_refptr<SequencedTaskRunner> task_runner1 =
+      pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+  scoped_refptr<SequencedTaskRunner> task_runner2 =
+      pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken());
+
+  // Create timer on pool #1.
+  task_runner1->PostTask(
+      FROM_HERE,
+      TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this))));
+  Wait();
+
+  // And tell it to execute on a different pool (#2).
+  task_runner1->PostTask(
+      FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer,
+                                     Unretained(this), task_runner2)));
+  Wait();
+
+  // Task will be scheduled from pool #1.
+  task_runner1->PostTask(FROM_HERE,
+                         Bind(&TimerSequenceTest::StartTimer, Unretained(this),
+                              TimeDelta::FromHours(1), Bind(&DoNothing)));
+
+  // Abandon task - must be called from scheduling pool (#1).
+  task_runner1->PostTask(
+      FROM_HERE,
+      TaskWithSignal(Bind(&TimerSequenceTest::AbandonTask, Unretained(this))));
+  Wait();
+
+  // Timer must be destroyed on the pool it was scheduled from (#1).
+  task_runner1->PostTask(
+      FROM_HERE,
+      TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this))));
+  Wait();
+}
+
+TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) {
+  scoped_refptr<SequencedTaskRunner> task_runner1 =
+      pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken());
+  scoped_refptr<SequencedTaskRunner> task_runner2 =
+      pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken());
+
+  // Create timer on pool #1.
+  task_runner1->PostTask(
+      FROM_HERE,
+      TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this))));
+  Wait();
+
+  // And tell it to execute on a different pool (#2).
+  task_runner1->PostTask(
+      FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer,
+                                     Unretained(this), task_runner2)));
+  Wait();
+
+  // Task will be scheduled from pool #1.
+  task_runner1->PostTask(
+      FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this),
+                      TimeDelta::FromMilliseconds(1),
+                      TaskWithSignal(Bind(&TimerSequenceTest::VerifyAffinity,
+                                          Unretained(task_runner2.get())))));
+
+  Wait();
+
+  // Timer must be destroyed on the pool it was scheduled from (#1).
+  task_runner1->PostTask(
+      FROM_HERE,
+      TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this))));
+  Wait();
+}
+
 }  // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 008b22a..59e5629b 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -213,13 +213,13 @@
     AllocationContextTracker::SetCaptureMode(
         AllocationContextTracker::CaptureMode::NATIVE_STACK);
 #endif  // !defined(OS_NACL)
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   } else if (profiling_mode == switches::kEnableHeapProfilingTaskProfiler) {
     // Enable heap tracking, which in turn enables capture of heap usage
     // tracking in tracked_objects.cc.
     if (!base::debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled())
       base::debug::ThreadHeapUsageTracker::EnableHeapTracking();
-#endif  // BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#endif  // BUILDFLAG(USE_ALLOCATOR_SHIM)
   } else {
     LOG(FATAL) << "Invalid mode '" << profiling_mode << "' for "
                << switches::kEnableHeapProfiling << " flag.";
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index d7865274..f8dbdbc 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -699,7 +699,7 @@
   }  // Release lock ASAP.
   death_data->RecordDurations(queue_duration, run_duration, random_number_);
 
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   if (stopwatch.heap_tracking_enabled()) {
     base::debug::ThreadHeapUsage heap_usage = stopwatch.heap_usage().usage();
     // Saturate the 64 bit counts on conversion to 32 bit storage.
@@ -1044,7 +1044,7 @@
   state_ = CREATED;
   child_ = NULL;
 #endif
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   heap_tracking_enabled_ =
       base::debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled();
 #endif
@@ -1064,7 +1064,7 @@
 #endif
 
   start_time_ = ThreadData::Now();
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   if (heap_tracking_enabled_)
     heap_usage_.Start();
 #endif
@@ -1091,7 +1091,7 @@
   state_ = STOPPED;
   DCHECK(child_ == NULL);
 #endif
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   if (heap_tracking_enabled_)
     heap_usage_.Stop(true);
 #endif
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 7ec6eae..b1355d52 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -853,7 +853,7 @@
   // this thread during that period.
   int32_t RunDurationMs() const;
 
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   const base::debug::ThreadHeapUsageTracker& heap_usage() const {
     return heap_usage_;
   }
@@ -867,7 +867,7 @@
   // Time when the stopwatch was started.
   TrackedTime start_time_;
 
-#if BUILDFLAG(ENABLE_MEMORY_TASK_PROFILER)
+#if BUILDFLAG(USE_ALLOCATOR_SHIM)
   base::debug::ThreadHeapUsageTracker heap_usage_;
   bool heap_tracking_enabled_;
 #endif
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index e357a9ef..4600b3e2 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -245,6 +245,9 @@
 
     // http://crbug.com/587199
     "race:base::TimerTest_OneShotTimer_CustomTaskRunner_Test::TestBody\n"
+    "race:base::TimerSequenceTest_OneShotTimerTaskOnPoolThread_Test::TestBody\n"
+    "race:base::TimerSequenceTest_OneShotTimerUsedAndTaskedOnDifferentPools_"
+    "Test::TestBody\n"
 
     // http://crbug.com/v8/6065
     "race:net::(anonymous namespace)::ProxyResolverV8TracingImpl::RequestImpl"
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index 4447a58..4fd1483 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -183,7 +183,8 @@
   if (!op->IsDrawOp())
     return false;
 
-  op->RasterWithAlpha(canvas, save_item.alpha);
+  SkRect bounds = save_item.has_bounds ? save_item.bounds : PaintOp::kUnsetRect;
+  op->RasterWithAlpha(canvas, bounds, save_item.alpha);
   return true;
 }
 
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 3d1ce30..b52b5555 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -55,9 +55,10 @@
 NOINLINE static void RasterWithAlphaInternal(RasterFunction raster_fn,
                                              const PaintOp* op,
                                              SkCanvas* canvas,
+                                             const SkRect& bounds,
                                              uint8_t alpha) {
-  // TODO(enne): is it ok to just drop the bounds here?
-  canvas->saveLayerAlpha(nullptr, alpha);
+  bool unset = bounds.x() == PaintOp::kUnsetRect.x();
+  canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha);
   SkMatrix unused_matrix;
   raster_fn(op, canvas, unused_matrix);
   canvas->restore();
@@ -67,12 +68,15 @@
 // have or don't have PaintFlags.
 template <typename T, bool HasFlags>
 struct Rasterizer {
-  static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
+  static void RasterWithAlpha(const T* op,
+                              SkCanvas* canvas,
+                              const SkRect& bounds,
+                              uint8_t alpha) {
     static_assert(
         !T::kHasPaintFlags,
         "This function should not be used for a PaintOp that has PaintFlags");
     DCHECK(T::kIsDrawOp);
-    RasterWithAlphaInternal(&T::Raster, op, canvas, alpha);
+    RasterWithAlphaInternal(&T::Raster, op, canvas, bounds, alpha);
   }
 };
 
@@ -80,6 +84,7 @@
     RasterWithFlagsFunction raster_fn,
     const PaintOpWithFlags* op,
     SkCanvas* canvas,
+    const SkRect& bounds,
     uint8_t alpha) {
   SkMatrix unused_matrix;
   if (alpha == 255) {
@@ -89,7 +94,8 @@
     flags.setAlpha(SkMulDiv255Round(flags.getAlpha(), alpha));
     raster_fn(op, &flags, canvas, unused_matrix);
   } else {
-    canvas->saveLayerAlpha(nullptr, alpha);
+    bool unset = bounds.x() == PaintOp::kUnsetRect.x();
+    canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha);
     raster_fn(op, &op->flags, canvas, unused_matrix);
     canvas->restore();
   }
@@ -97,11 +103,15 @@
 
 template <typename T>
 struct Rasterizer<T, true> {
-  static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
+  static void RasterWithAlpha(const T* op,
+                              SkCanvas* canvas,
+                              const SkRect& bounds,
+                              uint8_t alpha) {
     static_assert(T::kHasPaintFlags,
                   "This function expects the PaintOp to have PaintFlags");
     DCHECK(T::kIsDrawOp);
-    RasterWithAlphaInternalForFlags(&T::RasterWithFlags, op, canvas, alpha);
+    RasterWithAlphaInternalForFlags(&T::RasterWithFlags, op, canvas, bounds,
+                                    alpha);
   }
 };
 
@@ -109,6 +119,7 @@
 struct Rasterizer<DrawRecordOp, false> {
   static void RasterWithAlpha(const DrawRecordOp* op,
                               SkCanvas* canvas,
+                              const SkRect& bounds,
                               uint8_t alpha) {
     // This "looking into records" optimization is done here instead of
     // in the PaintOpBuffer::Raster function as DisplayItemList calls
@@ -117,12 +128,13 @@
       PaintOp* single_op = op->record->GetFirstOp();
       // RasterWithAlpha only supported for draw ops.
       if (single_op->IsDrawOp()) {
-        single_op->RasterWithAlpha(canvas, alpha);
+        single_op->RasterWithAlpha(canvas, bounds, alpha);
         return;
       }
     }
 
-    canvas->saveLayerAlpha(nullptr, alpha);
+    bool unset = bounds.x() == PaintOp::kUnsetRect.x();
+    canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha);
     SkMatrix unused_matrix;
     DrawRecordOp::Raster(op, canvas, unused_matrix);
     canvas->restore();
@@ -148,12 +160,13 @@
 
 using RasterAlphaFunction = void (*)(const PaintOp* op,
                                      SkCanvas* canvas,
+                                     const SkRect& bounds,
                                      uint8_t alpha);
 #define M(T) \
-  T::kIsDrawOp ? \
-  [](const PaintOp* op, SkCanvas* canvas, uint8_t alpha) { \
+  T::kIsDrawOp ? [](const PaintOp* op, SkCanvas* canvas, const SkRect& bounds, \
+                    uint8_t alpha) { \
     Rasterizer<T, T::kHasPaintFlags>::RasterWithAlpha( \
-        static_cast<const T*>(op), canvas, alpha); \
+        static_cast<const T*>(op), canvas, bounds, alpha); \
   } : static_cast<RasterAlphaFunction>(nullptr),
 static const RasterAlphaFunction g_raster_alpha_functions[kNumOpTypes] = {
     TYPES(M)};
@@ -446,8 +459,10 @@
   g_raster_functions[type](this, canvas, original_ctm);
 }
 
-void PaintOp::RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const {
-  g_raster_alpha_functions[type](this, canvas, alpha);
+void PaintOp::RasterWithAlpha(SkCanvas* canvas,
+                              const SkRect& bounds,
+                              uint8_t alpha) const {
+  g_raster_alpha_functions[type](this, canvas, bounds, alpha);
 }
 
 int ClipPathOp::CountSlowPaths() const {
@@ -723,7 +738,7 @@
           if (third && third->GetType() == PaintOpType::Restore) {
             const SaveLayerAlphaOp* save_op =
                 static_cast<const SaveLayerAlphaOp*>(op);
-            second->RasterWithAlpha(canvas, save_op->alpha);
+            second->RasterWithAlpha(canvas, save_op->bounds, save_op->alpha);
             continue;
           }
         }
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index e8d31142..db9eaad 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -86,7 +86,9 @@
   bool IsDrawOp() const;
 
   // Only valid for draw ops.
-  void RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const;
+  void RasterWithAlpha(SkCanvas* canvas,
+                       const SkRect& bounds,
+                       uint8_t alpha) const;
 
   int CountSlowPaths() const { return 0; }
   int CountSlowPathsFromFlags() const { return 0; }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index c8e1732..e29cf68 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -545,6 +545,7 @@
       "javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/MockVrCoreVersionCheckerImpl.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/MockVrDaydreamApi.java",
+      "javatests/src/org/chromium/chrome/browser/vr_shell/NfcSimUtils.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/VrFeedbackInfoBarTest.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTest.java",
       "javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java",
@@ -579,6 +580,17 @@
       "//third_party/WebKit/LayoutTests/resources/testharness.js",
     ]
   }
+
+  android_library("vr_nfc_simulator_java") {
+    testonly = true
+
+    java_files = [
+      "javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java",
+      "javatests/src/org/chromium/chrome/browser/vr_shell/NfcSimUtils.java",
+    ]
+
+    deps = []
+  }
 }
 
 # Overrides icon / name defined in chrome_java_resources.
@@ -876,6 +888,8 @@
     "$root_gen_dir/chrome_public_test_vr_apk_manifest/AndroidManifest.xml"
 chrome_sync_shell_test_apk_manifest =
     "$root_gen_dir/chrome_sync_shell_test_apk_manifest/AndroidManifest.xml"
+vr_nfc_simulator_apk_manifest =
+    "$root_gen_dir/vr_nfc_simulator_apk_manifest/AndroidManifest.xml"
 
 jinja_template("chrome_public_test_apk_manifest") {
   input = "javatests/AndroidManifest.xml"
@@ -889,6 +903,12 @@
   variables = chrome_public_jinja_variables
 }
 
+jinja_template("vr_nfc_simulator_apk_manifest") {
+  input = "javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/AndroidManifest.xml"
+  output = vr_nfc_simulator_apk_manifest
+  variables = chrome_public_jinja_variables
+}
+
 jinja_template("chrome_sync_shell_test_apk_manifest") {
   input = "sync_shell/javatests/AndroidManifest.xml"
   output = chrome_sync_shell_test_apk_manifest
@@ -935,6 +955,18 @@
     ]
     proguard_enabled = !is_java_debug
   }
+
+  android_apk("vr_nfc_simulator_apk") {
+    testonly = true
+    apk_name = "VrNfcSimulator"
+    android_manifest = vr_nfc_simulator_apk_manifest
+    android_manifest_dep = ":vr_nfc_simulator_apk_manifest"
+
+    deps = [
+      ":vr_nfc_simulator_java",
+    ]
+    proguard_enabled = false
+  }
 }
 
 android_library("chrome_sync_shell_test_apk_java") {
diff --git a/chrome/android/java/res/drawable/elo_card.xml b/chrome/android/java/res/drawable/elo_card.xml
new file mode 100644
index 0000000..ac45f4e
--- /dev/null
+++ b/chrome/android/java/res/drawable/elo_card.xml
@@ -0,0 +1,59 @@
+<?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. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+   xmlns:tools="http://schemas.android.com/tools"
+   tools:targetApi="21"
+   android:width="32dp"
+   android:height="20dp"
+   android:viewportWidth="128"
+   android:viewportHeight="80">
+
+    <path
+        android:pathData="M0,8C0,3.58 3.59,0 8.01,0L119.99,0C124.42,0 128,3.58 128,8L128,72C128,76.42 124.41,80 119.99,80L8.01,80C3.58,80 0,76.42 0,72L0,8Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#E0E0E0"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M4,8L4,72C4,74.21 5.79,76 8.01,76L119.99,76C122.2,76 124,74.21 124,72L124,8C124,5.79 122.21,4 119.99,4L8.01,4C5.8,4 4,5.79 4,8Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#FFFFFF"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M36,40C36,24.53 48.53,12 64,12C79.47,12 92,24.53 92,40C92,55.47 79.47,68 64,68C48.53,68 36,55.47 36,40"
+        android:strokeColor="#00000000"
+        android:fillColor="#000000"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M55.48,43.4C54.61,44.25 53.44,44.77 52.13,44.75C51.24,44.73 50.41,44.47 49.71,44.02L47.97,46.8C49.16,47.55 50.57,48 52.09,48.02C54.3,48.06 56.31,47.19 57.77,45.75L55.48,43.4Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#FFFFFF"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M47.54,40.55C47.52,40.36 47.51,40.17 47.52,39.98C47.56,37.39 49.69,35.32 52.28,35.36C53.69,35.38 54.94,36.03 55.79,37.03L47.54,40.55ZM52.33,32.08C47.93,32.02 44.31,35.53 44.24,39.93C44.22,41.58 44.69,43.12 45.53,44.4L59.96,38.23C59.15,34.76 56.06,32.14 52.33,32.08L52.33,32.08Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#FFFFFF"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M64.49,28.49L64.49,43.88L67.16,44.99L65.9,48.02L63.26,46.92C62.66,46.67 62.26,46.28 61.96,45.83C61.66,45.38 61.45,44.76 61.45,43.92L61.45,28.49L64.49,28.49Z"
+        android:strokeColor="#00000000"
+        android:fillColor="#FFFFFF"
+        android:strokeWidth="1"/>
+    <path 
+        android:pathData="M72.51,43.59L72.51,43.59C71.61,42.73 70.9,41.39 70.9,40.05C70.9,38.65 71.53,37.4 72.51,36.55C72.5,36.55 70.32,34.09 70.32,34.09C68.67,35.55 67.62,37.68 67.62,40.05C67.62,42.46 68.7,44.62 70.38,46.08L72.51,43.59"
+        android:strokeColor="#00000000"
+        android:fillColor="#00A6E0"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M74.03,35.64C74.54,35.45 75.02,35.36 75.59,35.36C77.86,35.36 79.74,36.97 80.19,39.1L83.4,38.43C82.65,34.81 79.44,32.08 75.59,32.08C74.66,32.08 73.77,32.25 72.94,32.54L74.03,35.64C74.03,35.64 74.05,35.63 74.03,35.64"
+        android:strokeColor="#00000000"
+        android:fillColor="#FFF000"
+        android:strokeWidth="1"/>
+    <path
+        android:pathData="M75.59,44.74C74.96,44.74 74.06,44.48 74.06,44.48L73.02,47.59C73.83,47.87 74.69,48.02 75.59,48.02C79.48,48.02 82.72,45.24 83.42,41.55L80.19,40.94C79.78,43.11 77.88,44.74 75.59,44.74"
+        android:strokeColor="#00000000"
+        android:fillColor="#FF0217"
+        android:strokeWidth="1"/>
+</vector>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
index c27abfc..b452d8a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundService.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser;
 
 import android.content.Context;
-import android.os.Bundle;
 
 import com.google.android.gms.gcm.GcmNetworkManager;
 import com.google.android.gms.gcm.GcmTaskService;
@@ -15,48 +14,29 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.chrome.browser.download.DownloadResumptionScheduler;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsLauncher;
-import org.chromium.chrome.browser.offlinepages.BackgroundOfflinerTask;
 import org.chromium.chrome.browser.offlinepages.BackgroundScheduler;
-import org.chromium.chrome.browser.offlinepages.BackgroundSchedulerProcessorImpl;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.precache.PrecacheController;
 import org.chromium.chrome.browser.precache.PrecacheUMA;
-import org.chromium.content.browser.BrowserStartupController;
 
 /**
  * {@link ChromeBackgroundService} is scheduled through the {@link GcmNetworkManager} when the
  * browser needs to be launched for scheduled tasks, or in response to changing network or power
  * conditions.
- *
- * If HOLD_WAKELOCK is set to true in a bundle in the task params, then the ChromeBackgroundService
- * will wait until the task reports done before returning control to the {@link GcmNetworkManager}.
- * This both guarantees that the wakelock keeps chrome awake and that the GcmNetworkManager does not
- * start another task in place of the one just started.  The GcmNetworkManager can start more than
- * one task concurrently, thought, so it does not guarantee that a different task won't start.
  */
 public class ChromeBackgroundService extends GcmTaskService {
     private static final String TAG = "BackgroundService";
-    /** Bundle key to use to specify we should block the GcmNetworkManager thread until the task on
-     * the UI thread is done before returning to the GcmNetworkManager.
-     */
-    public static final String HOLD_WAKELOCK = "HoldWakelock";
-    // GCM will return our wakelock after 3 minutes, we should be a second less than that.
-    private static final int WAKELOCK_TIMEOUT_SECONDS = 3 * 60 - 1;
-
-    private BackgroundOfflinerTask mBackgroundOfflinerTask;
 
     @Override
     @VisibleForTesting
     public int onRunTask(final TaskParams params) {
         final String taskTag = params.getTag();
         Log.i(TAG, "[" + taskTag + "] Woken up at " + new java.util.Date().toString());
-        final ChromeBackgroundServiceWaiter waiter = getWaiterIfNeeded(params.getExtras());
         final Context context = this;
         ThreadUtils.runOnUiThread(new Runnable() {
             @Override
@@ -67,8 +47,10 @@
                         break;
 
                     case OfflinePageUtils.TASK_TAG:
-                        handleOfflinePageBackgroundLoad(
-                                context, params.getExtras(), waiter, taskTag);
+                        // Offline pages are migrating to BackgroundTaskScheduler, therefore getting
+                        // a task through ChromeBackgroundSerivce should cause a rescheduling using
+                        // the new component.
+                        rescheduleOfflinePages();
                         break;
 
                     case SnippetsLauncher.TASK_TAG_WIFI:
@@ -92,8 +74,6 @@
                 }
             }
         });
-        // If needed, block the GcmNetworkManager thread until the UI thread has finished its work.
-        waitForTaskIfNeeded(waiter);
 
         return GcmNetworkManager.RESULT_SUCCESS;
     }
@@ -144,46 +124,6 @@
         PrecacheController.get(context).precache(tag);
     }
 
-    private void handleOfflinePageBackgroundLoad(
-            Context context, Bundle bundle, ChromeBackgroundServiceWaiter waiter, String tag) {
-        if (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                        .isStartupSuccessfullyCompleted()) {
-            launchBrowser(context, tag);
-        }
-
-        // Call BackgroundTask, provide context.
-        if (mBackgroundOfflinerTask == null) {
-            mBackgroundOfflinerTask =
-                    new BackgroundOfflinerTask(new BackgroundSchedulerProcessorImpl());
-        }
-        mBackgroundOfflinerTask.startBackgroundRequests(context, bundle, waiter);
-    }
-
-    /**
-     * If the bundle contains the special HOLD_WAKELOCK key set to true, then we create a
-     * CountDownLatch for use later in the wait step, and set its initial count to one.
-     */
-    @VisibleForTesting
-    public ChromeBackgroundServiceWaiter getWaiterIfNeeded(Bundle bundle) {
-        // If wait_needed is set to true, wait.
-        if (bundle != null && bundle.getBoolean(HOLD_WAKELOCK, false)) {
-            return new ChromeBackgroundServiceWaiter(WAKELOCK_TIMEOUT_SECONDS);
-        }
-        return null;
-    }
-
-    /**
-     * Some tasks need to block the GcmNetworkManager thread (and thus hold the wake lock) until the
-     * task is done.  If we have a waiter, then start waiting.
-     */
-    @VisibleForTesting
-    public void waitForTaskIfNeeded(ChromeBackgroundServiceWaiter waiter) {
-        if (waiter != null) {
-            // Block current thread until the onWaitDone method is called, or a timeout occurs.
-            waiter.startWaiting();
-        }
-    }
-
     @VisibleForTesting
     @SuppressFBWarnings("DM_EXIT")
     protected void launchBrowser(Context context, String tag) {
@@ -227,8 +167,9 @@
         }
     }
 
-    protected void rescheduleOfflinePagesTasksOnUpgrade() {
-        BackgroundScheduler.getInstance(this).rescheduleOfflinePagesTasksOnUpgrade();
+    /** Reschedules offline pages (using appropriate version of Background Task Scheduler). */
+    protected void rescheduleOfflinePages() {
+        BackgroundScheduler.getInstance().reschedule();
     }
 
     @Override
@@ -236,6 +177,5 @@
         rescheduleBackgroundSyncTasksOnUpgrade();
         reschedulePrecacheTasksOnUpgrade();
         rescheduleSnippetsTasksOnUpgrade();
-        rescheduleOfflinePagesTasksOnUpgrade();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiter.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiter.java
deleted file mode 100644
index 5e1544f..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiter.java
+++ /dev/null
@@ -1,50 +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.
-
-package org.chromium.chrome.browser;
-
-import org.chromium.base.Log;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Class to wait for a task to complete before releasing control back to the caller.
- */
-public class ChromeBackgroundServiceWaiter {
-    private static final String TAG = "CBSWaiter";
-    /** Synchronization object to control the wait. */
-    private final CountDownLatch mLatch;
-    /** How long to wait for before giving up */
-    private int mWakelockTimeoutSeconds;
-
-    public ChromeBackgroundServiceWaiter(int wakelockTimeoutSeconds) {
-        mWakelockTimeoutSeconds = wakelockTimeoutSeconds;
-        mLatch = new CountDownLatch(1);
-    }
-
-    /**
-     * Wait, blocking the current thread until another thread calls onWaitDone.
-     */
-    public void startWaiting() {
-        try {
-            boolean waitSucceeded = mLatch.await(mWakelockTimeoutSeconds, TimeUnit.SECONDS);
-            if (!waitSucceeded) {
-                Log.d(TAG, "waiting for latch timed out");
-            }
-        } catch (InterruptedException e) {
-            Log.d(TAG, "ChromeBackgroundServiceWaiter interrupted while holding wake lock. " + e);
-        }
-    }
-
-
-    /**
-     * Called when the wait is complete.
-     */
-    public void onWaitDone() {
-        // Release the waited thread to return to the caller, and thus release the wake lock held on
-        // behalf of the Owner.
-        mLatch.countDown();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java b/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java
index 9f67fa97..e248417 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser;
 
+import android.support.annotation.Nullable;
+
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.LoadUrlParams;
 
@@ -37,9 +39,11 @@
 
     /**
      * Get the currently active tab. This may be the tab that is displaying the native page or the
-     * tab behind the bottom sheet (if enabled).
+     * tab behind the bottom sheet (if enabled). If the bottom sheet is open and displaying the
+     * NTP UI, then the active tab will be null.
      * @return The active tab.
      */
+    @Nullable
     Tab getActiveTab();
 
     /** @return whether the hosted native page is currently visible. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundGcmScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundGcmScheduler.java
deleted file mode 100644
index c01c3fa..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundGcmScheduler.java
+++ /dev/null
@@ -1,68 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
-import com.google.android.gms.gcm.GcmNetworkManager;
-import com.google.android.gms.gcm.OneoffTask;
-import com.google.android.gms.gcm.Task;
-
-import org.chromium.chrome.browser.ChromeBackgroundService;
-
-/**
- * The background scheduler class is for setting GCM Network Manager tasks.
- */
-public class BackgroundGcmScheduler extends BackgroundScheduler {
-    public BackgroundGcmScheduler(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void cancel() {
-        GcmNetworkManager gcmNetworkManager = getGcmNetworkManager();
-        if (gcmNetworkManager == null) return;
-        gcmNetworkManager.cancelTask(OfflinePageUtils.TASK_TAG, ChromeBackgroundService.class);
-    }
-
-    @Override
-    protected void scheduleImpl(TriggerConditions triggerConditions, long delayStartSeconds,
-            long executionDeadlineSeconds, boolean overwrite) {
-        GcmNetworkManager gcmNetworkManager = getGcmNetworkManager();
-        if (gcmNetworkManager == null) return;
-
-        Bundle taskExtras = new Bundle();
-        TaskExtrasPacker.packTimeInBundle(taskExtras);
-        TaskExtrasPacker.packHoldWakelock(taskExtras);
-        TaskExtrasPacker.packTriggerConditionsInBundle(taskExtras, triggerConditions);
-
-        Task task = new OneoffTask.Builder()
-                            .setService(ChromeBackgroundService.class)
-                            .setExecutionWindow(delayStartSeconds, executionDeadlineSeconds)
-                            .setTag(OfflinePageUtils.TASK_TAG)
-                            .setUpdateCurrent(overwrite)
-                            .setRequiredNetwork(triggerConditions.requireUnmeteredNetwork()
-                                            ? Task.NETWORK_STATE_UNMETERED
-                                            : Task.NETWORK_STATE_CONNECTED)
-                            .setRequiresCharging(triggerConditions.requirePowerConnected())
-                            .setPersisted(true)
-                            .setExtras(taskExtras)
-                            .build();
-
-        // Schedule a task using GCM network manager.
-        gcmNetworkManager.schedule(task);
-    }
-
-    private GcmNetworkManager getGcmNetworkManager() {
-        if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(getContext())
-                == ConnectionResult.SUCCESS) {
-            return GcmNetworkManager.getInstance(getContext());
-        }
-        return null;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundJobScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundJobScheduler.java
deleted file mode 100644
index c1e2c0b..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundJobScheduler.java
+++ /dev/null
@@ -1,53 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
-import org.chromium.components.background_task_scheduler.TaskIds;
-import org.chromium.components.background_task_scheduler.TaskInfo;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * The background job scheduler class used for scheduling tasks using JobScheduler.
- */
-public class BackgroundJobScheduler extends BackgroundScheduler {
-    public BackgroundJobScheduler(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void cancel() {
-        BackgroundTaskSchedulerFactory.getScheduler().cancel(
-                getContext(), TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID);
-    }
-
-    @Override
-    protected void scheduleImpl(TriggerConditions triggerConditions, long delayStartSeconds,
-            long executionDeadlineSeconds, boolean overwrite) {
-        Bundle taskExtras = new Bundle();
-        TaskExtrasPacker.packTimeInBundle(taskExtras);
-        TaskExtrasPacker.packTriggerConditionsInBundle(taskExtras, triggerConditions);
-
-        TaskInfo taskInfo =
-                TaskInfo.createOneOffTask(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID,
-                                OfflineBackgroundTask.class,
-                                TimeUnit.SECONDS.toMillis(delayStartSeconds),
-                                TimeUnit.SECONDS.toMillis(executionDeadlineSeconds))
-                        .setRequiredNetworkType(triggerConditions.requireUnmeteredNetwork()
-                                        ? TaskInfo.NETWORK_TYPE_UNMETERED
-                                        : TaskInfo.NETWORK_TYPE_ANY)
-                        .setUpdateCurrent(overwrite)
-                        .setIsPersisted(true)
-                        .setExtras(taskExtras)
-                        .setRequiresCharging(triggerConditions.requirePowerConnected())
-                        .build();
-
-        BackgroundTaskSchedulerFactory.getScheduler().schedule(getContext(), taskInfo);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java
deleted file mode 100644
index 8bd7568..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java
+++ /dev/null
@@ -1,98 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.Callback;
-import org.chromium.base.Log;
-import org.chromium.base.SysUtils;
-import org.chromium.chrome.browser.ChromeBackgroundServiceWaiter;
-import org.chromium.chrome.browser.offlinepages.interfaces.BackgroundSchedulerProcessor;
-
-/**
- * Handles servicing of background offlining requests coming via the GcmNetworkManager.
- */
-public class BackgroundOfflinerTask {
-    private static final String TAG = "BGOfflinerTask";
-    private static final long DEFER_START_SECONDS = 5 * 60;
-
-    private final BackgroundSchedulerProcessor mBridge;
-
-    public BackgroundOfflinerTask(BackgroundSchedulerProcessor bridge) {
-        mBridge = bridge;
-    }
-
-    /**
-     * Triggers processing of background offlining requests.  This is called when
-     * system conditions are appropriate for background offlining, typically from the
-     * GcmTaskService onRunTask() method.  In response, we will start the
-     * task processing by passing the call along to the C++ RequestCoordinator.
-     * Also starts UMA collection.
-     *
-     * @returns true for success
-     */
-    public void startBackgroundRequests(
-            Context context, Bundle bundle, final ChromeBackgroundServiceWaiter waiter) {
-        // Set up backup scheduled task in case processing is killed before RequestCoordinator
-        // has a chance to reschedule base on remaining work.
-        BackgroundScheduler.getInstance(context).scheduleBackup(
-                TaskExtrasPacker.unpackTriggerConditionsFromBundle(bundle), DEFER_START_SECONDS);
-        // Complete the wait if background request processing was not started.
-        // If background processing was started, completion is going to be handled by callback.
-        if (!startBackgroundRequestsImpl(mBridge, context, bundle, createCallback(waiter))) {
-            waiter.onWaitDone();
-        }
-    }
-
-    /**
-     * Triggers processing of background offlining requests.  This is called when
-     * system conditions are appropriate for background offlining, typically from the
-     * GcmTaskService onRunTask() method.  In response, we will start the
-     * task processing by passing the call along to the C++ RequestCoordinator.
-     * Also starts UMA collection.
-     *
-     * @returns Whether processing will be carried out and completion will be indicated through a
-     *     callback.
-     */
-    static boolean startBackgroundRequestsImpl(BackgroundSchedulerProcessor bridge, Context context,
-            Bundle taskExtras, Callback<Boolean> callback) {
-        TriggerConditions triggerConditions =
-                TaskExtrasPacker.unpackTriggerConditionsFromBundle(taskExtras);
-        DeviceConditions currentConditions = DeviceConditions.getCurrentConditions(context);
-        if (!currentConditions.isPowerConnected()
-                && currentConditions.getBatteryPercentage()
-                        < triggerConditions.getMinimumBatteryPercentage()) {
-            Log.d(TAG, "Battery percentage is lower than minimum to start processing");
-            return false;
-        }
-
-        if (SysUtils.isLowEndDevice() && ApplicationStatus.hasVisibleActivities()) {
-            Log.d(TAG, "Application visible on low-end device so deferring background processing");
-            return false;
-        }
-
-        // Gather UMA data to measure how often the user's machine is amenable to background
-        // loading when we wake to do a task.
-        long taskScheduledTimeMillis = TaskExtrasPacker.unpackTimeFromBundle(taskExtras);
-        OfflinePageUtils.recordWakeupUMA(context, taskScheduledTimeMillis);
-
-        return bridge.startScheduledProcessing(currentConditions, callback);
-    }
-
-    private Callback<Boolean> createCallback(final ChromeBackgroundServiceWaiter waiter) {
-        return new Callback<Boolean>() {
-            /** Callback releasing the wakelock once background work concludes. */
-            @Override
-            public void onResult(Boolean result) {
-                Log.d(TAG, "onResult");
-                // Release the wake lock.
-                waiter.onWaitDone();
-            }
-        };
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java
index 38f5eeb..27b23c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java
@@ -4,48 +4,42 @@
 
 package org.chromium.chrome.browser.offlinepages;
 
-import android.content.Context;
-import android.os.Build;
+import android.os.Bundle;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.components.background_task_scheduler.TaskInfo;
 
 import java.util.concurrent.TimeUnit;
 
 /**
- * The background scheduler class is for setting GCM Network Manager tasks.
+ * Class responsible for scheduling and canceling offline page related background tasks.
  */
-public abstract class BackgroundScheduler {
-    private static final long ONE_WEEK_IN_SECONDS = TimeUnit.DAYS.toSeconds(7);
-    private static final long FIVE_MINUTES_IN_SECONDS = TimeUnit.MINUTES.toSeconds(5);
-    private static final long NO_DELAY = 0;
+public class BackgroundScheduler {
+    static final long ONE_WEEK_IN_MILLISECONDS = TimeUnit.DAYS.toMillis(7);
+    static final long FIVE_MINUTES_IN_MILLISECONDS = TimeUnit.MINUTES.toSeconds(5);
+    static final long NO_DELAY = 0;
     private static final boolean OVERWRITE = true;
 
-    /**
-     * Context used by the scheduler to access services. Extracted to a field, to clean up method
-     * signatures.
-     */
-    private Context mContext;
-
-    /**
-     * Provides an instance of BackgroundScheduler for given context and current API level.
-     * <p>
-     * Warning: Don't cache the returned value, as it is bound to {@code context}. Consumers should
-     * simply get an instance every time.
-     * @return An instance of BackgroundScheduler.
-     */
-    public static BackgroundScheduler getInstance(Context context) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            return new BackgroundJobScheduler(context);
-        } else {
-            return new BackgroundGcmScheduler(context);
-        }
+    private static class LazyHolder {
+        static final BackgroundScheduler INSTANCE = new BackgroundScheduler();
     }
 
-    protected BackgroundScheduler(Context context) {
-        mContext = context;
+    /** Provides an instance of BackgroundScheduler for given context and current API level. */
+    public static BackgroundScheduler getInstance() {
+        return LazyHolder.INSTANCE;
     }
 
-    /** Schedules a GCM Network Manager task for provided triggering conditions. */
+    /** Cancels a background tasks. */
+    public void cancel() {
+        BackgroundTaskSchedulerFactory.getScheduler().cancel(
+                ContextUtils.getApplicationContext(), TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID);
+    }
+
+    /** Schedules a background task for provided triggering conditions. */
     public void schedule(TriggerConditions triggerConditions) {
-        scheduleImpl(triggerConditions, NO_DELAY, ONE_WEEK_IN_SECONDS, OVERWRITE);
+        scheduleImpl(triggerConditions, NO_DELAY, ONE_WEEK_IN_MILLISECONDS, OVERWRITE);
     }
 
     /**
@@ -55,34 +49,41 @@
      * and/or queue updates. This is a backup task in case processing is killed by the
      * system.
      */
-    public void scheduleBackup(TriggerConditions triggerConditions, long delayStartSeconds) {
-        scheduleImpl(triggerConditions, delayStartSeconds, ONE_WEEK_IN_SECONDS, !OVERWRITE);
-    }
-
-    /** Cancel any outstanding GCM Network Manager requests. */
-    public abstract void cancel();
-
-    /**
-     * For the given Triggering conditions, start a new GCM Network Manager request allowed
-     * to run after {@code delayStartSecs} seconds.
-     */
-    protected abstract void scheduleImpl(TriggerConditions triggerConditions,
-            long delayStartSeconds, long executionDeadlineSeconds, boolean overwrite);
-
-    /** @return Context used to access OS services. */
-    protected Context getContext() {
-        return mContext;
+    public void scheduleBackup(TriggerConditions triggerConditions, long delayStartMs) {
+        scheduleImpl(triggerConditions, delayStartMs, ONE_WEEK_IN_MILLISECONDS, !OVERWRITE);
     }
 
     /**
-     * If GooglePlayServices upgrades, any outstaning tasks will be lost.
-     * Set a reminder to wake up and check the task queue if an upgrade happens.
+     * Method for rescheduling a background task for offline pages in the event of OS upgrade or
+     * GooglePlayServices upgrade.
+     * We use the least restrictive trigger conditions.  A wakeup will cause the queue to be
+     * checked, and the trigger conditions will be replaced by the current trigger conditions
+     * needed.
      */
-    public void rescheduleOfflinePagesTasksOnUpgrade() {
-        // We use the least restrictive trigger conditions.  A wakeup will cause
-        // the queue to be checked, and the trigger conditions will be replaced by
-        // the current trigger conditions needed.
+    public void reschedule() {
         TriggerConditions triggerConditions = new TriggerConditions(false, 0, false);
-        scheduleBackup(triggerConditions, FIVE_MINUTES_IN_SECONDS);
+        scheduleBackup(triggerConditions, FIVE_MINUTES_IN_MILLISECONDS);
+    }
+
+    protected void scheduleImpl(TriggerConditions triggerConditions, long delayStartMs,
+            long executionDeadlineMs, boolean overwrite) {
+        Bundle taskExtras = new Bundle();
+        TaskExtrasPacker.packTimeInBundle(taskExtras);
+        TaskExtrasPacker.packTriggerConditionsInBundle(taskExtras, triggerConditions);
+
+        TaskInfo taskInfo =
+                TaskInfo.createOneOffTask(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID,
+                                OfflineBackgroundTask.class, delayStartMs, executionDeadlineMs)
+                        .setRequiredNetworkType(triggerConditions.requireUnmeteredNetwork()
+                                        ? TaskInfo.NETWORK_TYPE_UNMETERED
+                                        : TaskInfo.NETWORK_TYPE_ANY)
+                        .setUpdateCurrent(overwrite)
+                        .setIsPersisted(true)
+                        .setExtras(taskExtras)
+                        .setRequiresCharging(triggerConditions.requirePowerConnected())
+                        .build();
+
+        BackgroundTaskSchedulerFactory.getScheduler().schedule(
+                ContextUtils.getApplicationContext(), taskInfo);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java
index cf09c6a..d18f73d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java
@@ -9,6 +9,8 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
+import java.util.concurrent.TimeUnit;
+
 /**
  * Provides Java scheduling support from native offlining code as
  * well as JNI interface to tell native code to start processing
@@ -42,19 +44,18 @@
 
     @CalledByNative
     private static void schedule(TriggerConditions triggerConditions) {
-        BackgroundScheduler.getInstance(ContextUtils.getApplicationContext())
-                .schedule(triggerConditions);
+        BackgroundScheduler.getInstance().schedule(triggerConditions);
     }
 
     @CalledByNative
     private static void backupSchedule(TriggerConditions triggerConditions, long delayInSeconds) {
-        BackgroundScheduler.getInstance(ContextUtils.getApplicationContext())
-                .scheduleBackup(triggerConditions, delayInSeconds);
+        BackgroundScheduler.getInstance().scheduleBackup(
+                triggerConditions, TimeUnit.SECONDS.toMillis(delayInSeconds));
     }
 
     @CalledByNative
     private static void unschedule() {
-        BackgroundScheduler.getInstance(ContextUtils.getApplicationContext()).cancel();
+        BackgroundScheduler.getInstance().cancel();
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessor.java
new file mode 100644
index 0000000..aa7c926c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessor.java
@@ -0,0 +1,46 @@
+// 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.
+
+package org.chromium.chrome.browser.offlinepages;
+
+import org.chromium.base.Callback;
+import org.chromium.base.VisibleForTesting;
+
+/** Class allowing for mocking out calls to BackgroundSchedulerBridge.  */
+public class BackgroundSchedulerProcessor {
+    private static BackgroundSchedulerProcessor sInstance;
+
+    /** Returns a singleton instance. */
+    public static BackgroundSchedulerProcessor getInstance() {
+        if (sInstance == null) {
+            sInstance = new BackgroundSchedulerProcessor();
+        }
+        return sInstance;
+    }
+
+    @VisibleForTesting
+    static void setInstanceForTesting(BackgroundSchedulerProcessor instance) {
+        sInstance = instance;
+    }
+
+    /**
+     * Starts processing of one or more queued background requests.  Returns whether processing was
+     * started and that caller should expect a callback (once processing has completed or
+     * terminated).  If processing was already active or not able to process for some other reason,
+     * returns false and this calling instance will not receive a callback.
+     */
+    public boolean startScheduledProcessing(
+            DeviceConditions deviceConditions, Callback<Boolean> callback) {
+        return BackgroundSchedulerBridge.startScheduledProcessing(deviceConditions, callback);
+    }
+
+    /**
+     * Stops processing background requests.
+     * @return Whether processing should be scheduled again at a later time, because there is more
+     * work.
+     */
+    public boolean stopScheduledProcessing() {
+        return BackgroundSchedulerBridge.stopScheduledProcessing();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java
deleted file mode 100644
index 5059f0b..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java
+++ /dev/null
@@ -1,25 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import org.chromium.base.Callback;
-import org.chromium.chrome.browser.offlinepages.interfaces.BackgroundSchedulerProcessor;
-
-/**
- * Implementation of the scheduler bridge class that defers to the static background scheduler
- * bridge.
- */
-public class BackgroundSchedulerProcessorImpl implements BackgroundSchedulerProcessor {
-    @Override
-    public boolean startScheduledProcessing(
-            DeviceConditions deviceConditions, Callback<Boolean> callback) {
-        return BackgroundSchedulerBridge.startScheduledProcessing(deviceConditions, callback);
-    }
-
-    @Override
-    public boolean stopScheduledProcessing() {
-        return BackgroundSchedulerBridge.stopScheduledProcessing();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java
index 1b617b4..b0956a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java
@@ -113,8 +113,12 @@
     }
 
     private static int getConnectionType(Context context) {
-        // Get the connection type from chromium's internal object.
-        int connectionType = NetworkChangeNotifier.getInstance().getCurrentConnectionType();
+        int connectionType = ConnectionType.CONNECTION_NONE;
+
+        // If we are starting in the background, native portion might not be initialized.
+        if (NetworkChangeNotifier.isInitialized()) {
+            connectionType = NetworkChangeNotifier.getInstance().getCurrentConnectionType();
+        }
 
         // Sometimes the NetworkConnectionNotifier lags the actual connection type, especially when
         // the GCM NM wakes us from doze state.  If we are really connected, report the connection
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java
index 50fb2cd..e3f16a2f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java
@@ -5,51 +5,74 @@
 package org.chromium.chrome.browser.offlinepages;
 
 import android.content.Context;
+import android.os.Bundle;
 
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
-import org.chromium.base.library_loader.LibraryProcessType;
-import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
-import org.chromium.chrome.browser.offlinepages.interfaces.BackgroundSchedulerProcessor;
-import org.chromium.components.background_task_scheduler.BackgroundTask;
+import org.chromium.base.SysUtils;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
 import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback;
 import org.chromium.components.background_task_scheduler.TaskIds;
 import org.chromium.components.background_task_scheduler.TaskParameters;
-import org.chromium.content.browser.BrowserStartupController;
 
 /**
- * Handles servicing background offlining requests coming via background_task_scheduler component.
+ * Handles servicing of background offlining requests coming via background_task_scheduler
+ * component.
  */
-public class OfflineBackgroundTask implements BackgroundTask {
-    private static final String TAG = "OPBackgroundTask";
-
-    BackgroundSchedulerProcessor mBackgroundProcessor;
-
-    public OfflineBackgroundTask() {
-        mBackgroundProcessor = new BackgroundSchedulerProcessorImpl();
-    }
+public class OfflineBackgroundTask extends NativeBackgroundTask {
+    private static final String TAG = "OfflineBkgrndTask";
 
     @Override
-    public boolean onStartTask(
+    @StartBeforeNativeResult
+    protected int onStartTaskBeforeNativeLoaded(
             Context context, TaskParameters taskParameters, TaskFinishedCallback callback) {
         assert taskParameters.getTaskId() == TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID;
 
-        // Ensuring that native potion of the browser is launched.
-        launchBrowserIfNecessary(context);
+        if (!checkConditions(context, taskParameters.getExtras())) {
+            return RESCHEDULE;
+        }
 
-        return BackgroundOfflinerTask.startBackgroundRequestsImpl(
-                mBackgroundProcessor, context, taskParameters.getExtras(), wrapCallback(callback));
+        return LOAD_NATIVE;
     }
 
     @Override
-    public boolean onStopTask(Context context, TaskParameters taskParameters) {
-        return mBackgroundProcessor.stopScheduledProcessing();
+    protected void onStartTaskWithNative(
+            Context context, TaskParameters taskParameters, TaskFinishedCallback callback) {
+        assert taskParameters.getTaskId() == TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID;
+
+        if (!startScheduledProcessing(BackgroundSchedulerProcessor.getInstance(), context,
+                    taskParameters.getExtras(), wrapCallback(callback))) {
+            callback.taskFinished(true);
+            return;
+        }
+
+        // Set up backup scheduled task in case processing is killed before RequestCoordinator
+        // has a chance to reschedule base on remaining work.
+        BackgroundScheduler.getInstance().scheduleBackup(
+                TaskExtrasPacker.unpackTriggerConditionsFromBundle(taskParameters.getExtras()),
+                BackgroundScheduler.FIVE_MINUTES_IN_MILLISECONDS);
+    }
+
+    @Override
+    protected boolean onStopTaskBeforeNativeLoaded(Context context, TaskParameters taskParameters) {
+        assert taskParameters.getTaskId() == TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID;
+
+        // Native didn't complete loading, but it was supposed to. Presume we need to reschedule.
+        return true;
+    }
+
+    @Override
+    protected boolean onStopTaskWithNative(Context context, TaskParameters taskParameters) {
+        assert taskParameters.getTaskId() == TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID;
+
+        return BackgroundSchedulerProcessor.getInstance().stopScheduledProcessing();
     }
 
     @Override
     public void reschedule(Context context) {
-        BackgroundScheduler.getInstance(context).rescheduleOfflinePagesTasksOnUpgrade();
+        BackgroundScheduler.getInstance().reschedule();
     }
 
     /** Wraps the callback for code reuse */
@@ -62,21 +85,56 @@
         };
     }
 
-    private static void launchBrowserIfNecessary(Context context) {
-        if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-                        .isStartupSuccessfullyCompleted()) {
-            return;
+    /**
+     * Starts scheduled processing and reports UMA. This method does not check for current
+     * conditions and should be used together with {@link #checkConditions} to ensure that it
+     * performs the tasks only when it is supposed to.
+     *
+     * @returns Whether processing will be carried out and completion will be indicated through a
+     *     callback.
+     */
+    @VisibleForTesting
+    static boolean startScheduledProcessing(BackgroundSchedulerProcessor bridge, Context context,
+            Bundle taskExtras, Callback<Boolean> callback) {
+        // Gather UMA data to measure how often the user's machine is amenable to background
+        // loading when we wake to do a task.
+        long taskScheduledTimeMillis = TaskExtrasPacker.unpackTimeFromBundle(taskExtras);
+        OfflinePageUtils.recordWakeupUMA(context, taskScheduledTimeMillis);
+
+        DeviceConditions deviceConditions = DeviceConditions.getCurrentConditions(context);
+        return bridge.startScheduledProcessing(deviceConditions, callback);
+    }
+
+    /** @returns Whether conditions for running the tasks are met. */
+    @VisibleForTesting
+    static boolean checkConditions(Context context, Bundle taskExtras) {
+        TriggerConditions triggerConditions =
+                TaskExtrasPacker.unpackTriggerConditionsFromBundle(taskExtras);
+
+        DeviceConditions deviceConditions = DeviceConditions.getCurrentConditions(context);
+        if (!areBatteryConditionsMet(deviceConditions, triggerConditions)) {
+            Log.d(TAG, "Battery percentage is lower than minimum to start processing");
+            return false;
         }
 
-        // TODO(fgorski): This method is taken from ChromeBackgroundService as a local fix and will
-        // be removed with BackgroundTaskScheduler supporting GcmNetworkManager scheduling.
-        try {
-            ChromeBrowserInitializer.getInstance(context).handleSynchronousStartup();
-        } catch (ProcessInitException e) {
-            Log.e(TAG, "ProcessInitException while starting the browser process.");
-            // Since the library failed to initialize nothing in the application can work, so kill
-            // the whole application not just the activity.
-            System.exit(-1);
+        if (!isSvelteConditionsMet()) {
+            Log.d(TAG, "Application visible on low-end device so deferring background processing");
+            return false;
         }
+
+        return true;
+    }
+
+    /** Whether battery conditions (on power and enough battery percentage) are met. */
+    private static boolean areBatteryConditionsMet(
+            DeviceConditions deviceConditions, TriggerConditions triggerConditions) {
+        return deviceConditions.isPowerConnected()
+                || (deviceConditions.getBatteryPercentage()
+                           >= triggerConditions.getMinimumBatteryPercentage());
+    }
+
+    /** Whether there are no visible activities when on Svelte. */
+    private static boolean isSvelteConditionsMet() {
+        return !SysUtils.isLowEndDevice() || !ApplicationStatus.hasVisibleActivities();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java
index be80d9f..da864a8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPacker.java
@@ -6,8 +6,6 @@
 
 import android.os.Bundle;
 
-import org.chromium.chrome.browser.ChromeBackgroundService;
-
 /**
  * Class to put our custom task information into the task bundle.
  */
@@ -20,11 +18,6 @@
     private static final String BATTERY_PERCENTAGE_TAG = "BatteryPercentage";
     private static final String UNMETERED_NETWORK_TAG = "UnmeteredNetwork";
 
-    /** Puts requirement to hold a wakelock in the bundle. */
-    public static void packHoldWakelock(Bundle bundle) {
-        bundle.putBoolean(ChromeBackgroundService.HOLD_WAKELOCK, true);
-    }
-
     /** Puts current time into the input bundle. */
     public static void packTimeInBundle(Bundle bundle) {
         bundle.putLong(SCHEDULED_TIME_TAG, System.currentTimeMillis());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java
deleted file mode 100644
index bf8d5699..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java
+++ /dev/null
@@ -1,29 +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.
-
-package org.chromium.chrome.browser.offlinepages.interfaces;
-
-import org.chromium.base.Callback;
-import org.chromium.chrome.browser.offlinepages.DeviceConditions;
-
-/**
- * Interface to allow mocking out the BackgroundSchedulerProcessor, which must call static
- * methods in BackgroundSchedulerBridge.
- */
-public interface BackgroundSchedulerProcessor {
-    /**
-     * Starts processing of one or more queued background requests.  Returns whether processing was
-     * started and that caller should expect a callback (once processing has completed or
-     * terminated).  If processing was already active or not able to process for some other reason,
-     * returns false and this calling instance will not receive a callback.
-     */
-    boolean startScheduledProcessing(DeviceConditions deviceConditions, Callback<Boolean> callback);
-
-    /**
-     * Stops processing background requests.
-     * @return Whether processing should be scheduled again at a later time, because there is more
-     * work.
-     */
-    boolean stopScheduledProcessing();
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java
index 35718d7..96475ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/JourneyLogger.java
@@ -121,7 +121,6 @@
      */
     public void setAborted(int reason) {
         assert reason < AbortReason.MAX;
-        assert mWasShowCalled;
 
         // The abort reasons on Android cascade into each other, so only the first one should be
         // recorded.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
index 128dd59c..406b4f02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
@@ -1056,10 +1056,11 @@
         /** Indicates whether the summary is displayed in a single line. */
         private boolean mSummaryInSingleLine;
 
-        /** Indicates whether the summary is set to display in a single line in DISPLAY_MODE_NORMAL
+        /**
+         * Indicates whether the summary is set to display in a single line in DISPLAY_MODE_NORMAL
          * by caller.
          */
-        boolean mSetDisplaySummaryInSingleLineInNormalMode = true;
+        private boolean mSetDisplaySummaryInSingleLineInNormalMode = true;
 
         /** Indicates whether the summary is set to R.style.PaymentsUiSectionDescriptiveText. */
         private boolean mSummaryInDescriptiveText;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ShippingSummaryInformation.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ShippingSummaryInformation.java
deleted file mode 100644
index c8a4321..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ShippingSummaryInformation.java
+++ /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.
-
-package org.chromium.chrome.browser.payments.ui;
-
-import javax.annotation.Nullable;
-
-/** The data to show in a shipping summary section. It contains shipping address and option. */
-public class ShippingSummaryInformation {
-    private SectionInformation mShippingAddress;
-    private SectionInformation mShippingOption;
-
-    /** Builds ShppingSummaryInformation with shipping address and option section information. */
-    public ShippingSummaryInformation(
-            SectionInformation shippingAddress, SectionInformation shippingOption) {
-        mShippingAddress = shippingAddress;
-        mShippingOption = shippingOption;
-    }
-
-    /**
-     * Returns the label for the selected shipping address.
-     *
-     * @return The label for the selected shipping address or null.
-     */
-    @Nullable
-    public String getSelectedShippingAddressLabel() {
-        PaymentOption address = mShippingAddress.getSelectedItem();
-        return address != null ? address.getLabel() : null;
-    }
-
-    /**
-     * Returns the sublabel for the selected shipping address.
-     *
-     * @return The sublabel for the selected shipping address or null.
-     */
-    @Nullable
-    public String getSelectedShippingAddressSublabel() {
-        PaymentOption address = mShippingAddress.getSelectedItem();
-        return address != null ? address.getSublabel() : null;
-    }
-
-    /**
-     * Returns the tertiary label for the selected shipping address.
-     *
-     * @return The tertiary label for the selected shipping address or null.
-     */
-    @Nullable
-    public String getSelectedShippingAddressTertiaryLabel() {
-        PaymentOption address = mShippingAddress.getSelectedItem();
-        return address != null ? address.getTertiaryLabel() : null;
-    }
-
-    /**
-     * Returns the label for the selected shipping option.
-     *
-     * @return The label for the selected shipping option or null.
-     */
-    @Nullable
-    public String getSelectedShippingOptionLabel() {
-        PaymentOption option = mShippingOption.getSelectedItem();
-        return option != null ? option.getLabel() : null;
-    }
-
-    /**
-     * Returns the shipping address section information.
-     *
-     * @return The shipping address section information.
-     */
-    public SectionInformation getShippingAddressSectionInfo() {
-        return mShippingAddress;
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java
index 60660c6..d2e94359 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java
@@ -9,6 +9,7 @@
 import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
+import android.support.v7.content.res.AppCompatResources;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
@@ -45,7 +46,8 @@
             Preference pref = new Preference(getActivity());
             pref.setTitle(card.getObfuscatedNumber());
             pref.setSummary(card.getFormattedExpirationDate(getActivity()));
-            pref.setIcon(card.getIssuerIconDrawableId());
+            pref.setIcon(
+                    AppCompatResources.getDrawable(getActivity(), card.getIssuerIconDrawableId()));
 
             if (card.getIsLocal()) {
                 pref.setFragment(AutofillLocalCardEditor.class.getName());
@@ -89,4 +91,4 @@
         PersonalDataManager.getInstance().unregisterDataObserver(this);
         super.onDestroyView();
     }
-}
\ No newline at end of file
+}
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 2b3aa24..c53044a 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
@@ -184,8 +184,13 @@
     }
 
     private void saveUrlForOffline(String url) {
-        OfflinePageBridge.getForProfile(mProfile).scheduleDownload(
-                mHost.getActiveTab().getWebContents(), "ntp_suggestions", url,
-                DownloadUiActionFlags.ALL);
+        if (mHost.getActiveTab() != null) {
+            OfflinePageBridge.getForProfile(mProfile).scheduleDownload(
+                    mHost.getActiveTab().getWebContents(), "ntp_suggestions", url,
+                    DownloadUiActionFlags.ALL);
+        } else {
+            OfflinePageBridge.getForProfile(mProfile).savePageLater(
+                    url, "ntp_suggestions", true /* userRequested */);
+        }
     }
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 931bb9f..b64a883c 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -20,7 +20,6 @@
   "java/src/org/chromium/chrome/browser/ChromeActivitySessionTracker.java",
   "java/src/org/chromium/chrome/browser/ChromeApplication.java",
   "java/src/org/chromium/chrome/browser/ChromeBackgroundService.java",
-  "java/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiter.java",
   "java/src/org/chromium/chrome/browser/ChromeBackupAgent.java",
   "java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java",
   "java/src/org/chromium/chrome/browser/ChromeFeatureList.java",
@@ -674,12 +673,9 @@
   "java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java",
   "java/src/org/chromium/chrome/browser/offlinepages/CCTRequestStatus.java",
   "java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/BackgroundGcmScheduler.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/BackgroundJobScheduler.java",
   "java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java",
   "java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java",
+  "java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessor.java",
   "java/src/org/chromium/chrome/browser/offlinepages/ClientId.java",
   "java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java",
   "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java",
@@ -692,7 +688,6 @@
   "java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java",
   "java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadItem.java",
   "java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageNotificationBridge.java",
-  "java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java",
   "java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java",
   "java/src/org/chromium/chrome/browser/omaha/ExponentialBackoffScheduler.java",
   "java/src/org/chromium/chrome/browser/omaha/MarketURLGetter.java",
@@ -799,7 +794,6 @@
   "java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUiErrorView.java",
   "java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java",
   "java/src/org/chromium/chrome/browser/payments/ui/SectionUiUtils.java",
-  "java/src/org/chromium/chrome/browser/payments/ui/ShippingSummaryInformation.java",
   "java/src/org/chromium/chrome/browser/payments/ui/ShoppingCart.java",
   "java/src/org/chromium/chrome/browser/permissions/AndroidPermissionRequester.java",
   "java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java",
@@ -1691,7 +1685,6 @@
 chrome_junit_test_java_sources = [
   "junit/src/org/chromium/chrome/browser/AppIndexingUtilTest.java",
   "junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java",
-  "junit/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiterTest.java",
   "junit/src/org/chromium/chrome/browser/DelayedScreenLockIntentHandlerTest.java",
   "junit/src/org/chromium/chrome/browser/DisableHistogramsRule.java",
   "junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java",
@@ -1753,14 +1746,12 @@
   "junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java",
   "junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java",
-  "junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java",
+  "junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/ShadowDeviceConditions.java",
-  "junit/src/org/chromium/chrome/browser/offlinepages/ShadowGcmNetworkManager.java",
-  "junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPackerTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridgeTest.java",
   "junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java
index 1e4c25f..542575f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackgroundServiceTest.java
@@ -75,7 +75,7 @@
         protected void reschedulePrecacheTasksOnUpgrade() {}
 
         @Override
-        protected void rescheduleOfflinePagesTasksOnUpgrade() {}
+        protected void rescheduleOfflinePages() {}
 
         // Posts an assertion task to the UI thread. Since this is only called after the call
         // to onRunTask, it will be enqueued after any possible call to launchBrowser, and we
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/NfcSimUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/NfcSimUtils.java
new file mode 100644
index 0000000..4d9a2e7
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/NfcSimUtils.java
@@ -0,0 +1,60 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.vr_shell;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Utility class to simulate a Daydream View NFC tag being scanned. In its own
+ * class so that both instrumentation tests and the standalone APK for use with
+ * Telemetry can share code without the APK including instrumentation-test-only
+ * code.
+ */
+public class NfcSimUtils {
+    private static final String DETECTION_ACTIVITY = ".nfc.ViewerDetectionActivity";
+    // TODO(bsheedy): Use constants from VrCore if ever exposed
+    private static final String APPLICATION_RECORD_STRING = "com.google.vr.vrcore";
+    private static final String RESERVED_KEY = "google.vr/rsvd";
+    private static final String VERSION_KEY = "google.vr/ver";
+    private static final String DATA_KEY = "google.vr/data";
+    private static final ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;
+    // Hard coded viewer ID (0x03) instead of using NfcParams and converting
+    // to a byte array because NfcParams were removed from the GVR SDK
+    private static final byte[] PROTO_BYTES = new byte[] {(byte) 0x08, (byte) 0x03};
+    private static final int VERSION = 123;
+    private static final int RESERVED = 456;
+
+    /**
+     * Makes an Intent that triggers VrCore as if the Daydream headset's NFC
+     * tag was scanned.
+     * @return The intent to send to VrCore to simulate an NFC scan.
+     */
+    public static Intent makeNfcIntent() {
+        Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED);
+        NdefMessage[] messages = new NdefMessage[] {new NdefMessage(
+                new NdefRecord[] {NdefRecord.createMime(RESERVED_KEY, intToByteArray(RESERVED)),
+                        NdefRecord.createMime(VERSION_KEY, intToByteArray(VERSION)),
+                        NdefRecord.createMime(DATA_KEY, PROTO_BYTES),
+                        NdefRecord.createApplicationRecord(APPLICATION_RECORD_STRING)})};
+        nfcIntent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, messages);
+        nfcIntent.setComponent(new ComponentName(
+                APPLICATION_RECORD_STRING, APPLICATION_RECORD_STRING + DETECTION_ACTIVITY));
+        return nfcIntent;
+    }
+
+    private static byte[] intToByteArray(int i) {
+        final ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
+        bb.order(BYTE_ORDER);
+        bb.putInt(i);
+        return bb.array();
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrUtils.java
index 0a2acef..3a2fbaac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrUtils.java
@@ -5,12 +5,8 @@
 package org.chromium.chrome.browser.vr_shell;
 
 import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.nfc.NdefMessage;
-import android.nfc.NdefRecord;
-import android.nfc.NfcAdapter;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -19,8 +15,6 @@
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -34,20 +28,6 @@
     public static final int POLL_TIMEOUT_SHORT_MS = 1000;
     public static final int POLL_TIMEOUT_LONG_MS = 10000;
 
-    private static final String DETECTION_ACTIVITY =
-            ".nfc.ViewerDetectionActivity";
-    // TODO(bsheedy): Use constants from VrCore if ever exposed
-    private static final String APPLICATION_RECORD_STRING = "com.google.vr.vrcore";
-    private static final String RESERVED_KEY = "google.vr/rsvd";
-    private static final String VERSION_KEY =  "google.vr/ver";
-    private static final String DATA_KEY =     "google.vr/data";
-    private static final ByteOrder BYTE_ORDER = ByteOrder.BIG_ENDIAN;
-    // Hard coded viewer ID (0x03) instead of using NfcParams and converting
-    // to a byte array because NfcParams were removed from the GVR SDK
-    private static final byte[] PROTO_BYTES = new byte[] {(byte) 0x08, (byte) 0x03};
-    private static final int VERSION = 123;
-    private static final int RESERVED = 456;
-
     /**
      * Gets the VrShellDelegate instance on the UI thread, as otherwise the
      * Choreographer obtained in VrShellDelegate's constructor is for the instrumentation
@@ -91,37 +71,12 @@
         });
     }
 
-    private static byte[] intToByteArray(int i) {
-        final ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
-        bb.order(BYTE_ORDER);
-        bb.putInt(i);
-        return bb.array();
-    }
-
-    /**
-     * Makes an Intent that triggers VrCore as if the Daydream headset's NFC
-     * tag was scanned.
-     * @return The intent to send to VrCore to simulate an NFC scan.
-     */
-    public static Intent makeNfcIntent() {
-        Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED);
-        NdefMessage[] messages = new NdefMessage[] {new NdefMessage(
-                new NdefRecord[] {NdefRecord.createMime(RESERVED_KEY, intToByteArray(RESERVED)),
-                        NdefRecord.createMime(VERSION_KEY, intToByteArray(VERSION)),
-                        NdefRecord.createMime(DATA_KEY, PROTO_BYTES),
-                        NdefRecord.createApplicationRecord(APPLICATION_RECORD_STRING)})};
-        nfcIntent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, messages);
-        nfcIntent.setComponent(new ComponentName(APPLICATION_RECORD_STRING,
-                  APPLICATION_RECORD_STRING + ".nfc.ViewerDetectionActivity"));
-        return nfcIntent;
-    }
-
     /**
      * Simulates the NFC tag of the Daydream headset being scanned.
      * @param context The Context that the activity will be started from.
      */
     public static void simNfcScan(Context context) {
-        Intent nfcIntent = makeNfcIntent();
+        Intent nfcIntent = NfcSimUtils.makeNfcIntent();
         try {
             context.startActivity(nfcIntent);
         } catch (ActivityNotFoundException e) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/AndroidManifest.xml b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/AndroidManifest.xml
new file mode 100644
index 0000000..cf149339
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+  <!-- Copyright (c) 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. -->
+  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.chromium.chrome.browser.vr_shell.nfc_apk">
+    <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />
+    <application>
+      <activity android:name="org.chromium.chrome.browser.vr_shell.nfc_apk.SimNfcActivity"
+        android:exported="true"
+        android:theme="@android:style/Theme.NoDisplay"
+        android:excludeFromRecents="true"/>
+    </application>
+  </manifest>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java
new file mode 100644
index 0000000..d788cd3
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.vr_shell.nfc_apk;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import org.chromium.chrome.browser.vr_shell.NfcSimUtils;
+
+/**
+ * Activity to simulate an NFC scan of a Daydream View VR headset. This is so
+ * tests that cannot interact directly with Java, e.g. Telemetry tests, can
+ * still force Chrome to enter VR.
+ */
+public class SimNfcActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Send off intent and close this application
+        startActivity(NfcSimUtils.makeNfcIntent());
+        finish();
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiterTest.java
deleted file mode 100644
index 55088e1e..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackgroundServiceWaiterTest.java
+++ /dev/null
@@ -1,75 +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.
-
-package org.chromium.chrome.browser;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Unit tests for the ChromeBackgroundServiceWaiter.
- */
-@RunWith(JUnit4.class)
-public class ChromeBackgroundServiceWaiterTest {
-    private static final int TIMEOUT_SECONDS = 30;
-
-    private AtomicBoolean mFinishedWaiting = new AtomicBoolean();
-    private AtomicBoolean mWaitFailed = new AtomicBoolean();
-
-    private boolean getFinishedWaiting() {
-        return mFinishedWaiting.get();
-    }
-
-    private void setFinishedWaiting(boolean newValue) {
-        mFinishedWaiting.getAndSet(newValue);
-    }
-
-    private boolean getWaitFailed() {
-        return mWaitFailed.get();
-    }
-
-    @Test
-    public void testWaiter() {
-        final ChromeBackgroundServiceWaiter waiter =
-                new ChromeBackgroundServiceWaiter(TIMEOUT_SECONDS);
-
-        Future<?> future = Executors.newSingleThreadExecutor().submit(new Runnable() {
-            @Override
-            public void run() {
-                // The finished waiting flag should not be set, if it is, the wait operation failed.
-                if (getFinishedWaiting()) {
-                    mWaitFailed.getAndSet(true);
-                }
-                waiter.onWaitDone();
-            }
-        });
-
-        // Wait for the thread, and set the flag after we are done waiting.
-        waiter.startWaiting();
-        setFinishedWaiting(true);
-
-        // Wait for the "onWaitDone" thread to complete.
-        try {
-            future.get();
-        } catch (InterruptedException | ExecutionException e) {
-            // Fail the test if we get an interrupted exception.
-            fail("InterruptedException or ExecutionException " + e);
-        }
-
-        // Verify the thread unblocked, and the flag got set.
-        assertTrue(getFinishedWaiting());
-        assertFalse(getWaitFailed());
-    }
-
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java
deleted file mode 100644
index 6b3bed9..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java
+++ /dev/null
@@ -1,229 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
-import com.google.android.gms.gcm.GcmNetworkManager;
-import com.google.android.gms.gcm.Task;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.internal.ShadowExtractor;
-import org.robolectric.shadows.gms.Shadows;
-import org.robolectric.shadows.gms.common.ShadowGoogleApiAvailability;
-
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
-import org.chromium.base.BaseSwitches;
-import org.chromium.base.CommandLine;
-import org.chromium.base.SysUtils;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeBackgroundServiceWaiter;
-import org.chromium.chrome.browser.DisableHistogramsRule;
-import org.chromium.net.ConnectionType;
-import org.chromium.testing.local.LocalRobolectricTestRunner;
-
-/**
- * Unit tests for BackgroundOfflinerTask.
- */
-@RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, sdk = 21,
-        shadows = {ShadowGcmNetworkManager.class, ShadowGoogleApiAvailability.class,
-                ShadowDeviceConditions.class})
-public class BackgroundOfflinerTaskTest {
-    private static final boolean REQUIRE_POWER = true;
-    private static final boolean REQUIRE_UNMETERED = true;
-    private static final boolean POWER_CONNECTED = true;
-    private static final int MINIMUM_BATTERY_LEVEL = 33;
-    private static final String IS_LOW_END_DEVICE_SWITCH =
-            "--" + BaseSwitches.ENABLE_LOW_END_DEVICE_MODE;
-
-    @Rule
-    public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
-
-    private Bundle mTaskExtras;
-    private long mTestTime;
-    private StubBackgroundSchedulerProcessor mStubBackgroundSchedulerProcessor;
-    private TriggerConditions mTriggerConditions =
-            new TriggerConditions(!REQUIRE_POWER, MINIMUM_BATTERY_LEVEL, REQUIRE_UNMETERED);
-    private DeviceConditions mDeviceConditions = new DeviceConditions(
-            !POWER_CONNECTED, MINIMUM_BATTERY_LEVEL + 5, ConnectionType.CONNECTION_3G);
-    private Activity mTestActivity;
-
-    private Context mContext;
-    private ShadowGcmNetworkManager mGcmNetworkManager;
-
-    @Before
-    public void setUp() throws Exception {
-        Shadows.shadowOf(GoogleApiAvailability.getInstance())
-                .setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS);
-        ShadowDeviceConditions.setCurrentConditions(mDeviceConditions);
-
-        // Build a bundle with trigger conditions.
-        mTaskExtras = new Bundle();
-        TaskExtrasPacker.packTimeInBundle(mTaskExtras);
-        TaskExtrasPacker.packTriggerConditionsInBundle(mTaskExtras, mTriggerConditions);
-
-        mStubBackgroundSchedulerProcessor = new StubBackgroundSchedulerProcessor();
-        mContext =  RuntimeEnvironment.application;
-        mGcmNetworkManager = (ShadowGcmNetworkManager) ShadowExtractor.extract(
-                GcmNetworkManager.getInstance(mContext));
-        mGcmNetworkManager.clear();
-
-        // Run tests as a low-end device.
-        CommandLine.init(new String[] {"testcommand", IS_LOW_END_DEVICE_SWITCH});
-
-        // Set up single, stopped Activity.
-        ApplicationStatus.destroyForJUnitTests();
-        mTestActivity = new Activity();
-        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.CREATED);
-        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.STOPPED);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        // Clean up static state for subsequent Robolectric tests.
-        CommandLine.reset();
-        SysUtils.reset();
-        ApplicationStatus.destroyForJUnitTests();
-    }
-
-    @Test
-    @Feature({"OfflinePages"})
-    public void testStartBackgroundRequests() {
-        BackgroundOfflinerTask task = new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
-        ChromeBackgroundServiceWaiter waiter = new ChromeBackgroundServiceWaiter(1);
-        assertNull("Nothing scheduled", mGcmNetworkManager.getScheduledTask());
-
-        task.startBackgroundRequests(RuntimeEnvironment.application, mTaskExtras, waiter);
-
-        // Check that the backup task was scheduled.
-        Task gcmTask = mGcmNetworkManager.getScheduledTask();
-        assertNotNull("Backup task scheduled", gcmTask);
-        assertEquals(mTriggerConditions,
-                TaskExtrasPacker.unpackTriggerConditionsFromBundle(gcmTask.getExtras()));
-
-        // Check with BackgroundSchedulerProcessor that processing stated.
-        assertTrue(mStubBackgroundSchedulerProcessor.getDidStartProcessing());
-        assertSame(mDeviceConditions, mStubBackgroundSchedulerProcessor.getDeviceConditions());
-
-        // Waiter is only released at the end of the test, when the processing concludes.
-        mStubBackgroundSchedulerProcessor.callback();
-        waiter.startWaiting();
-    }
-
-    @Test
-    @Feature({"OfflinePages"})
-    public void testStartBackgroundRequestsNotStarted() {
-        mStubBackgroundSchedulerProcessor.setFailToStart(true);
-        BackgroundOfflinerTask task = new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
-        ChromeBackgroundServiceWaiter waiter = new ChromeBackgroundServiceWaiter(1);
-        assertNull("Nothing scheduled", mGcmNetworkManager.getScheduledTask());
-
-        task.startBackgroundRequests(RuntimeEnvironment.application, mTaskExtras, waiter);
-        waiter.startWaiting();
-
-        // Check that the backup task was scheduled.
-        Task gcmTask = mGcmNetworkManager.getScheduledTask();
-        assertNotNull("Backup task scheduled", gcmTask);
-        assertEquals(mTriggerConditions,
-                TaskExtrasPacker.unpackTriggerConditionsFromBundle(gcmTask.getExtras()));
-
-        // Check with BackgroundSchedulerProcessor that it did not start.
-        assertFalse(mStubBackgroundSchedulerProcessor.getDidStartProcessing());
-    }
-
-    @Test
-    @Feature({"OfflinePages"})
-    public void testStartBackgroundRequestsForLowBatteryLevel() {
-        // Setup low battery conditions.
-        DeviceConditions deviceConditionsLowBattery = new DeviceConditions(
-                !POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI);
-        ShadowDeviceConditions.setCurrentConditions(deviceConditionsLowBattery);
-
-        BackgroundOfflinerTask task = new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
-        ChromeBackgroundServiceWaiter waiter = new ChromeBackgroundServiceWaiter(1);
-        assertNull("Nothing scheduled", mGcmNetworkManager.getScheduledTask());
-        task.startBackgroundRequests(RuntimeEnvironment.application, mTaskExtras, waiter);
-        waiter.startWaiting();
-
-        // Check that the backup task was scheduled.
-        Task gcmTask = mGcmNetworkManager.getScheduledTask();
-        assertNotNull("Backup task scheduled", gcmTask);
-        assertEquals(mTriggerConditions,
-                TaskExtrasPacker.unpackTriggerConditionsFromBundle(gcmTask.getExtras()));
-
-        // Check that startScheduledProcessing was NOT called.
-        assertFalse(mStubBackgroundSchedulerProcessor.getDidStartProcessing());
-
-        // Now verify low battery level but with power connected will start processing.
-        DeviceConditions deviceConditionsPowerConnected = new DeviceConditions(
-                POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI);
-        ShadowDeviceConditions.setCurrentConditions(deviceConditionsPowerConnected);
-
-        BackgroundOfflinerTask task2 =
-                new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
-        ChromeBackgroundServiceWaiter waiter2 = new ChromeBackgroundServiceWaiter(1);
-        task2.startBackgroundRequests(RuntimeEnvironment.application, mTaskExtras, waiter2);
-
-        assertTrue(mStubBackgroundSchedulerProcessor.getDidStartProcessing());
-
-        mStubBackgroundSchedulerProcessor.callback();
-        waiter2.startWaiting();
-    }
-
-    @Test
-    @Feature({"OfflinePages"})
-    public void testStartBackgroundRequestsForRunningActivityOnLowEndDevice() {
-        BackgroundOfflinerTask task = new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
-        ChromeBackgroundServiceWaiter waiter = new ChromeBackgroundServiceWaiter(1);
-        assertNull("Nothing scheduled", mGcmNetworkManager.getScheduledTask());
-
-        // Transition the test Activity to a running state.
-        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.STARTED);
-
-        task.startBackgroundRequests(RuntimeEnvironment.application, mTaskExtras, waiter);
-        waiter.startWaiting();
-
-        // Check that the backup task was scheduled.
-        Task gcmTask = mGcmNetworkManager.getScheduledTask();
-        assertNotNull("Backup task scheduled", gcmTask);
-        assertEquals(mTriggerConditions,
-                TaskExtrasPacker.unpackTriggerConditionsFromBundle(gcmTask.getExtras()));
-
-        // Check that startScheduledProcessing was NOT called.
-        assertFalse(mStubBackgroundSchedulerProcessor.getDidStartProcessing());
-
-        // Now verify will start processing when Activity is stopped.
-        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.STOPPED);
-        BackgroundOfflinerTask task2 =
-                new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
-        ChromeBackgroundServiceWaiter waiter2 = new ChromeBackgroundServiceWaiter(1);
-        task2.startBackgroundRequests(RuntimeEnvironment.application, mTaskExtras, waiter2);
-
-        assertTrue(mStubBackgroundSchedulerProcessor.getDidStartProcessing());
-
-        mStubBackgroundSchedulerProcessor.callback();
-        waiter2.startWaiting();
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java
index 32b959e8..6b0095d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerTest.java
@@ -5,98 +5,147 @@
 package org.chromium.chrome.browser.offlinepages;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.GoogleApiAvailability;
-import com.google.android.gms.gcm.GcmNetworkManager;
-import com.google.android.gms.gcm.Task;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
-import org.robolectric.internal.ShadowExtractor;
-import org.robolectric.shadows.gms.Shadows;
-import org.robolectric.shadows.gms.common.ShadowGoogleApiAvailability;
 
-import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.Feature;
+import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
+import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.components.background_task_scheduler.TaskInfo;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
 /**
  * Unit tests for BackgroundScheduler.
  */
 @RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class, sdk = 21,
-        shadows = {ShadowGcmNetworkManager.class, ShadowGoogleApiAvailability.class})
+@Config(manifest = Config.NONE)
 public class BackgroundSchedulerTest {
-    private Context mContext;
     private TriggerConditions mConditions1 = new TriggerConditions(
-            true /* power */, 10 /* battery percentage */, false /* unmetered */);
+            true /* power */, 10 /* battery percentage */, true /* requires unmetered */);
     private TriggerConditions mConditions2 = new TriggerConditions(
-            false /* power */, 0 /* battery percentage */, false /* unmetered */);
-    private ShadowGcmNetworkManager mGcmNetworkManager;
+            false /* power */, 0 /* battery percentage */, false /* does not require unmetered */);
+
+    @Mock
+    private BackgroundTaskScheduler mTaskScheduler;
+    @Captor
+    ArgumentCaptor<TaskInfo> mTaskInfo;
 
     @Before
     public void setUp() throws Exception {
-        Shadows.shadowOf(GoogleApiAvailability.getInstance())
-                .setIsGooglePlayServicesAvailable(ConnectionResult.SUCCESS);
+        MockitoAnnotations.initMocks(this);
+        ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application);
+        BackgroundTaskSchedulerFactory.setSchedulerForTesting(mTaskScheduler);
+        doReturn(true)
+                .when(mTaskScheduler)
+                .schedule(eq(RuntimeEnvironment.application), mTaskInfo.capture());
+    }
 
-        mContext = RuntimeEnvironment.application;
-        mGcmNetworkManager = (ShadowGcmNetworkManager) ShadowExtractor.extract(
-                GcmNetworkManager.getInstance(mContext));
-        mGcmNetworkManager.clear();
+    private void verifyFixedTaskInfoValues(TaskInfo info) {
+        assertEquals(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID, info.getTaskId());
+        assertEquals(OfflineBackgroundTask.class, info.getBackgroundTaskClass());
+        assertTrue(info.isPersisted());
+        assertFalse(info.isPeriodic());
+        assertEquals(BackgroundScheduler.ONE_WEEK_IN_MILLISECONDS,
+                info.getOneOffInfo().getWindowEndTimeMs());
+        assertTrue(info.getOneOffInfo().hasWindowStartTimeConstraint());
+
+        long scheduledTimeMillis = TaskExtrasPacker.unpackTimeFromBundle(info.getExtras());
+        assertTrue(scheduledTimeMillis > 0L);
     }
 
     @Test
     @Feature({"OfflinePages"})
-    public void testSchedule() {
-        assertNull(mGcmNetworkManager.getScheduledTask());
-        BackgroundScheduler.getInstance(mContext).schedule(mConditions1);
-        // Check with gcmNetworkManagerShadow that schedule got called.
-        assertNotNull(mGcmNetworkManager.getScheduledTask());
+    public void testScheduleUnmeteredAndCharging() {
+        BackgroundScheduler.getInstance().schedule(mConditions1);
+        verify(mTaskScheduler, times(1))
+                .schedule(eq(RuntimeEnvironment.application), eq(mTaskInfo.getValue()));
 
-        // Verify details of the scheduled task.
-        Task task = mGcmNetworkManager.getScheduledTask();
-        assertEquals(OfflinePageUtils.TASK_TAG, task.getTag());
-        long scheduledTimeMillis = TaskExtrasPacker.unpackTimeFromBundle(task.getExtras());
-        assertTrue(scheduledTimeMillis > 0L);
+        TaskInfo info = mTaskInfo.getValue();
+        verifyFixedTaskInfoValues(info);
+
+        assertEquals(TaskInfo.NETWORK_TYPE_UNMETERED, info.getRequiredNetworkType());
+        assertTrue(info.requiresCharging());
+
+        assertTrue(info.shouldUpdateCurrent());
+        assertEquals(BackgroundScheduler.NO_DELAY, info.getOneOffInfo().getWindowStartTimeMs());
+
         assertEquals(
-                mConditions1, TaskExtrasPacker.unpackTriggerConditionsFromBundle(task.getExtras()));
+                mConditions1, TaskExtrasPacker.unpackTriggerConditionsFromBundle(info.getExtras()));
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testScheduleMeteredAndNotCharging() {
+        BackgroundScheduler.getInstance().schedule(mConditions2);
+        verify(mTaskScheduler, times(1))
+                .schedule(eq(RuntimeEnvironment.application), eq(mTaskInfo.getValue()));
+
+        TaskInfo info = mTaskInfo.getValue();
+        verifyFixedTaskInfoValues(info);
+
+        assertEquals(TaskInfo.NETWORK_TYPE_ANY, info.getRequiredNetworkType());
+        assertFalse(info.requiresCharging());
+
+        assertTrue(info.shouldUpdateCurrent());
+        assertEquals(BackgroundScheduler.NO_DELAY, info.getOneOffInfo().getWindowStartTimeMs());
+
+        assertEquals(
+                mConditions2, TaskExtrasPacker.unpackTriggerConditionsFromBundle(info.getExtras()));
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testScheduleBackup() {
+        BackgroundScheduler.getInstance().scheduleBackup(
+                mConditions1, BackgroundScheduler.FIVE_MINUTES_IN_MILLISECONDS);
+        verify(mTaskScheduler, times(1))
+                .schedule(eq(RuntimeEnvironment.application), eq(mTaskInfo.getValue()));
+
+        TaskInfo info = mTaskInfo.getValue();
+        verifyFixedTaskInfoValues(info);
+
+        assertEquals(TaskInfo.NETWORK_TYPE_UNMETERED, info.getRequiredNetworkType());
+        assertTrue(info.requiresCharging());
+
+        assertFalse(info.shouldUpdateCurrent());
+        assertEquals(BackgroundScheduler.FIVE_MINUTES_IN_MILLISECONDS,
+                info.getOneOffInfo().getWindowStartTimeMs());
+
+        assertEquals(
+                mConditions1, TaskExtrasPacker.unpackTriggerConditionsFromBundle(info.getExtras()));
     }
 
     @Test
     @Feature({"OfflinePages"})
     public void testCancel() {
-        assertNull(mGcmNetworkManager.getScheduledTask());
-        BackgroundScheduler.getInstance(mContext).schedule(mConditions1);
-        assertNotNull(mGcmNetworkManager.getScheduledTask());
+        BackgroundScheduler.getInstance().schedule(mConditions1);
+        verify(mTaskScheduler, times(1))
+                .schedule(eq(RuntimeEnvironment.application), eq(mTaskInfo.getValue()));
 
-        assertNull(mGcmNetworkManager.getCanceledTask());
-        BackgroundScheduler.getInstance(mContext).cancel();
-        assertNotNull(mGcmNetworkManager.getCanceledTask());
-    }
-
-    @Test
-    @Feature({"OfflinePages"})
-    public void testReschedulOnUpgrade() {
-        assertNull(mGcmNetworkManager.getScheduledTask());
-        BackgroundScheduler.getInstance(mContext).rescheduleOfflinePagesTasksOnUpgrade();
-        // Check with gcmNetworkManagerShadow that schedule got called.
-        assertNotNull(mGcmNetworkManager.getScheduledTask());
-
-        // Verify details of the scheduled task.
-        Task task = mGcmNetworkManager.getScheduledTask();
-        assertEquals(OfflinePageUtils.TASK_TAG, task.getTag());
-        long scheduledTimeMillis = TaskExtrasPacker.unpackTimeFromBundle(task.getExtras());
-        assertTrue(scheduledTimeMillis > 0L);
-        assertEquals(
-                mConditions2, TaskExtrasPacker.unpackTriggerConditionsFromBundle(task.getExtras()));
+        doNothing()
+                .when(mTaskScheduler)
+                .cancel(eq(RuntimeEnvironment.application),
+                        eq(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID));
+        BackgroundScheduler.getInstance().cancel();
+        verify(mTaskScheduler, times(1))
+                .cancel(eq(RuntimeEnvironment.application),
+                        eq(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID));
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java
new file mode 100644
index 0000000..61a665c
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java
@@ -0,0 +1,287 @@
+// 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.
+
+package org.chromium.chrome.browser.offlinepages;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BaseSwitches;
+import org.chromium.base.Callback;
+import org.chromium.base.CommandLine;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.SysUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.DisableHistogramsRule;
+import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
+import org.chromium.components.background_task_scheduler.BackgroundTask;
+import org.chromium.components.background_task_scheduler.BackgroundTaskScheduler;
+import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.components.background_task_scheduler.TaskInfo;
+import org.chromium.components.background_task_scheduler.TaskParameters;
+import org.chromium.net.ConnectionType;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+/**
+ * Unit tests for OfflineBackgroundTask.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {ShadowDeviceConditions.class})
+public class OfflineBackgroundTaskTest {
+    private static final boolean REQUIRE_POWER = true;
+    private static final boolean REQUIRE_UNMETERED = true;
+    private static final boolean POWER_CONNECTED = true;
+    private static final int MINIMUM_BATTERY_LEVEL = 33;
+    private static final String IS_LOW_END_DEVICE_SWITCH =
+            "--" + BaseSwitches.ENABLE_LOW_END_DEVICE_MODE;
+
+    @Rule
+    public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
+
+    private Bundle mTaskExtras;
+    private long mTestTime;
+    private TriggerConditions mTriggerConditions =
+            new TriggerConditions(!REQUIRE_POWER, MINIMUM_BATTERY_LEVEL, REQUIRE_UNMETERED);
+    private DeviceConditions mDeviceConditions = new DeviceConditions(
+            !POWER_CONNECTED, MINIMUM_BATTERY_LEVEL + 5, ConnectionType.CONNECTION_3G);
+    private Activity mTestActivity;
+
+    @Mock
+    private BackgroundSchedulerProcessor mBackgroundSchedulerProcessor;
+
+    @Mock
+    private BackgroundTaskScheduler mTaskScheduler;
+    @Mock
+    private BackgroundTask.TaskFinishedCallback mTaskFinishedCallback;
+    @Mock
+    private Callback<Boolean> mInternalBooleanCallback;
+    @Captor
+    private ArgumentCaptor<TaskInfo> mTaskInfo;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application);
+        BackgroundTaskSchedulerFactory.setSchedulerForTesting(mTaskScheduler);
+        doReturn(true)
+                .when(mTaskScheduler)
+                .schedule(eq(RuntimeEnvironment.application), mTaskInfo.capture());
+
+        ShadowDeviceConditions.setCurrentConditions(mDeviceConditions);
+
+        // Set up background scheduler processor mock.
+        BackgroundSchedulerProcessor.setInstanceForTesting(mBackgroundSchedulerProcessor);
+
+        // Build a bundle with trigger conditions.
+        mTaskExtras = new Bundle();
+        TaskExtrasPacker.packTimeInBundle(mTaskExtras);
+        TaskExtrasPacker.packTriggerConditionsInBundle(mTaskExtras, mTriggerConditions);
+
+        // Run tests as a low-end device.
+        CommandLine.init(new String[] {"testcommand", IS_LOW_END_DEVICE_SWITCH});
+
+        // Set up single, stopped Activity.
+        ApplicationStatus.destroyForJUnitTests();
+        mTestActivity = new Activity();
+        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.CREATED);
+        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.STOPPED);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Clean up static state for subsequent Robolectric tests.
+        CommandLine.reset();
+        SysUtils.reset();
+        ApplicationStatus.destroyForJUnitTests();
+    }
+
+    private void setupScheduledProcessingWithResult(boolean result) {
+        doReturn(result)
+                .when(mBackgroundSchedulerProcessor)
+                .startScheduledProcessing(
+                        any(DeviceConditions.class), ArgumentMatchers.<Callback<Boolean>>any());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testCheckConditions_BatteryConditions_LowBattery_NoPower() {
+        // Setup low battery conditions with no power connected.
+        DeviceConditions deviceConditionsLowBattery = new DeviceConditions(
+                !POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI);
+        ShadowDeviceConditions.setCurrentConditions(deviceConditionsLowBattery);
+
+        // Verify that conditions for processing are not met.
+        assertFalse(
+                OfflineBackgroundTask.checkConditions(RuntimeEnvironment.application, mTaskExtras));
+
+        // Check impact on starting before native loaded.
+        TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded(
+                RuntimeEnvironment.application, params, mTaskFinishedCallback);
+        assertEquals(NativeBackgroundTask.RESCHEDULE, result);
+        // Task finished can only gets called from the native part, when async processing starts.
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testCheckConditions_BatteryConditions_LowBattery_WithPower() {
+        // Set battery percentage below minimum level, but connect power.
+        DeviceConditions deviceConditionsPowerConnected = new DeviceConditions(
+                POWER_CONNECTED, MINIMUM_BATTERY_LEVEL - 1, ConnectionType.CONNECTION_WIFI);
+        ShadowDeviceConditions.setCurrentConditions(deviceConditionsPowerConnected);
+
+        // Now verify that same battery level, with power connected, will pass the conditions.
+        assertTrue(
+                OfflineBackgroundTask.checkConditions(RuntimeEnvironment.application, mTaskExtras));
+
+        // Check impact on starting before native loaded.
+        TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded(
+                RuntimeEnvironment.application, params, mTaskFinishedCallback);
+        assertEquals(NativeBackgroundTask.LOAD_NATIVE, result);
+        // Task finished can only gets called from the native part, when async processing starts.
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testCheckConditions_OnLowEndDevice_ActivityStarted() {
+        // Transition the test Activity to a running state.
+        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.STARTED);
+
+        // Verify that conditions for processing are not met.
+        assertFalse(
+                OfflineBackgroundTask.checkConditions(RuntimeEnvironment.application, mTaskExtras));
+
+        // Check impact on starting before native loaded.
+        TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded(
+                RuntimeEnvironment.application, params, mTaskFinishedCallback);
+        assertEquals(NativeBackgroundTask.RESCHEDULE, result);
+        // Task finished can only gets called from the native part, when async processing starts.
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testCheckConditions_OnLowEndDevice_ActivityStopped() {
+        // Switch activity state to stopped.
+        ApplicationStatus.onStateChangeForTesting(mTestActivity, ActivityState.STOPPED);
+
+        // Now verify that condition check passes when Activity is stopped.
+        assertTrue(
+                OfflineBackgroundTask.checkConditions(RuntimeEnvironment.application, mTaskExtras));
+
+        // Check impact on starting before native loaded.
+        TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        int result = new OfflineBackgroundTask().onStartTaskBeforeNativeLoaded(
+                RuntimeEnvironment.application, params, mTaskFinishedCallback);
+        assertEquals(NativeBackgroundTask.LOAD_NATIVE, result);
+        // Task finished can only gets called from the native part, when async processing starts.
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testOnStartTaskWithNative_BackupScheduleIfExecutingTask() {
+        setupScheduledProcessingWithResult(true);
+
+        TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        new OfflineBackgroundTask().onStartTaskWithNative(
+                RuntimeEnvironment.application, params, mTaskFinishedCallback);
+
+        verify(mTaskScheduler, times(1))
+                .schedule(eq(RuntimeEnvironment.application), any(TaskInfo.class));
+        // Task is running at this point, hence no callback issued.
+        verify(mTaskFinishedCallback, times(0)).taskFinished(anyBoolean());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testOnStartTaskWithNative_RescheduleThroughCallbackWhenRunning() {
+        setupScheduledProcessingWithResult(false);
+
+        TaskParameters params = TaskParameters.create(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)
+                                        .addExtras(mTaskExtras)
+                                        .build();
+
+        new OfflineBackgroundTask().onStartTaskWithNative(
+                RuntimeEnvironment.application, params, mTaskFinishedCallback);
+
+        verify(mTaskScheduler, times(0)).schedule(any(Context.class), any(TaskInfo.class));
+        // Task started async processing after native load, but processing refused to progress,
+        // hence task finished called with reschedule request.
+        verify(mTaskFinishedCallback, times(1)).taskFinished(eq(true));
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testStartBackgroundRequests() {
+        setupScheduledProcessingWithResult(true);
+
+        assertTrue(OfflineBackgroundTask.startScheduledProcessing(mBackgroundSchedulerProcessor,
+                RuntimeEnvironment.application, mTaskExtras, mInternalBooleanCallback));
+
+        // Check with BackgroundSchedulerProcessor that processing started.
+        verify(mBackgroundSchedulerProcessor, times(1))
+                .startScheduledProcessing(eq(mDeviceConditions), eq(mInternalBooleanCallback));
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
+    public void testStartBackgroundRequestsNotStarted() {
+        // Processing will not be started here.
+        setupScheduledProcessingWithResult(false);
+
+        assertFalse(OfflineBackgroundTask.startScheduledProcessing(mBackgroundSchedulerProcessor,
+                RuntimeEnvironment.application, mTaskExtras, mInternalBooleanCallback));
+
+        // Check with BackgroundSchedulerProcessor that it did not start.
+        verify(mBackgroundSchedulerProcessor, times(1))
+                .startScheduledProcessing(eq(mDeviceConditions), eq(mInternalBooleanCallback));
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ShadowGcmNetworkManager.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ShadowGcmNetworkManager.java
deleted file mode 100644
index f1f9420..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ShadowGcmNetworkManager.java
+++ /dev/null
@@ -1,50 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import com.google.android.gms.gcm.GcmNetworkManager;
-import com.google.android.gms.gcm.GcmTaskService;
-import com.google.android.gms.gcm.Task;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-/**
- * Custom shadow for the OS's GcmNetworkManager.  We use this to hook the call to GcmNetworkManager
- * to make sure it was invoked as we expect.
- */
-@Implements(GcmNetworkManager.class)
-public class ShadowGcmNetworkManager {
-    private Task mTask;
-    private Task mCanceledTask;
-
-    @Implementation
-    public void schedule(Task task) {
-        // Capture the string part divisions so we can check them.
-        mTask = task;
-    }
-
-    @Implementation
-    public void cancelTask(String tag, Class<? extends GcmTaskService> gcmTaskService) {
-        if (mTask != null && mTask.getTag().equals(tag)
-                && mTask.getServiceName().equals(gcmTaskService.getName())) {
-            mCanceledTask = mTask;
-            mTask = null;
-        }
-    }
-
-    public Task getScheduledTask() {
-        return mTask;
-    }
-
-    public Task getCanceledTask() {
-        return mCanceledTask;
-    }
-
-    public void clear() {
-        mTask = null;
-        mCanceledTask = null;
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java
deleted file mode 100644
index 3951d5e4..0000000
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java
+++ /dev/null
@@ -1,52 +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.
-
-package org.chromium.chrome.browser.offlinepages;
-
-import org.chromium.base.Callback;
-import org.chromium.chrome.browser.offlinepages.interfaces.BackgroundSchedulerProcessor;
-
-/**
- * Custom stub for our own BackgroundSchedulerRequestProcessor.
- */
-public class StubBackgroundSchedulerProcessor implements BackgroundSchedulerProcessor {
-    private boolean mFailToStart;
-    private boolean mDidStartProcessing;
-    private DeviceConditions mDeviceConditions;
-    private Callback<Boolean> mCallback;
-
-    public void setFailToStart(boolean failToStart) {
-        mFailToStart = failToStart;
-    }
-
-    public boolean getDidStartProcessing() {
-        return mDidStartProcessing;
-    }
-
-    public DeviceConditions getDeviceConditions() {
-        return mDeviceConditions;
-    }
-
-    public void callback() {
-        mCallback.onResult(true);
-    }
-
-    @Override
-    public boolean startScheduledProcessing(
-            DeviceConditions deviceConditions, Callback<Boolean> callback) {
-        if (mFailToStart) {
-            return false;
-        }
-
-        mDidStartProcessing = true;
-        mDeviceConditions = deviceConditions;
-        mCallback = callback;
-        return true;
-    }
-
-    @Override
-    public boolean stopScheduledProcessing() {
-        return true;
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPackerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPackerTest.java
index c2b05590..668d520f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPackerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/TaskExtrasPackerTest.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.offlinepages;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
@@ -16,7 +15,6 @@
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeBackgroundService;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
 /** Unit tests for {@link TaskExtrasPacker}. */
@@ -37,15 +35,6 @@
 
     @Test
     @Feature({"OfflinePages"})
-    public void testHoldWakelock() {
-        Bundle taskExtras = new Bundle();
-        assertFalse(taskExtras.getBoolean(ChromeBackgroundService.HOLD_WAKELOCK, false));
-        TaskExtrasPacker.packHoldWakelock(taskExtras);
-        assertTrue(taskExtras.getBoolean(ChromeBackgroundService.HOLD_WAKELOCK, false));
-    }
-
-    @Test
-    @Feature({"OfflinePages"})
     public void testTriggerConditionsExtra() {
         Bundle taskExtras = new Bundle();
         TriggerConditions conditions1 = new TriggerConditions(true, 25, false);
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java
index 9f285c8..1d6b4c7 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/MainActivity.java
@@ -7,9 +7,6 @@
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
@@ -68,7 +65,10 @@
      */
     private void launch() {
         String overrideUrl = getOverrideUrl();
-        String startUrl = (overrideUrl != null) ? overrideUrl : getStartUrl();
+        String startUrl = (overrideUrl != null)
+                ? overrideUrl
+                : WebApkUtils.readMetaDataFromManifest(this, WebApkMetaDataKeys.START_URL);
+
         if (startUrl == null) {
             return;
         }
@@ -178,16 +178,4 @@
         }
         return null;
     }
-
-    /** Returns the start URL from the Android Manifest. */
-    private String getStartUrl() {
-        ApplicationInfo appInfo;
-        try {
-            appInfo = getPackageManager().getApplicationInfo(
-                    getPackageName(), PackageManager.GET_META_DATA);
-        } catch (NameNotFoundException e) {
-            return null;
-        }
-        return appInfo.metaData.getString(WebApkMetaDataKeys.START_URL);
-    }
 }
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
index a9b5424f..4096cdc 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
@@ -8,7 +8,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
 
 import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
 
@@ -47,20 +46,24 @@
      */
     public static String getHostBrowserPackageName(Context context) {
         if (sHostPackage != null) return sHostPackage;
-        String hostPackage = null;
-        try {
-            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
-                    context.getPackageName(), PackageManager.GET_META_DATA);
-            Bundle bundle = ai.metaData;
-            hostPackage = bundle.getString(WebApkMetaDataKeys.RUNTIME_HOST);
-        } catch (NameNotFoundException e) {
-            e.printStackTrace();
-        }
+        String hostPackage = readMetaDataFromManifest(context, WebApkMetaDataKeys.RUNTIME_HOST);
         // Set {@link sHostPackage} to a non-null value so that the value is computed only once.
         sHostPackage = hostPackage != null ? hostPackage : "";
         return sHostPackage;
     }
 
+    /** Returns the <meta-data> value in the Android Manifest for {@link key}. */
+    public static String readMetaDataFromManifest(Context context, String key) {
+        ApplicationInfo ai = null;
+        try {
+            ai = context.getPackageManager().getApplicationInfo(
+                    context.getPackageName(), PackageManager.GET_META_DATA);
+        } catch (NameNotFoundException e) {
+            return null;
+        }
+        return ai.metaData.getString(key);
+    }
+
     /**
      * Returns the uid for the host browser that was specified when building the WebAPK.
      * @param context A context.
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc
index 50f8373e..209516d 100644
--- a/chrome/app/chrome_exe_main_win.cc
+++ b/chrome/app/chrome_exe_main_win.cc
@@ -123,14 +123,9 @@
   // does not have EnableChildWindowDpiMessage, necessary for correct non-client
   // area scaling across monitors.
   bool allowed_platform = base::win::GetVersion() >= base::win::VERSION_WIN10;
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
-  bool per_monitor_dpi_switch =
-      !command_line->HasSwitch(switches::kDisablePerMonitorDpi);
   PROCESS_DPI_AWARENESS process_dpi_awareness =
-      allowed_platform && per_monitor_dpi_switch
-          ? PROCESS_PER_MONITOR_DPI_AWARE
-          : PROCESS_SYSTEM_DPI_AWARE;
+      allowed_platform ? PROCESS_PER_MONITOR_DPI_AWARE
+                       : PROCESS_SYSTEM_DPI_AWARE;
   if (!SetProcessDpiAwarenessWrapper(process_dpi_awareness)) {
     SetProcessDPIAwareWrapper();
   }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 9d6c032..e13f52bc 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -7802,9 +7802,6 @@
           Import bookmarks and settings...
         </message>
 
-        <message name="IDS_OPTIONS_CONTROLLED_SETTING_POLICY" desc="Text displayed in the controlled settings bubble when a setting's value is enforced by policy.">
-          This setting is enforced by your administrator.
-        </message>
         <message name="IDS_OPTIONS_CONTROLLED_SETTING_EXTENSION" desc="Text displayed in the controlled settings bubble when a setting's value is enforced by an extension.">
           This setting is enforced by an extension.
         </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f5c2bb7..542d001 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -280,6 +280,8 @@
     "conflicts/module_inspector_win.h",
     "conflicts/msi_util_win.cc",
     "conflicts/msi_util_win.h",
+    "conflicts/third_party_metrics_recorder_win.cc",
+    "conflicts/third_party_metrics_recorder_win.h",
     "content_settings/chrome_content_settings_utils.cc",
     "content_settings/chrome_content_settings_utils.h",
     "content_settings/cookie_settings_factory.cc",
@@ -696,6 +698,8 @@
     "net/file_downloader.h",
     "net/http_server_properties_manager_factory.cc",
     "net/http_server_properties_manager_factory.h",
+    "net/loading_predictor_observer.cc",
+    "net/loading_predictor_observer.h",
     "net/net_error_diagnostics_dialog.h",
     "net/net_error_diagnostics_dialog_mac.cc",
     "net/net_error_diagnostics_dialog_win.cc",
@@ -723,8 +727,6 @@
     "net/referrer.h",
     "net/request_source_bandwidth_histograms.cc",
     "net/request_source_bandwidth_histograms.h",
-    "net/resource_prefetch_predictor_observer.cc",
-    "net/resource_prefetch_predictor_observer.h",
     "net/safe_search_util.cc",
     "net/safe_search_util.h",
     "net/sdch_owner_pref_storage.cc",
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index db2a624..439c241 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -30,6 +30,7 @@
 #include "content/public/common/referrer.h"
 #include "jni/DownloadController_jni.h"
 #include "net/base/filename_util.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
 #include "ui/base/page_transition_types.h"
@@ -91,7 +92,7 @@
   if (!is_link && extra_headers.empty())
     dl_params->set_prefer_cache(true);
   dl_params->set_prompt(false);
-  dlm->DownloadUrl(std::move(dl_params));
+  dlm->DownloadUrl(std::move(dl_params), NO_TRAFFIC_ANNOTATION_YET);
 }
 
 // Check if an interrupted download item can be auto resumed.
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
index 02ef92b..ab5c979 100644
--- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -34,6 +34,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/OfflinePageDownloadBridge_jni.h"
 #include "net/base/filename_util.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "url/gurl.h"
 
 using base::android::AttachCurrentThread;
@@ -367,7 +368,7 @@
 
     dl_params->set_prefer_cache(true);
     dl_params->set_prompt(false);
-    dlm->DownloadUrl(std::move(dl_params));
+    dlm->DownloadUrl(std::move(dl_params), NO_TRAFFIC_ANNOTATION_YET);
     return;
   }
 
diff --git a/chrome/browser/android/resource_id.h b/chrome/browser/android/resource_id.h
index 7b0a881b..0dfcf07 100644
--- a/chrome/browser/android/resource_id.h
+++ b/chrome/browser/android/resource_id.h
@@ -68,6 +68,7 @@
 LINK_RESOURCE_ID(IDR_AUTOFILL_CC_AMEX, R.drawable.amex_card)
 LINK_RESOURCE_ID(IDR_AUTOFILL_CC_DINERS, R.drawable.diners_card)
 LINK_RESOURCE_ID(IDR_AUTOFILL_CC_DISCOVER, R.drawable.discover_card)
+LINK_RESOURCE_ID(IDR_AUTOFILL_CC_ELO, R.drawable.elo_card)
 LINK_RESOURCE_ID(IDR_AUTOFILL_CC_GENERIC, R.drawable.ic_credit_card_black)
 LINK_RESOURCE_ID(IDR_AUTOFILL_CC_JCB, R.drawable.jcb_card)
 LINK_RESOURCE_ID(IDR_AUTOFILL_CC_MASTERCARD, R.drawable.mc_card)
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc
index 6892f34..caf4d3a0 100644
--- a/chrome/browser/chrome_browser_field_trials_desktop.cc
+++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -24,8 +24,6 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "components/browser_watcher/features.h"
-#include "components/browser_watcher/stability_paths.h"
 #include "components/metrics/persistent_system_profile.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/common/content_switches.h"
@@ -34,7 +32,10 @@
 #if defined(OS_WIN)
 #include "base/win/pe_image.h"
 #include "chrome/install_static/install_util.h"
+#include "components/browser_watcher/features.h"
 #include "components/browser_watcher/stability_data_names.h"
+#include "components/browser_watcher/stability_metrics.h"
+#include "components/browser_watcher/stability_paths.h"
 #endif
 
 #if defined(OS_WIN)
@@ -68,19 +69,6 @@
 }
 
 #if defined(OS_WIN)
-// DO NOT CHANGE VALUES. This is logged persistently in a histogram.
-enum StabilityDebuggingInitializationStatus {
-  INIT_SUCCESS = 0,
-  CREATE_STABILITY_DIR_FAILED = 1,
-  GET_STABILITY_FILE_PATH_FAILED = 2,
-  INIT_STATUS_MAX = 3
-};
-
-void LogStabilityDebuggingInitStatus(
-    StabilityDebuggingInitializationStatus status) {
-  UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Record.InitStatus", status,
-                            INIT_STATUS_MAX);
-}
 
 // Record information about the chrome module.
 void RecordChromeModuleInfo(
@@ -130,18 +118,18 @@
   base::FilePath user_data_dir;
   if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir) ||
       !base::CreateDirectory(browser_watcher::GetStabilityDir(user_data_dir))) {
-    LOG(ERROR) << "Failed to create the stability directory.";
-    LogStabilityDebuggingInitStatus(CREATE_STABILITY_DIR_FAILED);
     return;
   }
+  browser_watcher::LogStabilityRecordEvent(
+      browser_watcher::StabilityRecordEvent::kStabilityDirectoryExists);
+
   base::FilePath stability_file;
   if (!browser_watcher::GetStabilityFileForProcess(
           base::Process::Current(), user_data_dir, &stability_file)) {
-    LOG(ERROR) << "Failed to obtain stability file's path.";
-    LogStabilityDebuggingInitStatus(GET_STABILITY_FILE_PATH_FAILED);
     return;
   }
-  LogStabilityDebuggingInitStatus(INIT_SUCCESS);
+  browser_watcher::LogStabilityRecordEvent(
+      browser_watcher::StabilityRecordEvent::kGotStabilityPath);
 
   // Track code activities (such as posting task, blocking on locks, and
   // joining threads) that can cause hanging threads and general instability
@@ -153,6 +141,8 @@
   base::debug::GlobalActivityTracker* global_tracker =
       base::debug::GlobalActivityTracker::Get();
   if (global_tracker) {
+    browser_watcher::LogStabilityRecordEvent(
+        browser_watcher::StabilityRecordEvent::kGotTracker);
     // Record product, version, channel, special build and platform.
     wchar_t exe_file[MAX_PATH] = {};
     CHECK(::GetModuleFileName(nullptr, exe_file, arraysize(exe_file)));
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
index 1dcec90..5900062 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/arc/common/accessibility_helper.mojom.h"
 #include "components/exo/wm_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/display.h"
 #include "ui/display/manager/managed_display_info.h"
 
 namespace arc {
@@ -24,16 +25,23 @@
     FakeWMHelper() = default;
 
    private:
-    const display::ManagedDisplayInfo GetDisplayInfo(
+    const display::ManagedDisplayInfo& GetDisplayInfo(
         int64_t display_id) const override {
-      return display::ManagedDisplayInfo(display_id, "", false);
+      static const display::ManagedDisplayInfo info;
+      return info;
     }
-    aura::Window* GetContainer(int container_id) override { return nullptr; }
+    aura::Window* GetPrimaryDisplayContainer(int container_id) override {
+      return nullptr;
+    }
     aura::Window* GetActiveWindow() const override { return nullptr; }
     aura::Window* GetFocusedWindow() const override { return nullptr; }
     ui::CursorSetType GetCursorSet() const override {
       return ui::CursorSetType::CURSOR_SET_NORMAL;
     }
+    const display::Display& GetCursorDisplay() const override {
+      static const display::Display display;
+      return display;
+    }
     void AddPreTargetHandler(ui::EventHandler* handler) override {}
     void PrependPreTargetHandler(ui::EventHandler* handler) override {}
     void RemovePreTargetHandler(ui::EventHandler* handler) override {}
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index b8fe3a4..447290b 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/user_manager/known_user.h"
 #include "extensions/browser/extension_registry.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index e1820c0..b4d6e51 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1219,8 +1219,12 @@
 
   profile->OnLogin();
 
-  session_manager::SessionManager::Get()->SetSessionState(
-      session_manager::SessionState::LOGGED_IN_NOT_ACTIVE);
+  // Skip LOGGED_IN_NOT_ACTIVE state for kiosk launching so that login dialog
+  // such as network config during launch is put on top of the login screen.
+  if (!user_manager->IsLoggedInAsKioskApp()) {
+    session_manager::SessionManager::Get()->SetSessionState(
+        session_manager::SessionState::LOGGED_IN_NOT_ACTIVE);
+  }
 
   // Send the notification before creating the browser so additional objects
   // that need the profile (e.g. the launcher) can be created first.
diff --git a/chrome/browser/chromeos/options/network_config_view.cc b/chrome/browser/chromeos/options/network_config_view.cc
index 3482665..497bbc0 100644
--- a/chrome/browser/chromeos/options/network_config_view.cc
+++ b/chrome/browser/chromeos/options/network_config_view.cc
@@ -26,6 +26,7 @@
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "components/device_event_log/device_event_log.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/user_manager/user.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/aura/window_event_dispatcher.h"
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index b0d4fbca..263a9e2 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -31,6 +31,7 @@
       // base::Unretained().
       module_inspector_(base::Bind(&ModuleDatabase::OnModuleInspected,
                                    base::Unretained(this))),
+      third_party_metrics_(this),
       weak_ptr_factory_(this) {}
 
 ModuleDatabase::~ModuleDatabase() {
diff --git a/chrome/browser/conflicts/module_database_win.h b/chrome/browser/conflicts/module_database_win.h
index 9aba610..57452a5 100644
--- a/chrome/browser/conflicts/module_database_win.h
+++ b/chrome/browser/conflicts/module_database_win.h
@@ -17,6 +17,7 @@
 #include "base/sequenced_task_runner.h"
 #include "chrome/browser/conflicts/module_info_win.h"
 #include "chrome/browser/conflicts/module_inspector_win.h"
+#include "chrome/browser/conflicts/third_party_metrics_recorder_win.h"
 #include "content/public/common/process_type.h"
 
 class ModuleDatabaseObserver;
@@ -175,6 +176,8 @@
 
   base::ObserverList<ModuleDatabaseObserver> observer_list_;
 
+  ThirdPartyMetricsRecorder third_party_metrics_;
+
   // Weak pointer factory for this object. This is used when bouncing
   // incoming events to |task_runner_|.
   base::WeakPtrFactory<ModuleDatabase> weak_ptr_factory_;
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.cc b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
new file mode 100644
index 0000000..aad8300
--- /dev/null
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.cc
@@ -0,0 +1,61 @@
+// 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/conflicts/third_party_metrics_recorder_win.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/conflicts/module_database_win.h"
+#include "chrome/browser/conflicts/module_info_win.h"
+
+ThirdPartyMetricsRecorder::ThirdPartyMetricsRecorder(
+    ModuleDatabase* module_database) {
+  // base::Unretained() is safe here because ThirdPartyMetricsRecorder owns
+  // |installed_programs_| and the callback won't be invoked if this instance is
+  // destroyed.
+  installed_programs_.Initialize(
+      base::Bind(&ThirdPartyMetricsRecorder::OnInstalledProgramsInitialized,
+                 base::Unretained(this), module_database));
+}
+
+ThirdPartyMetricsRecorder::~ThirdPartyMetricsRecorder() = default;
+
+void ThirdPartyMetricsRecorder::OnNewModuleFound(
+    const ModuleInfoKey& module_key,
+    const ModuleInfoData& module_data) {
+  if (!IsThirdPartyModule(module_data))
+    return;
+
+  std::vector<base::string16> program_names;
+  bool uninstallable = installed_programs_.GetInstalledProgramNames(
+      module_key.module_path, &program_names);
+  UMA_HISTOGRAM_BOOLEAN("ThirdPartyModules.Uninstallable", uninstallable);
+}
+
+bool ThirdPartyMetricsRecorder::IsThirdPartyModule(
+    const ModuleInfoData& module_data) {
+  static const wchar_t kMicrosoft[] = L"Microsoft ";
+  static const wchar_t kGoogle[] = L"Google Inc";
+
+  const base::string16& certificate_subject =
+      module_data.inspection_result->certificate_info.subject;
+
+  // Check if the signer name begins with "Microsoft ". Signatures are
+  // typically "Microsoft Corporation" or "Microsoft Windows", but others
+  // may exist.
+  if (base::StartsWith(certificate_subject, kMicrosoft,
+                       base::CompareCase::SENSITIVE))
+    return false;
+
+  return certificate_subject != kGoogle;
+}
+
+void ThirdPartyMetricsRecorder::OnInstalledProgramsInitialized(
+    ModuleDatabase* module_database) {
+  module_database->AddObserver(this);
+}
diff --git a/chrome/browser/conflicts/third_party_metrics_recorder_win.h b/chrome/browser/conflicts/third_party_metrics_recorder_win.h
new file mode 100644
index 0000000..ef1eecdd
--- /dev/null
+++ b/chrome/browser/conflicts/third_party_metrics_recorder_win.h
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CONFLICTS_THIRD_PARTY_METRICS_RECORDER_WIN_H_
+#define CHROME_BROWSER_CONFLICTS_THIRD_PARTY_METRICS_RECORDER_WIN_H_
+
+#include "base/macros.h"
+#include "chrome/browser/conflicts/installed_programs_win.h"
+#include "chrome/browser/conflicts/module_database_observer_win.h"
+
+class ModuleDatabase;
+struct ModuleInfoData;
+struct ModuleInfoKey;
+
+// Records metrics about third party modules loaded into Chrome.
+class ThirdPartyMetricsRecorder : public ModuleDatabaseObserver {
+ public:
+  explicit ThirdPartyMetricsRecorder(ModuleDatabase* module_database);
+  ~ThirdPartyMetricsRecorder() override;
+
+  // ModuleDatabaseObserver:
+  void OnNewModuleFound(const ModuleInfoKey& module_key,
+                        const ModuleInfoData& module_data) override;
+
+ private:
+  void OnInstalledProgramsInitialized(ModuleDatabase* module_database);
+
+  // Returns true if |module_data| is a third party module. Third party modules
+  // are defined as not being signed by Google or Microsoft.
+  bool IsThirdPartyModule(const ModuleInfoData& module_data);
+
+  InstalledPrograms installed_programs_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThirdPartyMetricsRecorder);
+};
+
+#endif  // CHROME_BROWSER_CONFLICTS_THIRD_PARTY_METRICS_RECORDER_WIN_H_
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 3bdf61d..a97e405 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -112,6 +112,7 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
@@ -890,7 +891,8 @@
           DownloadUrlParameters::CreateForWebContentsMainFrame(
               web_contents, starting_url));
       params->set_callback(creation_observer->callback());
-      DownloadManagerForBrowser(browser())->DownloadUrl(std::move(params));
+      DownloadManagerForBrowser(browser())->DownloadUrl(
+          std::move(params), TRAFFIC_ANNOTATION_FOR_TESTS);
 
       // Wait until the item is created, or we have determined that it
       // won't be.
@@ -1723,7 +1725,7 @@
       DownloadUrlParameters::CreateForWebContentsMainFrame(
           new_tab, slow_download_url));
   params->set_prompt(true);
-  manager->DownloadUrl(std::move(params));
+  manager->DownloadUrl(std::move(params), TRAFFIC_ANNOTATION_FOR_TESTS);
   observer->WaitForFinished();
 
   DownloadManager::DownloadVector items;
@@ -2200,7 +2202,8 @@
       DownloadUrlParameters::CreateForWebContentsMainFrame(
           web_contents, url));
   params->set_prompt(true);
-  DownloadManagerForBrowser(browser())->DownloadUrl(std::move(params));
+  DownloadManagerForBrowser(browser())->DownloadUrl(
+      std::move(params), TRAFFIC_ANNOTATION_FOR_TESTS);
   observer->WaitForFinished();
   EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::COMPLETE));
   CheckDownloadStates(1, DownloadItem::COMPLETE);
@@ -2230,7 +2233,8 @@
       DownloadUrlParameters::CreateForWebContentsMainFrame(
           web_contents, url));
   params->set_file_path(target_file_full_path);
-  DownloadManagerForBrowser(browser())->DownloadUrl(std::move(params));
+  DownloadManagerForBrowser(browser())->DownloadUrl(
+      std::move(params), TRAFFIC_ANNOTATION_FOR_TESTS);
   observer->WaitForFinished();
   EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::COMPLETE));
 
@@ -2267,7 +2271,8 @@
       DownloadUrlParameters::CreateForWebContentsMainFrame(web_contents, url));
   params->set_file_path(target_file_full_path);
   params->set_transient(true);
-  DownloadManagerForBrowser(browser())->DownloadUrl(std::move(params));
+  DownloadManagerForBrowser(browser())->DownloadUrl(
+      std::move(params), TRAFFIC_ANNOTATION_FOR_TESTS);
   observer->WaitForFinished();
   EXPECT_EQ(1u, observer->NumDownloadsSeenInState(DownloadItem::COMPLETE));
 
@@ -3837,7 +3842,8 @@
       DownloadUrlParameters::CreateForWebContentsMainFrame(
           web_contents, url));
   params->set_callback(base::Bind(&SetHiddenDownloadCallback));
-  download_manager->DownloadUrl(std::move(params));
+  download_manager->DownloadUrl(std::move(params),
+                                TRAFFIC_ANNOTATION_FOR_TESTS);
   observer->WaitForFinished();
 
   // Verify that download shelf is not shown.
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index f133b318..ca489c0a 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -79,6 +79,7 @@
 #include "net/base/filename_util.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_util.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/gfx/image/image_skia.h"
@@ -1041,7 +1042,7 @@
 
   DownloadManager* manager = BrowserContext::GetDownloadManager(
       current_profile);
-  manager->DownloadUrl(std::move(download_params));
+  manager->DownloadUrl(std::move(download_params), NO_TRAFFIC_ANNOTATION_YET);
   RecordDownloadSource(DOWNLOAD_INITIATED_BY_EXTENSION);
   RecordApiFunctions(DOWNLOADS_FUNCTION_DOWNLOAD);
   return true;
diff --git a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
index 40c094a5..dac1971 100644
--- a/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
+++ b/chrome/browser/extensions/api/streams_private/streams_private_apitest.cc
@@ -30,6 +30,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using content::BrowserContext;
@@ -390,7 +391,8 @@
   params->set_file_path(target_path);
 
   // Start download of the URL with a path "/text_path.txt" on the test server.
-  download_manager->DownloadUrl(std::move(params));
+  download_manager->DownloadUrl(std::move(params),
+                                TRAFFIC_ANNOTATION_FOR_TESTS);
 
   // Wait for the download to start.
   download_observer->WaitForFinished();
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index 3e7ff15..c7651b6 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -63,6 +63,7 @@
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
 #include "net/base/escape.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
@@ -679,7 +680,7 @@
   params->set_callback(base::Bind(&WebstoreInstaller::OnDownloadStarted,
                                   this,
                                   extension_id));
-  download_manager->DownloadUrl(std::move(params));
+  download_manager->DownloadUrl(std::move(params), NO_TRAFFIC_ANNOTATION_YET);
 }
 
 void WebstoreInstaller::UpdateDownloadProgress() {
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 0d8316e..4168a51 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -26,7 +26,7 @@
 #include "chrome/browser/loader/predictor_resource_throttle.h"
 #include "chrome/browser/loader/safe_browsing_resource_throttle.h"
 #include "chrome/browser/mod_pagespeed/mod_pagespeed_metrics.h"
-#include "chrome/browser/net/resource_prefetch_predictor_observer.h"
+#include "chrome/browser/net/loading_predictor_observer.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/plugins/plugin_prefs.h"
 #include "chrome/browser/prerender/prerender_manager.h"
@@ -536,8 +536,8 @@
                                   resource_type, throttles);
 #endif  // !defined(DISABLE_NACL)
 
-  if (io_data->resource_prefetch_predictor_observer()) {
-    io_data->resource_prefetch_predictor_observer()->OnRequestStarted(
+  if (io_data->loading_predictor_observer()) {
+    io_data->loading_predictor_observer()->OnRequestStarted(
         request, resource_type, info->GetWebContentsGetterForRequest());
   }
 }
@@ -811,8 +811,8 @@
   }
 #endif
 
-  if (io_data->resource_prefetch_predictor_observer())
-    io_data->resource_prefetch_predictor_observer()->OnResponseStarted(
+  if (io_data->loading_predictor_observer())
+    io_data->loading_predictor_observer()->OnResponseStarted(
         request, info->GetWebContentsGetterForRequest());
 
   mod_pagespeed::RecordMetrics(info->GetResourceType(), request->url(),
@@ -837,8 +837,8 @@
   signin::FixMirrorRequestHeaderHelper(request, redirect_url, io_data,
                                        info->GetChildID(), info->GetRouteID());
 
-  if (io_data->resource_prefetch_predictor_observer()) {
-    io_data->resource_prefetch_predictor_observer()->OnRequestRedirected(
+  if (io_data->loading_predictor_observer()) {
+    io_data->loading_predictor_observer()->OnRequestRedirected(
         request, redirect_url, info->GetWebContentsGetterForRequest());
   }
 
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
index 519e2cb..b7a7ddf9 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -464,10 +464,11 @@
 
 void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() {
   RecordLinuxGlibcVersion();
-#if defined(USE_X11) && !defined(OS_CHROMEOS)
-  UMA_HISTOGRAM_ENUMERATION("Linux.WindowManager",
-                            GetLinuxWindowManager(),
+#if defined(OS_LINUX) && defined(USE_X11) && !defined(OS_CHROMEOS)
+  UMA_HISTOGRAM_ENUMERATION("Linux.WindowManager", GetLinuxWindowManager(),
                             UMA_LINUX_WINDOW_MANAGER_COUNT);
+#endif
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
   base::PostTaskWithTraits(FROM_HERE,
                            {base::MayBlock(), base::TaskPriority::BACKGROUND},
                            base::BindOnce(&RecordLinuxDistro));
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 01fb012..37a49f70 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -13,7 +13,6 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
-#include "base/debug/activity_tracker.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
@@ -423,17 +422,9 @@
 
 void ChromeMetricsServiceClient::OnLogCleanShutdown() {
 #if defined(OS_WIN)
-  base::debug::GlobalActivityTracker* global_tracker =
-      base::debug::GlobalActivityTracker::Get();
-  if (global_tracker)
-    global_tracker->MarkDeleted();
-
   base::FilePath user_data_dir;
-  if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
-    // TODO(manzagop): add a metric.
-    return;
-  }
-  browser_watcher::MarkStabilityFileForDeletion(user_data_dir);
+  if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
+    browser_watcher::MarkOwnStabilityFileDeleted(user_data_dir);
 #endif  // OS_WIN
 }
 
diff --git a/chrome/browser/net/resource_prefetch_predictor_observer.cc b/chrome/browser/net/loading_predictor_observer.cc
similarity index 76%
rename from chrome/browser/net/resource_prefetch_predictor_observer.cc
rename to chrome/browser/net/loading_predictor_observer.cc
index 4dc2b0b..8d48d01 100644
--- a/chrome/browser/net/resource_prefetch_predictor_observer.cc
+++ b/chrome/browser/net/loading_predictor_observer.cc
@@ -1,8 +1,8 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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/net/resource_prefetch_predictor_observer.h"
+#include "chrome/browser/net/loading_predictor_observer.h"
 
 #include <memory>
 #include <string>
@@ -20,6 +20,7 @@
 }
 
 using content::BrowserThread;
+using predictors::LoadingPredictor;
 using predictors::ResourcePrefetchPredictor;
 using URLRequestSummary =
     predictors::ResourcePrefetchPredictor::URLRequestSummary;
@@ -48,15 +49,13 @@
 };
 
 void ReportRequestStats(RequestStats stat) {
-  UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.RequestStats",
-                            stat,
+  UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.RequestStats", stat,
                             REQUEST_STATS_MAX);
 }
 
 void ReportMainFrameRequestStats(MainFrameRequestStats stat) {
   UMA_HISTOGRAM_ENUMERATION("ResourcePrefetchPredictor.MainFrameRequestStats",
-                            stat,
-                            MAIN_FRAME_REQUEST_STATS_MAX);
+                            stat, MAIN_FRAME_REQUEST_STATS_MAX);
 }
 
 bool TryToFillNavigationID(
@@ -79,18 +78,17 @@
 
 namespace chrome_browser_net {
 
-ResourcePrefetchPredictorObserver::ResourcePrefetchPredictorObserver(
-    ResourcePrefetchPredictor* predictor)
+LoadingPredictorObserver::LoadingPredictorObserver(LoadingPredictor* predictor)
     : predictor_(predictor->AsWeakPtr()) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
-ResourcePrefetchPredictorObserver::~ResourcePrefetchPredictorObserver() {
+LoadingPredictorObserver::~LoadingPredictorObserver() {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
         BrowserThread::CurrentlyOn(BrowserThread::IO));
 }
 
-void ResourcePrefetchPredictorObserver::OnRequestStarted(
+void LoadingPredictorObserver::OnRequestStarted(
     net::URLRequest* request,
     content::ResourceType resource_type,
     const content::ResourceRequestInfo::WebContentsGetter&
@@ -109,17 +107,16 @@
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &ResourcePrefetchPredictorObserver::OnRequestStartedOnUIThread,
-          base::Unretained(this), base::Passed(std::move(summary)),
-          web_contents_getter, request->first_party_for_cookies(),
-          request->creation_time()));
+      base::BindOnce(&LoadingPredictorObserver::OnRequestStartedOnUIThread,
+                     base::Unretained(this), base::Passed(std::move(summary)),
+                     web_contents_getter, request->first_party_for_cookies(),
+                     request->creation_time()));
 
   if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
     ReportMainFrameRequestStats(MAIN_FRAME_REQUEST_STATS_PROCESSED_REQUESTS);
 }
 
-void ResourcePrefetchPredictorObserver::OnRequestRedirected(
+void LoadingPredictorObserver::OnRequestRedirected(
     net::URLRequest* request,
     const GURL& redirect_url,
     const content::ResourceRequestInfo::WebContentsGetter&
@@ -145,11 +142,10 @@
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &ResourcePrefetchPredictorObserver::OnRequestRedirectedOnUIThread,
-          base::Unretained(this), base::Passed(std::move(summary)),
-          web_contents_getter, request->first_party_for_cookies(),
-          request->creation_time()));
+      base::BindOnce(&LoadingPredictorObserver::OnRequestRedirectedOnUIThread,
+                     base::Unretained(this), base::Passed(std::move(summary)),
+                     web_contents_getter, request->first_party_for_cookies(),
+                     request->creation_time()));
 
   if (request_info &&
       request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
@@ -157,7 +153,7 @@
   }
 }
 
-void ResourcePrefetchPredictorObserver::OnResponseStarted(
+void LoadingPredictorObserver::OnResponseStarted(
     net::URLRequest* request,
     const content::ResourceRequestInfo::WebContentsGetter&
         web_contents_getter) {
@@ -182,11 +178,10 @@
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::BindOnce(
-          &ResourcePrefetchPredictorObserver::OnResponseStartedOnUIThread,
-          base::Unretained(this), base::Passed(std::move(summary)),
-          web_contents_getter, request->first_party_for_cookies(),
-          request->creation_time()));
+      base::BindOnce(&LoadingPredictorObserver::OnResponseStartedOnUIThread,
+                     base::Unretained(this), base::Passed(std::move(summary)),
+                     web_contents_getter, request->first_party_for_cookies(),
+                     request->creation_time()));
 
   ReportRequestStats(REQUEST_STATS_TOTAL_PROCESSED_RESPONSES);
   if (request_info &&
@@ -195,7 +190,7 @@
   }
 }
 
-void ResourcePrefetchPredictorObserver::OnRequestStartedOnUIThread(
+void LoadingPredictorObserver::OnRequestStartedOnUIThread(
     std::unique_ptr<URLRequestSummary> summary,
     const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
     const GURL& main_frame_url,
@@ -205,10 +200,12 @@
                              main_frame_url, creation_time)) {
     return;
   }
-  predictor_->RecordURLRequest(*summary);
+  if (summary->resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
+    predictor_->OnMainFrameRequest(*summary);
+  predictor_->resource_prefetch_predictor()->RecordURLRequest(*summary);
 }
 
-void ResourcePrefetchPredictorObserver::OnRequestRedirectedOnUIThread(
+void LoadingPredictorObserver::OnRequestRedirectedOnUIThread(
     std::unique_ptr<URLRequestSummary> summary,
     const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
     const GURL& main_frame_url,
@@ -218,10 +215,12 @@
                              main_frame_url, creation_time)) {
     return;
   }
-  predictor_->RecordURLRedirect(*summary);
+  if (summary->resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
+    predictor_->OnMainFrameRedirect(*summary);
+  predictor_->resource_prefetch_predictor()->RecordURLRedirect(*summary);
 }
 
-void ResourcePrefetchPredictorObserver::OnResponseStartedOnUIThread(
+void LoadingPredictorObserver::OnResponseStartedOnUIThread(
     std::unique_ptr<URLRequestSummary> summary,
     const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
     const GURL& main_frame_url,
@@ -231,7 +230,9 @@
                              main_frame_url, creation_time)) {
     return;
   }
-  predictor_->RecordURLResponse(*summary);
+  if (summary->resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
+    predictor_->OnMainFrameResponse(*summary);
+  predictor_->resource_prefetch_predictor()->RecordURLResponse(*summary);
 }
 
 }  // namespace chrome_browser_net
diff --git a/chrome/browser/net/resource_prefetch_predictor_observer.h b/chrome/browser/net/loading_predictor_observer.h
similarity index 79%
rename from chrome/browser/net/resource_prefetch_predictor_observer.h
rename to chrome/browser/net/loading_predictor_observer.h
index 4801540..4753f51b 100644
--- a/chrome/browser/net/resource_prefetch_predictor_observer.h
+++ b/chrome/browser/net/loading_predictor_observer.h
@@ -1,14 +1,15 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_NET_RESOURCE_PREFETCH_PREDICTOR_OBSERVER_H_
-#define CHROME_BROWSER_NET_RESOURCE_PREFETCH_PREDICTOR_OBSERVER_H_
+#ifndef CHROME_BROWSER_NET_LOADING_PREDICTOR_OBSERVER_H_
+#define CHROME_BROWSER_NET_LOADING_PREDICTOR_OBSERVER_H_
 
 #include <memory>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/predictors/loading_predictor.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/resource_type.h"
@@ -22,17 +23,16 @@
 namespace chrome_browser_net {
 
 // Observes resource requests in the ResourceDispatcherHostDelegate and notifies
-// the ResourcePrefetchPredictor about the ones it is interested in.
+// the LoadingPredictor about the ones it is interested in.
 //  - Has an instance per profile, and is owned by the corresponding
 //    ProfileIOData.
 //  - Needs to be constructed on UI thread. Can be destroyed on UI or IO thread.
 //    As for member functions, public members are meant to be called on the IO
 //    thread and private members from the UI thread.
-class ResourcePrefetchPredictorObserver {
+class LoadingPredictorObserver {
  public:
-  explicit ResourcePrefetchPredictorObserver(
-      predictors::ResourcePrefetchPredictor* predictor);
-  ~ResourcePrefetchPredictorObserver();
+  explicit LoadingPredictorObserver(predictors::LoadingPredictor* predictor);
+  ~LoadingPredictorObserver();
 
   // Parts of the ResourceDispatcherHostDelegate that we want to observe.
   void OnRequestStarted(net::URLRequest* request,
@@ -72,11 +72,11 @@
       const base::TimeTicks& creation_time) const;
 
   // Owned by profile.
-  base::WeakPtr<predictors::ResourcePrefetchPredictor> predictor_;
+  base::WeakPtr<predictors::LoadingPredictor> predictor_;
 
-  DISALLOW_COPY_AND_ASSIGN(ResourcePrefetchPredictorObserver);
+  DISALLOW_COPY_AND_ASSIGN(LoadingPredictorObserver);
 };
 
 }  // namespace chrome_browser_net
 
-#endif  // CHROME_BROWSER_NET_RESOURCE_PREFETCH_PREDICTOR_OBSERVER_H_
+#endif  // CHROME_BROWSER_NET_LOADING_PREDICTOR_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer_unittest.cc
index 1251655d..64cbc254 100644
--- a/chrome/browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer_unittest.cc
@@ -23,7 +23,7 @@
       Profile* profile)
       : ResourcePrefetchPredictor(config, profile) {}
 
-  MOCK_METHOD1(IsUrlPrefetchable, bool(const GURL& main_frame_url));
+  MOCK_CONST_METHOD1(IsUrlPrefetchable, bool(const GURL& main_frame_url));
 
   ~MockResourcePrefetchPredictor() override {}
 };
diff --git a/chrome/browser/predictors/loading_predictor.cc b/chrome/browser/predictors/loading_predictor.cc
index d5bd264..e818418 100644
--- a/chrome/browser/predictors/loading_predictor.cc
+++ b/chrome/browser/predictors/loading_predictor.cc
@@ -5,24 +5,37 @@
 #include "chrome/browser/predictors/loading_predictor.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 
 namespace predictors {
 
+using URLRequestSummary = ResourcePrefetchPredictor::URLRequestSummary;
+
 LoadingPredictor::LoadingPredictor(const LoadingPredictorConfig& config,
-                                   Profile* profile) {
-  resource_prefetch_predictor_ =
-      base::MakeUnique<ResourcePrefetchPredictor>(config, profile);
-}
+                                   Profile* profile)
+    : config_(config),
+      profile_(profile),
+      resource_prefetch_predictor_(
+          base::MakeUnique<ResourcePrefetchPredictor>(config, profile)) {}
 
 LoadingPredictor::~LoadingPredictor() = default;
 
 void LoadingPredictor::PrepareForPageLoad(const GURL& url, HintOrigin origin) {
-  resource_prefetch_predictor_->StartPrefetching(url, origin);
+  if (active_hints_.find(url) != active_hints_.end() ||
+      !resource_prefetch_predictor_->IsUrlPrefetchable(url))
+    return;
+
+  // To report hint durations.
+  active_hints_.emplace(url, base::TimeTicks::Now());
+
+  if (config_.IsPrefetchingEnabledForOrigin(profile_, origin))
+    resource_prefetch_predictor_->StartPrefetching(url);
 }
 
 void LoadingPredictor::CancelPageLoadHint(const GURL& url) {
-  resource_prefetch_predictor_->StopPrefetching(url);
+  CancelActiveHint(active_hints_.find(url));
 }
 
 void LoadingPredictor::StartInitialization() {
@@ -38,4 +51,87 @@
   resource_prefetch_predictor_->Shutdown();
 }
 
+void LoadingPredictor::OnMainFrameRequest(const URLRequestSummary& summary) {
+  DCHECK(summary.resource_type == content::RESOURCE_TYPE_MAIN_FRAME);
+
+  const NavigationID& navigation_id = summary.navigation_id;
+  CleanupAbandonedHintsAndNavigations(navigation_id);
+  active_navigations_.emplace(navigation_id, navigation_id.main_frame_url);
+  PrepareForPageLoad(navigation_id.main_frame_url, HintOrigin::NAVIGATION);
+}
+
+void LoadingPredictor::OnMainFrameRedirect(const URLRequestSummary& summary) {
+  DCHECK(summary.resource_type == content::RESOURCE_TYPE_MAIN_FRAME);
+
+  auto it = active_navigations_.find(summary.navigation_id);
+  if (it != active_navigations_.end()) {
+    if (summary.navigation_id.main_frame_url == summary.redirect_url)
+      return;
+    NavigationID navigation_id = summary.navigation_id;
+    navigation_id.main_frame_url = summary.redirect_url;
+    active_navigations_.emplace(navigation_id, it->second);
+    active_navigations_.erase(it);
+  }
+}
+
+void LoadingPredictor::OnMainFrameResponse(const URLRequestSummary& summary) {
+  DCHECK(summary.resource_type == content::RESOURCE_TYPE_MAIN_FRAME);
+
+  const NavigationID& navigation_id = summary.navigation_id;
+  auto it = active_navigations_.find(navigation_id);
+  if (it != active_navigations_.end()) {
+    const GURL& initial_url = it->second;
+    CancelPageLoadHint(initial_url);
+    active_navigations_.erase(it);
+  } else {
+    CancelPageLoadHint(navigation_id.main_frame_url);
+  }
+}
+
+std::map<GURL, base::TimeTicks>::iterator LoadingPredictor::CancelActiveHint(
+    std::map<GURL, base::TimeTicks>::iterator hint_it) {
+  if (hint_it == active_hints_.end())
+    return hint_it;
+
+  const GURL& url = hint_it->first;
+  resource_prefetch_predictor_->StopPrefetching(url);
+
+  UMA_HISTOGRAM_TIMES(
+      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram,
+      base::TimeTicks::Now() - hint_it->second);
+  return active_hints_.erase(hint_it);
+}
+
+void LoadingPredictor::CleanupAbandonedHintsAndNavigations(
+    const NavigationID& navigation_id) {
+  base::TimeTicks time_now = base::TimeTicks::Now();
+  const base::TimeDelta max_navigation_age =
+      base::TimeDelta::FromSeconds(config_.max_navigation_lifetime_seconds);
+
+  // Hints.
+  for (auto it = active_hints_.begin(); it != active_hints_.end();) {
+    base::TimeDelta prefetch_age = time_now - it->second;
+    if (prefetch_age > max_navigation_age) {
+      // Will go to the last bucket in the duration reported in
+      // CancelActiveHint() meaning that the duration was unlimited.
+      it = CancelActiveHint(it);
+    } else {
+      ++it;
+    }
+  }
+
+  // Navigations.
+  for (auto it = active_navigations_.begin();
+       it != active_navigations_.end();) {
+    if ((it->first.tab_id == navigation_id.tab_id) ||
+        (time_now - it->first.creation_time > max_navigation_age)) {
+      const GURL& initial_url = it->second;
+      CancelActiveHint(active_hints_.find(initial_url));
+      it = active_navigations_.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
 }  // namespace predictors
diff --git a/chrome/browser/predictors/loading_predictor.h b/chrome/browser/predictors/loading_predictor.h
index 9bcdd81..4588febb 100644
--- a/chrome/browser/predictors/loading_predictor.h
+++ b/chrome/browser/predictors/loading_predictor.h
@@ -5,12 +5,17 @@
 #ifndef CHROME_BROWSER_PREDICTORS_LOADING_PREDICTOR_H_
 #define CHROME_BROWSER_PREDICTORS_LOADING_PREDICTOR_H_
 
+#include <map>
 #include <memory>
+#include <utility>
 
+#include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "url/gurl.h"
 
 class Profile;
 
@@ -22,6 +27,9 @@
 // From a high-level request (GURL and motivation) and a database of historical
 // data, initiates predictive actions to speed up page loads.
 //
+// Also listens to main frame requests/redirects/responses to initiate and
+// cancel page load hints.
+//
 // See ResourcePrefetchPredictor for a description of the resource prefetch
 // predictor.
 //
@@ -48,8 +56,45 @@
   // KeyedService:
   void Shutdown() override;
 
+  void OnMainFrameRequest(
+      const ResourcePrefetchPredictor::URLRequestSummary& summary);
+  void OnMainFrameRedirect(
+      const ResourcePrefetchPredictor::URLRequestSummary& summary);
+  void OnMainFrameResponse(
+      const ResourcePrefetchPredictor::URLRequestSummary& summary);
+
  private:
+  // Cancels an active hint, from its iterator inside |active_hints_|. If the
+  // iterator is .end(), does nothing. Returns the iterator after deletion of
+  // the entry.
+  std::map<GURL, base::TimeTicks>::iterator CancelActiveHint(
+      std::map<GURL, base::TimeTicks>::iterator hint_it);
+  void CleanupAbandonedHintsAndNavigations(const NavigationID& navigation_id);
+
+  // For testing.
+  void set_mock_resource_prefetch_predictor(
+      std::unique_ptr<ResourcePrefetchPredictor> predictor) {
+    resource_prefetch_predictor_ = std::move(predictor);
+  }
+
+  LoadingPredictorConfig config_;
+  Profile* profile_;
   std::unique_ptr<ResourcePrefetchPredictor> resource_prefetch_predictor_;
+  std::map<GURL, base::TimeTicks> active_hints_;
+  // Initial URL.
+  std::map<NavigationID, GURL> active_navigations_;
+
+  friend class LoadingPredictorTest;
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestMainFrameResponseCancelsHint);
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestMainFrameRequestCancelsStaleNavigations);
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestMainFrameResponseClearsNavigations);
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestMainFrameRequestDoesntCancelExternalHint);
+  FRIEND_TEST_ALL_PREFIXES(LoadingPredictorTest,
+                           TestDontTrackNonPrefetchableUrls);
 
   DISALLOW_COPY_AND_ASSIGN(LoadingPredictor);
 };
diff --git a/chrome/browser/predictors/loading_predictor_unittest.cc b/chrome/browser/predictors/loading_predictor_unittest.cc
new file mode 100644
index 0000000..f9faee40
--- /dev/null
+++ b/chrome/browser/predictors/loading_predictor_unittest.cc
@@ -0,0 +1,219 @@
+// 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/predictors/loading_predictor.h"
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
+#include "chrome/browser/predictors/resource_prefetch_predictor_test_util.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace predictors {
+
+namespace {
+// First two are prefetchable, last one is not (see SetUp()).
+const char kUrl[] = "http://www.google.com/cats";
+const char kUrl2[] = "http://www.google.com/dogs";
+const char kUrl3[] = "https://unknown.website/catsanddogs";
+}
+
+// Does nothing, controls which URLs are prefetchable.
+class MockResourcePrefetcherPredictor : public ResourcePrefetchPredictor {
+ public:
+  MockResourcePrefetcherPredictor(const LoadingPredictorConfig& config,
+                                  Profile* profile)
+      : ResourcePrefetchPredictor(config, profile) {}
+
+  bool IsUrlPrefetchable(const GURL& main_frame_url) const override {
+    return prefetchable_urls_.find(main_frame_url) != prefetchable_urls_.end();
+  }
+
+  void AddPrefetchableUrl(const GURL& url) { prefetchable_urls_.insert(url); }
+
+  MOCK_METHOD0(StartInitialization, void());
+  MOCK_METHOD0(Shutdown, void());
+  MOCK_METHOD1(StartPrefetching, void(const GURL&));
+  MOCK_METHOD1(StopPrefeching, void(const GURL&));
+
+ private:
+  std::set<GURL> prefetchable_urls_;
+};
+
+class LoadingPredictorTest : public testing::Test {
+ public:
+  LoadingPredictorTest();
+  ~LoadingPredictorTest() override;
+  void SetUp() override;
+  void TearDown() override;
+
+ protected:
+  content::TestBrowserThreadBundle thread_bundle_;
+  std::unique_ptr<LoadingPredictor> predictor_;
+  std::unique_ptr<TestingProfile> profile_;
+};
+
+LoadingPredictorTest::LoadingPredictorTest()
+    : profile_(base::MakeUnique<TestingProfile>()) {}
+
+LoadingPredictorTest::~LoadingPredictorTest() {
+  profile_ = nullptr;
+  base::RunLoop().RunUntilIdle();
+}
+
+void LoadingPredictorTest::SetUp() {
+  LoadingPredictorConfig config;
+  PopulateTestConfig(&config);
+  predictor_ = base::MakeUnique<LoadingPredictor>(config, profile_.get());
+  auto mock =
+      base::MakeUnique<MockResourcePrefetcherPredictor>(config, profile_.get());
+  mock->AddPrefetchableUrl(GURL(kUrl));
+  mock->AddPrefetchableUrl(GURL(kUrl2));
+  predictor_->set_mock_resource_prefetch_predictor(std::move(mock));
+  predictor_->StartInitialization();
+  base::RunLoop().RunUntilIdle();
+}
+
+void LoadingPredictorTest::TearDown() {
+  predictor_ = nullptr;
+  profile_->DestroyHistoryService();
+}
+
+TEST_F(LoadingPredictorTest, TestPrefetchingDurationHistogram) {
+  base::HistogramTester histogram_tester;
+
+  const GURL url = GURL(kUrl);
+  const GURL url2 = GURL(kUrl2);
+  const GURL url3 = GURL(kUrl3);
+  predictor_->PrepareForPageLoad(url, HintOrigin::EXTERNAL);
+  predictor_->CancelPageLoadHint(url);
+  histogram_tester.ExpectTotalCount(
+      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, 1);
+
+  // Mismatched start / end.
+  predictor_->PrepareForPageLoad(url, HintOrigin::EXTERNAL);
+  predictor_->CancelPageLoadHint(url2);
+  // No increment.
+  histogram_tester.ExpectTotalCount(
+      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, 1);
+
+  // Can track a navigation (url2) while one is still in progress (url).
+  predictor_->PrepareForPageLoad(url2, HintOrigin::EXTERNAL);
+  predictor_->CancelPageLoadHint(url2);
+  histogram_tester.ExpectTotalCount(
+      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, 2);
+
+  // Do not track non-prefetchable URLs.
+  predictor_->PrepareForPageLoad(url3, HintOrigin::EXTERNAL);
+  predictor_->CancelPageLoadHint(url3);
+  // No increment.
+  histogram_tester.ExpectTotalCount(
+      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, 2);
+}
+
+TEST_F(LoadingPredictorTest, TestMainFrameResponseCancelsHint) {
+  const GURL url = GURL(kUrl);
+  predictor_->PrepareForPageLoad(url, HintOrigin::EXTERNAL);
+  EXPECT_EQ(1UL, predictor_->active_hints_.size());
+
+  auto summary = CreateURLRequestSummary(12, url.spec());
+  predictor_->OnMainFrameResponse(summary);
+  EXPECT_TRUE(predictor_->active_hints_.empty());
+}
+
+TEST_F(LoadingPredictorTest, TestMainFrameRequestCancelsStaleNavigations) {
+  const std::string url = kUrl;
+  const std::string url2 = kUrl2;
+  const int tab_id = 12;
+  const auto& active_navigations = predictor_->active_navigations_;
+  const auto& active_hints = predictor_->active_hints_;
+
+  auto summary = CreateURLRequestSummary(tab_id, url);
+  auto navigation_id = CreateNavigationID(tab_id, url);
+
+  predictor_->OnMainFrameRequest(summary);
+  EXPECT_NE(active_navigations.find(navigation_id), active_navigations.end());
+  EXPECT_NE(active_hints.find(GURL(url)), active_hints.end());
+
+  summary = CreateURLRequestSummary(tab_id, url2);
+  predictor_->OnMainFrameRequest(summary);
+  EXPECT_EQ(active_navigations.find(navigation_id), active_navigations.end());
+  EXPECT_EQ(active_hints.find(GURL(url)), active_hints.end());
+
+  auto navigation_id2 = CreateNavigationID(tab_id, url2);
+  EXPECT_NE(active_navigations.find(navigation_id2), active_navigations.end());
+}
+
+TEST_F(LoadingPredictorTest, TestMainFrameResponseClearsNavigations) {
+  const std::string url = kUrl;
+  const std::string redirected = kUrl2;
+  const int tab_id = 12;
+  const auto& active_navigations = predictor_->active_navigations_;
+  const auto& active_hints = predictor_->active_hints_;
+
+  auto summary = CreateURLRequestSummary(tab_id, url);
+  auto navigation_id = CreateNavigationID(tab_id, url);
+
+  predictor_->OnMainFrameRequest(summary);
+  EXPECT_NE(active_navigations.find(navigation_id), active_navigations.end());
+  EXPECT_FALSE(active_hints.empty());
+
+  predictor_->OnMainFrameResponse(summary);
+  EXPECT_TRUE(active_navigations.empty());
+  EXPECT_TRUE(active_hints.empty());
+
+  // With redirects.
+  predictor_->OnMainFrameRequest(summary);
+  EXPECT_NE(active_navigations.find(navigation_id), active_navigations.end());
+  EXPECT_FALSE(active_hints.empty());
+
+  summary.redirect_url = GURL(redirected);
+  predictor_->OnMainFrameRedirect(summary);
+  EXPECT_FALSE(active_navigations.empty());
+  EXPECT_FALSE(active_hints.empty());
+
+  summary.navigation_id.main_frame_url = GURL(redirected);
+  predictor_->OnMainFrameResponse(summary);
+  EXPECT_TRUE(active_navigations.empty());
+  EXPECT_TRUE(active_hints.empty());
+}
+
+TEST_F(LoadingPredictorTest, TestMainFrameRequestDoesntCancelExternalHint) {
+  const GURL url = GURL(kUrl);
+  const int tab_id = 12;
+  const auto& active_navigations = predictor_->active_navigations_;
+  auto& active_hints = predictor_->active_hints_;
+
+  predictor_->PrepareForPageLoad(url, HintOrigin::EXTERNAL);
+  auto it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+  EXPECT_TRUE(active_navigations.empty());
+
+  // To check that the hint is not replaced, set the start time in the past,
+  // and check later that it didn't change.
+  base::TimeTicks start_time = it->second - base::TimeDelta::FromSeconds(10);
+  it->second = start_time;
+
+  auto summary = CreateURLRequestSummary(tab_id, url.spec());
+  predictor_->OnMainFrameRequest(summary);
+  EXPECT_NE(active_navigations.find(summary.navigation_id),
+            active_navigations.end());
+  it = active_hints.find(url);
+  EXPECT_NE(it, active_hints.end());
+  EXPECT_EQ(start_time, it->second);
+}
+
+TEST_F(LoadingPredictorTest, TestDontTrackNonPrefetchableUrls) {
+  const GURL url3 = GURL(kUrl3);
+  predictor_->PrepareForPageLoad(url3, HintOrigin::EXTERNAL);
+  EXPECT_TRUE(predictor_->active_hints_.empty());
+}
+
+}  // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index ecb50a4..11f0b234 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -628,9 +628,7 @@
   if (initialization_state_ != INITIALIZED)
     return;
 
-  if (response.resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
-    OnMainFrameResponse(response);
-  else
+  if (response.resource_type != content::RESOURCE_TYPE_MAIN_FRAME)
     OnSubresourceResponse(response);
 }
 
@@ -678,56 +676,6 @@
     nav_it->second->first_contentful_paint = first_contentful_paint;
 }
 
-void ResourcePrefetchPredictor::StartPrefetching(const GURL& url,
-                                                 HintOrigin origin) {
-  TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url",
-               url.spec());
-  // Save prefetch start time to report prefetching duration.
-  if (inflight_prefetches_.find(url) == inflight_prefetches_.end() &&
-      IsUrlPrefetchable(url)) {
-    inflight_prefetches_.insert(std::make_pair(url, base::TimeTicks::Now()));
-  }
-
-  if (!prefetch_manager_.get())  // Prefetching not enabled.
-    return;
-  if (!config_.IsPrefetchingEnabledForOrigin(profile_, origin))
-    return;
-
-  ResourcePrefetchPredictor::Prediction prediction;
-  if (!GetPrefetchData(url, &prediction))
-    return;
-
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&ResourcePrefetcherManager::MaybeAddPrefetch,
-                     prefetch_manager_, url, prediction.subresource_urls));
-
-  if (observer_)
-    observer_->OnPrefetchingStarted(url);
-}
-
-void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) {
-  TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url",
-               url.spec());
-  auto it = inflight_prefetches_.find(url);
-  if (it != inflight_prefetches_.end()) {
-    UMA_HISTOGRAM_TIMES(
-        internal::kResourcePrefetchPredictorPrefetchingDurationHistogram,
-        base::TimeTicks::Now() - it->second);
-    inflight_prefetches_.erase(it);
-  }
-  if (!prefetch_manager_.get())  // Not enabled.
-    return;
-
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&ResourcePrefetcherManager::MaybeRemovePrefetch,
-                     prefetch_manager_, url));
-
-  if (observer_)
-    observer_->OnPrefetchingStopped(url);
-}
-
 void ResourcePrefetchPredictor::OnPrefetchingFinished(
     const GURL& main_frame_url,
     std::unique_ptr<ResourcePrefetcher::PrefetcherStats> stats) {
@@ -737,7 +685,8 @@
   prefetcher_stats_.insert(std::make_pair(main_frame_url, std::move(stats)));
 }
 
-bool ResourcePrefetchPredictor::IsUrlPrefetchable(const GURL& main_frame_url) {
+bool ResourcePrefetchPredictor::IsUrlPrefetchable(
+    const GURL& main_frame_url) const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (initialization_state_ != INITIALIZED)
     return false;
@@ -771,30 +720,13 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(INITIALIZED, initialization_state_);
 
-  const GURL& main_frame_url = request.navigation_id.main_frame_url;
-  StartPrefetching(main_frame_url, HintOrigin::NAVIGATION);
-
   CleanupAbandonedNavigations(request.navigation_id);
 
   // New empty navigation entry.
-  inflight_navigations_.insert(
-      std::make_pair(request.navigation_id,
-                     base::MakeUnique<PageRequestSummary>(main_frame_url)));
-}
-
-void ResourcePrefetchPredictor::OnMainFrameResponse(
-    const URLRequestSummary& response) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_EQ(INITIALIZED, initialization_state_);
-
-  NavigationMap::iterator nav_it =
-      inflight_navigations_.find(response.navigation_id);
-  if (nav_it != inflight_navigations_.end()) {
-    // To match an URL in StartPrefetching().
-    StopPrefetching(nav_it->second->initial_url);
-  } else {
-    StopPrefetching(response.navigation_id.main_frame_url);
-  }
+  const GURL& main_frame_url = request.navigation_id.main_frame_url;
+  inflight_navigations_.emplace(
+      request.navigation_id,
+      base::MakeUnique<PageRequestSummary>(main_frame_url));
 }
 
 void ResourcePrefetchPredictor::OnMainFrameRedirect(
@@ -825,8 +757,7 @@
   NavigationID navigation_id(response.navigation_id);
   navigation_id.main_frame_url = response.redirect_url;
   summary->main_frame_url = response.redirect_url;
-  inflight_navigations_.insert(
-      std::make_pair(navigation_id, std::move(summary)));
+  inflight_navigations_.emplace(navigation_id, std::move(summary));
 }
 
 void ResourcePrefetchPredictor::OnSubresourceResponse(
@@ -1079,20 +1010,6 @@
     }
   }
 
-  for (auto it = inflight_prefetches_.begin();
-       it != inflight_prefetches_.end();) {
-    base::TimeDelta prefetch_age = time_now - it->second;
-    if (prefetch_age > max_navigation_age) {
-      // It goes to the last bucket meaning that the duration was unlimited.
-      UMA_HISTOGRAM_TIMES(
-          internal::kResourcePrefetchPredictorPrefetchingDurationHistogram,
-          prefetch_age);
-      it = inflight_prefetches_.erase(it);
-    } else {
-      ++it;
-    }
-  }
-
   // Remove old prefetches that haven't been claimed.
   for (auto stats_it = prefetcher_stats_.begin();
        stats_it != prefetcher_stats_.end();) {
@@ -1599,6 +1516,40 @@
   }
 }
 
+void ResourcePrefetchPredictor::StartPrefetching(const GURL& url) {
+  TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StartPrefetching", "url",
+               url.spec());
+  if (!prefetch_manager_.get())  // Not enabled.
+    return;
+
+  ResourcePrefetchPredictor::Prediction prediction;
+  bool has_data = GetPrefetchData(url, &prediction);
+  DCHECK(has_data);
+
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&ResourcePrefetcherManager::MaybeAddPrefetch,
+                     prefetch_manager_, url, prediction.subresource_urls));
+
+  if (observer_)
+    observer_->OnPrefetchingStarted(url);
+}
+
+void ResourcePrefetchPredictor::StopPrefetching(const GURL& url) {
+  TRACE_EVENT1("browser", "ResourcePrefetchPredictor::StopPrefetching", "url",
+               url.spec());
+  if (!prefetch_manager_.get())  // Not enabled.
+    return;
+
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&ResourcePrefetcherManager::MaybeRemovePrefetch,
+                     prefetch_manager_, url));
+
+  if (observer_)
+    observer_->OnPrefetchingStopped(url);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TestObserver.
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index f01b150..e8a88fb 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -24,6 +24,7 @@
 #include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 #include "chrome/browser/predictors/resource_prefetcher.h"
+#include "chrome/browser/predictors/resource_prefetcher_manager.h"
 #include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/history/core/browser/history_types.h"
@@ -214,9 +215,9 @@
   ~ResourcePrefetchPredictor() override;
 
   // Starts initialization by posting a task to the DB thread to read the
-  // predictor database.
-  void StartInitialization();
-  void Shutdown();
+  // predictor database. Virtual for testing.
+  virtual void StartInitialization();
+  virtual void Shutdown();
 
   // Thread safe.
   static bool ShouldRecordRequest(net::URLRequest* request,
@@ -258,7 +259,7 @@
       std::unique_ptr<ResourcePrefetcher::PrefetcherStats> stats);
 
   // Returns true if prefetching data exists for the |main_frame_url|.
-  virtual bool IsUrlPrefetchable(const GURL& main_frame_url);
+  virtual bool IsUrlPrefetchable(const GURL& main_frame_url) const;
 
   // Returns true iff |resource| has sufficient confidence level and required
   // number of hits.
@@ -274,9 +275,9 @@
   void SetObserverForTesting(TestObserver* observer);
 
  private:
-  // Starts prefetching if it is enabled for |origin| and prefetching data
-  // exists for the |main_frame_url| either at the URL or at the host level.
-  void StartPrefetching(const GURL& main_frame_url, HintOrigin origin);
+  // Starts prefetching if it is enabled and prefetching data exists for the
+  // |main_frame_url| either at the URL or at the host level.
+  void StartPrefetching(const GURL& main_frame_url);
 
   // Stops prefetching that may be in progress corresponding to
   // |main_frame_url|.
@@ -360,7 +361,6 @@
   // Functions called on different network events pertaining to the loading of
   // main frame resource or sub resources.
   void OnMainFrameRequest(const URLRequestSummary& request);
-  void OnMainFrameResponse(const URLRequestSummary& response);
   void OnMainFrameRedirect(const URLRequestSummary& response);
   void OnSubresourceResponse(const URLRequestSummary& response);
   void OnSubresourceRedirect(const URLRequestSummary& response);
@@ -405,7 +405,7 @@
   // database has been read.
   void OnHistoryAndCacheLoaded();
 
-  // Cleanup inflight_navigations_, inflight_prefetches_, and prefetcher_stats_.
+  // Cleanup inflight_navigations_, and prefetcher_stats_.
   void CleanupAbandonedNavigations(const NavigationID& navigation_id);
 
   // Deletes all URLs from the predictor database, the caches and removes all
@@ -463,6 +463,12 @@
     tables_ = tables;
   }
 
+  // For testing.
+  void set_mock_resource_prefetcher_manager(
+      scoped_refptr<ResourcePrefetcherManager> prefetch_manager) {
+    prefetch_manager_ = prefetch_manager;
+  }
+
   Profile* const profile_;
   TestObserver* observer_;
   const LoadingPredictorConfig config_;
@@ -478,7 +484,6 @@
   std::unique_ptr<ManifestDataMap> manifest_data_;
   std::unique_ptr<OriginDataMap> origin_data_;
 
-  std::map<GURL, base::TimeTicks> inflight_prefetches_;
   NavigationMap inflight_navigations_;
 
   std::map<GURL, std::unique_ptr<ResourcePrefetcher::PrefetcherStats>>
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
index 98af40f..a8a3762 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
@@ -176,6 +176,22 @@
   return summary;
 }
 
+void PopulateTestConfig(LoadingPredictorConfig* config, bool small_db) {
+  if (small_db) {
+    config->max_urls_to_track = 3;
+    config->max_hosts_to_track = 2;
+    config->min_url_visit_count = 2;
+    config->max_resources_per_entry = 4;
+    config->max_consecutive_misses = 2;
+    config->max_redirect_consecutive_misses = 2;
+    config->min_resource_confidence_to_trigger_prefetch = 0.5;
+  }
+  config->is_url_learning_enabled = true;
+  config->is_manifests_enabled = true;
+  config->is_origin_learning_enabled = true;
+  config->mode = LoadingPredictorConfig::LEARNING;
+}
+
 std::ostream& operator<<(std::ostream& os, const PrefetchData& data) {
   os << "[" << data.primary_key() << "," << data.last_visit_time() << "]"
      << std::endl;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
index e66fedd7..d11f783 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
@@ -77,6 +77,8 @@
     bool has_validators = false,
     bool always_revalidate = false);
 
+void PopulateTestConfig(LoadingPredictorConfig* config, bool small_db = true);
+
 // For printing failures nicely.
 std::ostream& operator<<(std::ostream& stream, const PrefetchData& data);
 std::ostream& operator<<(std::ostream& stream, const ResourceData& resource);
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 00383da..e67236a7 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -14,8 +14,10 @@
 #include "base/test/histogram_tester.h"
 #include "base/time/time.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/predictors/loading_predictor.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor_test_util.h"
+#include "chrome/browser/predictors/resource_prefetcher_manager.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/history_types.h"
@@ -259,7 +261,7 @@
   }
 
   void InitializePredictor() {
-    predictor_->StartInitialization();
+    loading_predictor_->StartInitialization();
     base::RunLoop loop;
     loop.RunUntilIdle();  // Runs the DB lookup.
     profile_->BlockUntilHistoryProcessesPendingRequests();
@@ -267,20 +269,10 @@
 
   void ResetPredictor(bool small_db = true) {
     LoadingPredictorConfig config;
-    if (small_db) {
-      config.max_urls_to_track = 3;
-      config.max_hosts_to_track = 2;
-      config.max_resources_per_entry = 4;
-      config.max_consecutive_misses = 2;
-      config.max_redirect_consecutive_misses = 2;
-      config.min_resource_confidence_to_trigger_prefetch = 0.5;
-    }
-    config.is_url_learning_enabled = true;
-    config.is_manifests_enabled = true;
-    config.is_origin_learning_enabled = true;
-
-    config.mode |= LoadingPredictorConfig::LEARNING;
-    predictor_.reset(new ResourcePrefetchPredictor(config, profile_.get()));
+    PopulateTestConfig(&config, small_db);
+    loading_predictor_ =
+        base::MakeUnique<LoadingPredictor>(config, profile_.get());
+    predictor_ = loading_predictor_->resource_prefetch_predictor();
     predictor_->set_mock_tables(mock_tables_);
   }
 
@@ -296,7 +288,8 @@
   std::unique_ptr<TestingProfile> profile_;
   net::TestURLRequestContext url_request_context_;
 
-  std::unique_ptr<ResourcePrefetchPredictor> predictor_;
+  std::unique_ptr<LoadingPredictor> loading_predictor_;
+  ResourcePrefetchPredictor* predictor_;
   scoped_refptr<StrictMock<MockResourcePrefetchPredictorTables>> mock_tables_;
 
   PrefetchDataMap test_url_data_;
@@ -355,7 +348,8 @@
             mock_tables_->manifest_table_.data_);
   EXPECT_EQ(*predictor_->origin_data_->data_cache_,
             mock_tables_->origin_table_.data_);
-  predictor_.reset(NULL);
+  loading_predictor_ = nullptr;
+  predictor_ = nullptr;
   profile_->DestroyHistoryService();
 }
 
@@ -624,8 +618,7 @@
       content::RESOURCE_TYPE_SCRIPT, net::MEDIUM, "text/javascript", false);
   predictor_->RecordURLResponse(resource3);
 
-  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(
-      predictor_.get());
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
   EXPECT_CALL(
       mock_observer,
       OnNavigationLearned(kVisitCount,
@@ -724,8 +717,7 @@
 
   predictor_->RecordURLResponse(redirected);
 
-  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(
-      predictor_.get());
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
   EXPECT_CALL(mock_observer,
               OnNavigationLearned(
                   kVisitCount, CreatePageRequestSummary("http://www.google.com",
@@ -839,8 +831,7 @@
   no_store.is_no_store = true;
   predictor_->RecordURLResponse(no_store);
 
-  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(
-      predictor_.get());
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
   EXPECT_CALL(mock_observer,
               OnNavigationLearned(
                   kVisitCount, CreatePageRequestSummary("http://www.google.com",
@@ -942,8 +933,7 @@
       content::RESOURCE_TYPE_IMAGE, net::MEDIUM, "image/png", false);
   predictor_->RecordURLResponse(resource2);
 
-  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(
-      predictor_.get());
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
   EXPECT_CALL(mock_observer,
               OnNavigationLearned(
                   kVisitCount, CreatePageRequestSummary(
@@ -1013,8 +1003,7 @@
   predictor_->RecordURLRedirect(fb3);
   NavigationID fb_end = CreateNavigationID(1, "https://facebook.com/google");
 
-  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(
-      predictor_.get());
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
   EXPECT_CALL(
       mock_observer,
       OnNavigationLearned(kVisitCount, CreatePageRequestSummary(
@@ -1064,8 +1053,7 @@
   predictor_->RecordURLRedirect(fb3);
   NavigationID fb_end = CreateNavigationID(1, "https://facebook.com/google");
 
-  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(
-      predictor_.get());
+  StrictMock<MockResourcePrefetchPredictorObserver> mock_observer(predictor_);
   EXPECT_CALL(
       mock_observer,
       OnNavigationLearned(kVisitCount, CreatePageRequestSummary(
@@ -2069,28 +2057,6 @@
       ResourcePrefetchPredictor::RedirectStatus::REDIRECT_CORRECTLY_PREDICTED);
 }
 
-TEST_F(ResourcePrefetchPredictorTest, TestPrefetchingDurationHistogram) {
-  // Prefetching duration for an url without resources in the database
-  // shouldn't be recorded.
-  const std::string main_frame_url = "http://google.com/?query=cats";
-  predictor_->StartPrefetching(GURL(main_frame_url), HintOrigin::EXTERNAL);
-  predictor_->StopPrefetching(GURL(main_frame_url));
-  histogram_tester_->ExpectTotalCount(
-      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, 0);
-
-  // Fill the database to record a duration.
-  PrefetchData google = CreatePrefetchData("google.com", 1);
-  InitializeResourceData(
-      google.add_resources(), "https://cdn.google.com/script.js",
-      content::RESOURCE_TYPE_SCRIPT, 10, 0, 1, 2.1, net::MEDIUM, false, false);
-  predictor_->host_resource_data_->UpdateData(google.primary_key(), google);
-
-  predictor_->StartPrefetching(GURL(main_frame_url), HintOrigin::EXTERNAL);
-  predictor_->StopPrefetching(GURL(main_frame_url));
-  histogram_tester_->ExpectTotalCount(
-      internal::kResourcePrefetchPredictorPrefetchingDurationHistogram, 1);
-}
-
 TEST_F(ResourcePrefetchPredictorTest, TestRecordFirstContentfulPaint) {
   auto res1_time = base::TimeTicks::FromInternalValue(1);
   auto res2_time = base::TimeTicks::FromInternalValue(2);
diff --git a/chrome/browser/predictors/resource_prefetcher_manager.h b/chrome/browser/predictors/resource_prefetcher_manager.h
index 84a8ec52..52fb50273 100644
--- a/chrome/browser/predictors/resource_prefetcher_manager.h
+++ b/chrome/browser/predictors/resource_prefetcher_manager.h
@@ -63,7 +63,6 @@
  private:
   friend class base::RefCountedThreadSafe<ResourcePrefetcherManager>;
   friend class MockResourcePrefetcherManager;
-
   ~ResourcePrefetcherManager() override;
 
   ResourcePrefetchPredictor* predictor_;
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index fd34c47d..644fd76b 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -38,8 +38,8 @@
 #include "chrome/browser/net/chrome_http_user_agent_settings.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
 #include "chrome/browser/net/chrome_url_request_context_getter.h"
+#include "chrome/browser/net/loading_predictor_observer.h"
 #include "chrome/browser/net/proxy_service_factory.h"
-#include "chrome/browser/net/resource_prefetch_predictor_observer.h"
 #include "chrome/browser/policy/cloud/policy_header_service_factory.h"
 #include "chrome/browser/policy/policy_helpers.h"
 #include "chrome/browser/predictors/loading_predictor.h"
@@ -391,9 +391,9 @@
 
   if (auto* loading_predictor =
           predictors::LoadingPredictorFactory::GetForProfile(profile)) {
-    resource_prefetch_predictor_observer_.reset(
-        new chrome_browser_net::ResourcePrefetchPredictorObserver(
-            loading_predictor->resource_prefetch_predictor()));
+    loading_predictor_observer_ =
+        base::MakeUnique<chrome_browser_net::LoadingPredictorObserver>(
+            loading_predictor);
   }
 
   ProtocolHandlerRegistry* protocol_handler_registry =
@@ -1100,9 +1100,9 @@
   resource_context_->host_resolver_ = io_thread_globals->host_resolver.get();
   resource_context_->request_context_ = main_request_context_.get();
 
-  if (profile_params_->resource_prefetch_predictor_observer_) {
-    resource_prefetch_predictor_observer_.reset(
-        profile_params_->resource_prefetch_predictor_observer_.release());
+  if (profile_params_->loading_predictor_observer_) {
+    loading_predictor_observer_ =
+        std::move(profile_params_->loading_predictor_observer_);
   }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 4b14494..895fa55 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -51,7 +51,7 @@
 }
 
 namespace chrome_browser_net {
-class ResourcePrefetchPredictorObserver;
+class LoadingPredictorObserver;
 }
 
 namespace certificate_transparency {
@@ -204,9 +204,9 @@
     return &incognito_availibility_pref_;
   }
 
-  chrome_browser_net::ResourcePrefetchPredictorObserver*
-      resource_prefetch_predictor_observer() const {
-    return resource_prefetch_predictor_observer_.get();
+  chrome_browser_net::LoadingPredictorObserver* loading_predictor_observer()
+      const {
+    return loading_predictor_observer_.get();
   }
 
   policy::PolicyHeaderIOHelper* policy_header_helper() const {
@@ -313,8 +313,8 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
     scoped_refptr<extensions::InfoMap> extension_info_map;
 #endif
-    std::unique_ptr<chrome_browser_net::ResourcePrefetchPredictorObserver>
-        resource_prefetch_predictor_observer_;
+    std::unique_ptr<chrome_browser_net::LoadingPredictorObserver>
+        loading_predictor_observer_;
 
     // This pointer exists only as a means of conveying a url job factory
     // pointer from the protocol handler registry on the UI thread to the
@@ -600,8 +600,8 @@
 
   mutable scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
 
-  mutable std::unique_ptr<chrome_browser_net::ResourcePrefetchPredictorObserver>
-      resource_prefetch_predictor_observer_;
+  mutable std::unique_ptr<chrome_browser_net::LoadingPredictorObserver>
+      loading_predictor_observer_;
 
   mutable std::unique_ptr<ChromeHttpUserAgentSettings>
       chrome_http_user_agent_settings_;
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 2d32b98..fa436c0 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -108,6 +108,7 @@
 #include "content/public/common/url_utils.h"
 #include "extensions/features/features.h"
 #include "net/base/escape.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ppapi/features/features.h"
 #include "printing/features/features.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -2221,8 +2222,8 @@
   dl_params->set_suggested_name(params_.suggested_filename);
   dl_params->set_prompt(true);
 
-  BrowserContext::GetDownloadManager(browser_context_)->DownloadUrl(
-      std::move(dl_params));
+  BrowserContext::GetDownloadManager(browser_context_)
+      ->DownloadUrl(std::move(dl_params), NO_TRAFFIC_ANNOTATION_YET);
 }
 
 void RenderViewContextMenu::ExecSaveAs() {
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.html b/chrome/browser/resources/chromeos/login/oobe_welcome.html
index 34d39e4e..275db8a 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.html
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/cr_elements/network/cr_network_icon.html">
 <link rel="import" href="chrome://resources/cr_elements/network/cr_network_select.html">
 <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
@@ -89,9 +90,9 @@
         on-accessibility-button-clicked="onWelcomeAccessibilityButtonClicked_"
         on-timezone-button-clicked="onWelcomeTimezoneButtonClicked_"
         on-next-button-clicked="onWelcomeNextButtonClicked_"
-        timezone-button-visible="[[isTimezoneButtonVisible_(highlightStrength)]]"
-        debugging-link-visible="[[debuggingLinkVisible]]"
-        >
+        timezone-button-visible=
+            "[[isTimezoneButtonVisible_(highlightStrength)]]"
+        debugging-link-visible="[[debuggingLinkVisible]]">
     </oobe-welcome-dialog>
     <oobe-dialog id="languageScreen" role="dialog" hidden has-buttons
         i18n-values="aria-label:languageSectionTitle">
@@ -99,15 +100,16 @@
           icon1x="oobe-welcome-32:language" icon2x="oobe-welcome-64:language">
       </hd-iron-icon>
       <div class="header">
-        <h1 class="title" i18n-content="languageSectionTitle"></h1>
+        <h1 class="title">[[i18nDynamic(locale, 'languageSectionTitle')]]</h1>
       </div>
       <div class="footer layout vertical">
         <template is="dom-if" if="[[enabled]]">
           <div id="languageDropdownContainer"
               class="flex layout center horizontal justified
                   language-selection-entry">
-            <div class="language-selection-title layout vertical center-justified"
-                i18n-content="languageDropdownTitle">
+            <div class=
+                "language-selection-title layout vertical center-justified">
+              [[i18nDynamic(locale, 'languageDropdownTitle')]]
             </div>
             <oobe-i18n-dropdown id="languageSelect" items="[[languages]]"
                 on-select-item="onLanguageSelected_"
@@ -118,8 +120,9 @@
           <div id="keyboardDropdownContainer"
               class="flex layout center horizontal justified
                  language-selection-entry">
-            <div class="language-selection-title layout vertical center-justified"
-                i18n-content="keyboardDropdownTitle">
+            <div class=
+                "language-selection-title layout vertical center-justified">
+              [[i18nDynamic(locale, 'keyboardDropdownTitle')]]
             </div>
             <oobe-i18n-dropdown id="keyboardSelect" items="[[keyboards]]"
                 on-select-item="onKeyboardSelected_"
@@ -130,7 +133,7 @@
       </div>
       <div class="bottom-buttons layout horizontal end-justified">
         <oobe-text-button inverse on-tap="closeLanguageSection_">
-          <div i18n-content="oobeOKButtonText"></div>
+          <div>[[i18nDynamic(locale, 'oobeOKButtonText')]]</div>
         </oobe-text-button>
       </div>
     </oobe-dialog>
@@ -141,8 +144,12 @@
           icon2x="oobe-welcome-64:accessibility">
       </hd-iron-icon>
       <div class="header">
-        <h1 class="title" i18n-content="accessibilitySectionTitle"></h1>
-        <div class="subtitle" i18n-content="accessibilitySectionHint"></div>
+        <h1 class="title">
+          [[i18nDynamic(locale, 'accessibilitySectionTitle')]]
+        </h1>
+        <div class="subtitle">
+          [[i18nDynamic(locale, 'accessibilitySectionHint')]]
+        </div>
       </div>
       <div class="footer layout vertical">
         <oobe-a11y-option checked="[[a11yStatus.spokenFeedbackEnabled]]"
@@ -150,56 +157,76 @@
             chrome-message="enableSpokenFeedback"
             i18n-values="label-for-aria:spokenFeedbackOption"
             class="focus-on-show">
-          <span class="title" i18n-content="spokenFeedbackOption"></span>
-          <span class="checked-value" i18n-content="spokenFeedbackOptionOn">
+          <span class="title">
+            [[i18nDynamic(locale, 'spokenFeedbackOption')]]
           </span>
-          <span class="unchecked-value" i18n-content="spokenFeedbackOptionOff">
+          <span class="checked-value">
+            [[i18nDynamic(locale, 'spokenFeedbackOptionOn')]]
+          </span>
+          <span class="unchecked-value">
+            [[i18nDynamic(locale, 'spokenFeedbackOptionOff')]]
           </span>
         </oobe-a11y-option>
         <oobe-a11y-option checked="[[a11yStatus.largeCursorEnabled]]"
             on-change="onA11yOptionChanged_"
             chrome-message="enableLargeCursor"
             i18n-values="label-for-aria:largeCursorOption">
-          <span class="title" i18n-content="largeCursorOption"></span>
-          <span class="checked-value" i18n-content="largeCursorOptionOn">
+          <span class="title">
+            [[i18nDynamic(locale, 'largeCursorOption')]]
           </span>
-          <span class="unchecked-value" i18n-content="largeCursorOptionOff">
+          <span class="checked-value">
+            [[i18nDynamic(locale, 'largeCursorOptionOn')]]
+          </span>
+          <span class="unchecked-value">
+            [[i18nDynamic(locale, 'largeCursorOptionOff')]]
           </span>
         </oobe-a11y-option>
         <oobe-a11y-option checked="[[a11yStatus.highContrastEnabled]]"
             on-change="onA11yOptionChanged_"
             chrome-message="enableHighContrast"
             i18n-values="label-for-aria:highContrastOption">
-          <span class="title" i18n-content="highContrastOption"></span>
-          <span class="checked-value" i18n-content="highContrastOptionOn">
+          <span class="title">
+            [[i18nDynamic(locale, 'highContrastOption')]]
           </span>
-          <span class="unchecked-value" i18n-content="highContrastOptionOff">
+          <span class="checked-value">
+            [[i18nDynamic(locale, 'highContrastOptionOn')]]
+          </span>
+          <span class="unchecked-value">
+            [[i18nDynamic(locale, 'highContrastOptionOff')]]
           </span>
         </oobe-a11y-option>
         <oobe-a11y-option checked="[[a11yStatus.screenMagnifierEnabled]]"
             on-change="onA11yOptionChanged_"
             chrome-message="enableScreenMagnifier"
             i18n-values="label-for-aria:screenMagnifierOption">
-          <span class="title" i18n-content="screenMagnifierOption"></span>
-          <span class="checked-value" i18n-content="screenMagnifierOptionOn">
+          <span class="title">
+            [[i18nDynamic(locale, 'screenMagnifierOption')]]
           </span>
-          <span class="unchecked-value" i18n-content="screenMagnifierOptionOff">
+          <span class="checked-value">
+            [[i18nDynamic(locale, 'screenMagnifierOptionOn')]]
+          </span>
+          <span class="unchecked-value">
+            [[i18nDynamic(locale, 'screenMagnifierOptionOff')]]
           </span>
         </oobe-a11y-option>
         <oobe-a11y-option checked="[[a11yStatus.virtualKeyboardEnabled]]"
             on-change="onA11yOptionChanged_"
             chrome-message="enableVirtualKeyboard"
             i18n-values="label-for-aria:virtualKeyboardOption">
-          <span class="title" i18n-content="virtualKeyboardOption"></span>
-          <span class="checked-value" i18n-content="virtualKeyboardOptionOn">
+          <span class="title">
+            [[i18nDynamic(locale, 'virtualKeyboardOption')]]
           </span>
-          <span class="unchecked-value" i18n-content="virtualKeyboardOptionOff">
+          <span class="checked-value">
+            [[i18nDynamic(locale, 'virtualKeyboardOptionOn')]]
+          </span>
+          <span class="unchecked-value">
+            [[i18nDynamic(locale, 'virtualKeyboardOptionOff')]]
           </span>
         </oobe-a11y-option>
       </div>
       <div class="bottom-buttons layout horizontal end-justified">
         <oobe-text-button inverse on-tap="closeAccessibilitySection_">
-          <div i18n-content="oobeOKButtonText"></div>
+          <div>[[i18nDynamic(locale, 'oobeOKButtonText')]]</div>
         </oobe-text-button>
       </div>
     </oobe-dialog>
@@ -209,13 +236,14 @@
           icon1x="oobe-welcome-32:timezone" icon2x="oobe-welcome-64:timezone">
       </hd-iron-icon>
       <div class="header">
-        <h1 class="title" i18n-content="timezoneSectionTitle"></h1>
+        <h1 class="title">[[i18nDynamic(locale, 'timezoneSectionTitle')]]</h1>
       </div>
       <div class="footer layout vertical">
         <div class="flex layout center horizontal justified
               timezone-selection-entry">
-          <div class="timezone-selection-title layout vertical center-justified"
-              i18n-content="timezoneDropdownTitle">
+          <div class=
+              "timezone-selection-title layout vertical center-justified">
+            [[i18nDynamic(locale, 'timezoneDropdownTitle')]]
           </div>
           <oobe-i18n-dropdown id="timezoneSelect" items="[[timezones]]"
               on-select-item="onTimezoneSelected_"
@@ -226,7 +254,7 @@
       </div>
       <div class="bottom-buttons layout horizontal end-justified">
         <oobe-text-button inverse on-tap="closeTimezoneSection_">
-          <div i18n-content="oobeOKButtonText"></div>
+          <div>[[i18nDynamic(locale, 'oobeOKButtonText')]]</div>
         </oobe-text-button>
       </div>
     </oobe-dialog>
@@ -237,8 +265,10 @@
           icon1x="oobe-welcome-32:wifi" icon2x="oobe-welcome-64:wifi">
       </hd-iron-icon>
       <div class="header">
-        <h1 class="title" i18n-content="networkSectionTitle"></h1>
-        <div class="subtitle" i18n-content="networkSectionHint"></div>
+        <h1 class="title">[[i18nDynamic(locale, 'networkSectionTitle')]]</h1>
+        <div class="subtitle">
+          [[i18nDynamic(locale, 'networkSectionHint')]]
+        </div>
       </div>
       <div class="footer layout vertical">
         <cr-network-select id="networkSelect"
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index cd1ec9f..2092704 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -9,6 +9,8 @@
 Polymer({
   is: 'oobe-welcome-md',
 
+  behaviors: [I18nBehavior],
+
   properties: {
     /**
      * Currently selected system language (display name).
@@ -32,7 +34,7 @@
      */
     languages: {
       type: Array,
-      observer: "onLanguagesChanged_",
+      observer: 'onLanguagesChanged_',
     },
 
     /**
@@ -41,7 +43,7 @@
      */
     keyboards: {
       type: Array,
-      observer: "onKeyboardsChanged_",
+      observer: 'onKeyboardsChanged_',
     },
 
     /**
@@ -89,7 +91,7 @@
     /**
      * Controls displaying of "Enable debugging features" link.
      */
-     debuggingLinkVisible: Boolean,
+    debuggingLinkVisible: Boolean,
   },
 
   /**
@@ -130,6 +132,8 @@
       addWiFiNetworkMenuName: loadTimeData.getString('addWiFiNetworkMenuName'),
       proxySettingsMenuName: loadTimeData.getString('proxySettingsMenuName'),
     };
+
+    this.i18nUpdateLocale();
   },
 
   /**
@@ -207,21 +211,27 @@
         customItemName: 'proxySettingsMenuName',
         polymerIcon: 'oobe-welcome-20:add-proxy',
         customData: {
-          onTap: function() { self.OpenProxySettingsDialog_(); },
+          onTap: function() {
+            self.OpenProxySettingsDialog_();
+          },
         },
       },
       {
         customItemName: 'addWiFiNetworkMenuName',
         polymerIcon: 'oobe-welcome-20:add-wifi',
         customData: {
-          onTap: function() { self.OpenAddWiFiNetworkDialog_(); },
+          onTap: function() {
+            self.OpenAddWiFiNetworkDialog_();
+          },
         },
       },
       {
         customItemName: 'addMobileNetworkMenuName',
         polymerIcon: 'oobe-welcome-20:add-cellular',
         customData: {
-          onTap: function() { self.OpenAddWiFiNetworkDialog_(); },
+          onTap: function() {
+            self.OpenAddWiFiNetworkDialog_();
+          },
         },
       },
     ];
@@ -275,7 +285,7 @@
   },
 
   /**
-   * Handle Networwork Setup screen "Proxy settings" button.
+   * Handle Network Setup screen "Proxy settings" button.
    *
    * @private
    */
@@ -284,7 +294,7 @@
   },
 
   /**
-   * Handle Networwork Setup screen "Add WiFi network" button.
+   * Handle Network Setup screen "Add WiFi network" button.
    *
    * @private
    */
@@ -293,7 +303,7 @@
   },
 
   /**
-   * Handle Networwork Setup screen "Add cellular network" button.
+   * Handle Network Setup screen "Add cellular network" button.
    *
    * @private
    */
diff --git a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc
index f7a56836..2f525e05 100644
--- a/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc
+++ b/chrome/browser/ui/android/tab_contents/chrome_web_contents_view_delegate_android.cc
@@ -32,7 +32,7 @@
     const content::ContextMenuParams& params) {
   content::ContentViewCore* content_view_core =
       content::ContentViewCore::FromWebContents(web_contents_);
-  if (content_view_core && content_view_core->ShowPastePopup(params))
+  if (content_view_core && content_view_core->ShowSelectionMenu(params))
     return;
 
   // TODO(dtrainor, kouhei): Give WebView a Populator/delegate so it can use
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 274bed9..fc12774 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -47,7 +47,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/grit/generated_resources.h"
 #include "chromeos/login/login_state.h"
 #include "chromeos/network/portal_detector/network_portal_detector.h"
 #include "components/google/core/browser/google_util.h"
@@ -61,8 +60,6 @@
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/ime/chromeos/input_method_util.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/time_format.h"
 #include "ui/chromeos/events/pref_names.h"
 #include "ui/chromeos/ime/input_method_menu_item.h"
 #include "ui/chromeos/ime/input_method_menu_manager.h"
@@ -247,13 +244,6 @@
   }
 }
 
-base::string16 SystemTrayDelegateChromeOS::GetIMEManagedMessage() {
-  auto ime_state = input_method::InputMethodManager::Get()->GetActiveIMEState();
-  return ime_state->GetAllowedInputMethods().empty()
-             ? base::string16()
-             : l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_POLICY);
-}
-
 ash::NetworkingConfigDelegate*
 SystemTrayDelegateChromeOS::GetNetworkingConfigDelegate() const {
   return networking_config_delegate_.get();
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
index c75fcf61..a4a1690 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -51,7 +51,6 @@
   void GetCurrentIME(ash::IMEInfo* info) override;
   void GetAvailableIMEList(ash::IMEInfoList* list) override;
   void GetCurrentIMEProperties(ash::IMEPropertyInfoList* list) override;
-  base::string16 GetIMEManagedMessage() override;
   ash::NetworkingConfigDelegate* GetNetworkingConfigDelegate() const override;
   bool GetSessionStartTime(base::TimeTicks* session_start_time) override;
   bool GetSessionLengthLimit(base::TimeDelta* session_length_limit) override;
diff --git a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
index fe0fae7..385d472 100644
--- a/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_layout_model.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/autofill/autofill_popup_view.h"
 #include "chrome/browser/ui/autofill/popup_constants.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/popup_item_ids.h"
 #include "components/autofill/core/browser/suggestion.h"
 #include "components/autofill/core/common/autofill_util.h"
@@ -49,15 +50,16 @@
   const char* name;
   int id;
 } kDataResources[] = {
-    {"americanExpressCC", IDR_AUTOFILL_CC_AMEX},
-    {"dinersCC", IDR_AUTOFILL_CC_GENERIC},
-    {"discoverCC", IDR_AUTOFILL_CC_DISCOVER},
-    {"genericCC", IDR_AUTOFILL_CC_GENERIC},
-    {"jcbCC", IDR_AUTOFILL_CC_GENERIC},
-    {"masterCardCC", IDR_AUTOFILL_CC_MASTERCARD},
-    {"mirCC", IDR_AUTOFILL_CC_MIR},
-    {"unionPayCC", IDR_AUTOFILL_CC_UNIONPAY},
-    {"visaCC", IDR_AUTOFILL_CC_VISA},
+    {autofill::kAmericanExpressCard, IDR_AUTOFILL_CC_AMEX},
+    {autofill::kDinersCard, IDR_AUTOFILL_CC_DINERS},
+    {autofill::kDiscoverCard, IDR_AUTOFILL_CC_DISCOVER},
+    {autofill::kEloCard, IDR_AUTOFILL_CC_ELO},
+    {autofill::kGenericCard, IDR_AUTOFILL_CC_GENERIC},
+    {autofill::kJCBCard, IDR_AUTOFILL_CC_JCB},
+    {autofill::kMasterCard, IDR_AUTOFILL_CC_MASTERCARD},
+    {autofill::kMirCard, IDR_AUTOFILL_CC_MIR},
+    {autofill::kUnionPay, IDR_AUTOFILL_CC_UNIONPAY},
+    {autofill::kVisaCard, IDR_AUTOFILL_CC_VISA},
 #if defined(OS_ANDROID)
     {"httpWarning", IDR_AUTOFILL_HTTP_WARNING},
     {"httpsInvalid", IDR_AUTOFILL_HTTPS_INVALID_WARNING},
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
index f500fd0..abd4fcbb1 100644
--- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.cc
@@ -82,7 +82,7 @@
 bool ContactInfoEditorViewController::ValidateModelAndSave() {
   // TODO(crbug.com/712224): Move this method and its helpers to a base class
   // shared with the Shipping Address editor.
-  if (!ValidateModel())
+  if (!ValidateInputFields())
     return false;
 
   if (profile_to_edit_) {
@@ -125,16 +125,6 @@
                                 IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL);
 }
 
-bool ContactInfoEditorViewController::ValidateModel() {
-  for (const auto& field : text_fields()) {
-    // Force a blur, as validation only occurs after the first blur.
-    field.first->OnBlur();
-    if (field.first->invalid())
-      return false;
-  }
-  return true;
-}
-
 void ContactInfoEditorViewController::PopulateProfile(
     autofill::AutofillProfile* profile) {
   for (const auto& field : text_fields()) {
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h
index 661a402..1d10660d 100644
--- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller.h
@@ -50,7 +50,6 @@
   base::string16 GetSheetTitle() override;
 
  private:
-  bool ValidateModel();
   // Uses the values in the UI fields to populate the corresponding values in
   // |profile|.
   void PopulateProfile(autofill::AutofillProfile* profile);
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index 0068ad3..e32b8d0 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -389,21 +389,19 @@
   autofill::CreditCard credit_card;
   credit_card.set_origin(autofill::kSettingsOrigin);
 
+  if (!ValidateInputFields())
+    return false;
+
   for (const auto& field : text_fields()) {
     // ValidatingTextfield* is the key, EditorField is the value.
     DCHECK_EQ(autofill::CREDIT_CARD,
               autofill::AutofillType(field.second.type).group());
-    if (field.first->invalid())
-      return false;
-
     credit_card.SetInfo(autofill::AutofillType(field.second.type),
                         field.first->text(), locale);
   }
   for (const auto& field : comboboxes()) {
     // ValidatingCombobox* is the key, EditorField is the value.
     ValidatingCombobox* combobox = field.first;
-    if (combobox->invalid())
-      return false;
 
     if (field.second.type == kBillingAddressType) {
       autofill::AddressComboboxModel* model =
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
index 0047e43..2a3fd75 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
@@ -176,6 +176,9 @@
   autofill::TestAutofillClock test_clock;
   test_clock.SetNow(kJune2017);
 
+  autofill::AutofillProfile billing_profile(autofill::test::GetFullProfile());
+  AddAutofillProfile(billing_profile);
+
   InvokePaymentRequestUI();
 
   OpenCreditCardEditorScreen();
@@ -184,13 +187,14 @@
                           autofill::CREDIT_CARD_NAME_FULL);
   SetEditorTextfieldValue(base::ASCIIToUTF16("4111111111111111"),
                           autofill::CREDIT_CARD_NUMBER);
+
+  SelectBillingAddress(billing_profile.guid());
+
   // The card is expired.
   SetComboboxValue(base::ASCIIToUTF16("01"), autofill::CREDIT_CARD_EXP_MONTH);
   SetComboboxValue(base::ASCIIToUTF16("2017"),
                    autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
 
-  ClickOnDialogViewAndWait(DialogViewID::EDITOR_SAVE_BUTTON);
-
   EXPECT_FALSE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NAME_FULL));
   EXPECT_FALSE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NUMBER));
   EXPECT_TRUE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH));
@@ -199,8 +203,18 @@
                 IDS_PAYMENTS_VALIDATION_INVALID_CREDIT_CARD_EXPIRED),
             GetErrorLabelForType(autofill::CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR));
 
+  views::View* save_button = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON));
+
+  EXPECT_FALSE(save_button->enabled());
+  ClickOnDialogViewAndWait(DialogViewID::EDITOR_SAVE_BUTTON);
+
   autofill::PersonalDataManager* personal_data_manager = GetDataManager();
   EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size());
+
+  SetComboboxValue(base::ASCIIToUTF16("12"), autofill::CREDIT_CARD_EXP_MONTH);
+
+  EXPECT_TRUE(save_button->enabled());
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest, EditingMaskedCard) {
@@ -358,7 +372,7 @@
                           autofill::CREDIT_CARD_NAME_FULL);
   // In this test case, only "visa" and "mastercard" are supported, so entering
   // a MIR card will fail.
-  SetEditorTextfieldValue(base::ASCIIToUTF16("22222222invalidcard"),
+  SetEditorTextfieldValue(base::ASCIIToUTF16("22002222invalidcard"),
                           autofill::CREDIT_CARD_NUMBER);
   EXPECT_EQ(l10n_util::GetStringUTF16(
                 IDS_PAYMENTS_VALIDATION_UNSUPPORTED_CREDIT_CARD_TYPE),
@@ -783,4 +797,45 @@
   EXPECT_FALSE(textfield->IsValid());
 }
 
+IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest, DoneButtonDisabled) {
+  autofill::TestAutofillClock test_clock;
+  test_clock.SetNow(kJune2017);
+  InvokePaymentRequestUI();
+
+  autofill::AutofillProfile billing_profile(autofill::test::GetFullProfile());
+  AddAutofillProfile(billing_profile);
+
+  OpenCreditCardEditorScreen();
+
+  views::View* save_button = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON));
+
+  EXPECT_FALSE(save_button->enabled());
+
+  // Set all fields but one:
+  SetEditorTextfieldValue(base::ASCIIToUTF16("Bob Jones"),
+                          autofill::CREDIT_CARD_NAME_FULL);
+  SetEditorTextfieldValue(base::ASCIIToUTF16("4111111111111111"),
+                          autofill::CREDIT_CARD_NUMBER);
+  SetComboboxValue(base::ASCIIToUTF16("05"), autofill::CREDIT_CARD_EXP_MONTH);
+  SetComboboxValue(base::ASCIIToUTF16("2026"),
+                   autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+  // Still disabled.
+  EXPECT_FALSE(save_button->enabled());
+
+  // Set the last field.
+  SelectBillingAddress(billing_profile.guid());
+
+  // Should be good to go.
+  EXPECT_TRUE(save_button->enabled());
+
+  // Change a field to something invalid, to make sure it works both ways.
+  SetEditorTextfieldValue(base::ASCIIToUTF16("Ni!"),
+                          autofill::CREDIT_CARD_NUMBER);
+
+  // Back to being disabled.
+  EXPECT_FALSE(save_button->enabled());
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index ceee69e..1eacd6c0 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -129,6 +129,18 @@
   return nullptr;
 }
 
+bool EditorViewController::ValidateInputFields() {
+  for (const auto& field : text_fields()) {
+    if (!field.first->IsValid())
+      return false;
+  }
+  for (const auto& field : comboboxes()) {
+    if (!field.first->IsValid())
+      return false;
+  }
+  return true;
+}
+
 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() {
   std::unique_ptr<views::Button> button(
       views::MdTextButton::CreateSecondaryUiBlueButton(
@@ -208,11 +220,15 @@
 
 void EditorViewController::ContentsChanged(views::Textfield* sender,
                                            const base::string16& new_contents) {
-  static_cast<ValidatingTextfield*>(sender)->OnContentsChanged();
+  ValidatingTextfield* sender_cast = static_cast<ValidatingTextfield*>(sender);
+  sender_cast->OnContentsChanged();
+  primary_button()->SetEnabled(ValidateInputFields());
 }
 
 void EditorViewController::OnPerformAction(views::Combobox* sender) {
-  static_cast<ValidatingCombobox*>(sender)->OnContentsChanged();
+  ValidatingCombobox* sender_cast = static_cast<ValidatingCombobox*>(sender);
+  sender_cast->OnContentsChanged();
+  primary_button()->SetEnabled(ValidateInputFields());
 }
 
 std::unique_ptr<views::View> EditorViewController::CreateEditorView() {
@@ -306,6 +322,9 @@
   if (!initial_focus_field_view_)
     initial_focus_field_view_ = first_field;
 
+  // Validate all fields and disable the primary (Done) button if necessary.
+  primary_button()->SetEnabled(ValidateInputFields());
+
   // Adds the "* indicates a required field" label in "disabled" grey text.
   std::unique_ptr<views::Label> required_field = base::MakeUnique<views::Label>(
       l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE));
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.h b/chrome/browser/ui/views/payments/editor_view_controller.h
index 216b45c..fbe836d 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/editor_view_controller.h
@@ -113,7 +113,9 @@
   virtual std::unique_ptr<views::View> CreateHeaderView();
   // |focusable_field| is to be set with a pointer to the view that should get
   // default focus within the custom view. |valid| should be set to the initial
-  // validity state of the custom view.
+  // validity state of the custom view. If a custom view requires model
+  // validation, it should be tracked in |text_fields_| or |comboboxes_| (e.g.,
+  // by using CreateComboboxForField).
   virtual std::unique_ptr<views::View> CreateCustomFieldView(
       autofill::ServerFieldType type,
       views::View** focusable_field,
@@ -129,6 +131,7 @@
       autofill::ServerFieldType type) = 0;
   // Validates the data entered and attempts to save; returns true on success.
   virtual bool ValidateModelAndSave() = 0;
+
   // Creates a ValidationDelegate which knows how to validate for a given
   // |field| definition.
   virtual std::unique_ptr<ValidationDelegate> CreateValidationDelegate(
@@ -136,6 +139,9 @@
   virtual std::unique_ptr<ui::ComboboxModel> GetComboboxModelForType(
       const autofill::ServerFieldType& type) = 0;
 
+  // Returns true if all fields are valid.
+  bool ValidateInputFields();
+
   // PaymentRequestSheetController;
   std::unique_ptr<views::Button> CreatePrimaryButton() override;
   void FillContentView(views::View* content_view) override;
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index 39054ab..3150960 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -55,6 +55,20 @@
 
 namespace {
 const auto kBillingAddressType = autofill::ADDRESS_BILLING_LINE1;
+
+// This is preferred to SelectValue, since only SetSelectedRow fires the events
+// as if done by a user.
+void SelectComboboxRowForValue(views::Combobox* combobox,
+                               const base::string16& text) {
+  int i;
+  for (i = 0; i < combobox->GetRowCount(); i++) {
+    if (combobox->GetTextForRow(i) == text)
+      break;
+  }
+  DCHECK(i < combobox->GetRowCount()) << "Combobox does not contain " << text;
+  combobox->SetSelectedRow(i);
+}
+
 }  // namespace
 
 PersonalDataLoadedObserverMock::PersonalDataLoadedObserverMock() {}
@@ -571,8 +585,8 @@
       static_cast<ValidatingTextfield*>(delegate_->dialog_view()->GetViewByID(
           EditorViewController::GetInputFieldViewId(type)));
   DCHECK(textfield);
-  textfield->SetText(value);
-  textfield->OnContentsChanged();
+  textfield->SetText(base::string16());
+  textfield->InsertText(value);
   textfield->OnBlur();
 }
 
@@ -592,8 +606,7 @@
       static_cast<ValidatingCombobox*>(delegate_->dialog_view()->GetViewByID(
           EditorViewController::GetInputFieldViewId(type)));
   DCHECK(combobox);
-  combobox->SelectValue(value);
-  combobox->OnContentsChanged();
+  SelectComboboxRowForValue(combobox, value);
   combobox->OnBlur();
 }
 
diff --git a/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc b/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
index 53157556..337bb1c 100644
--- a/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui_data_source.h"
 
 namespace policy_indicator {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 6901d29d..5367d52e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1056,16 +1056,9 @@
 #endif  // defined(OS_MACOSX)
 
 #if defined(OS_WIN)
-// Disables per monitor DPI for supported Windows versions.
-// This flag overrides kEnablePerMonitorDpi.
-const char kDisablePerMonitorDpi[]          = "disable-per-monitor-dpi";
-
 // Fallback to XPS. By default connector uses CDD.
 const char kEnableCloudPrintXps[]           = "enable-cloud-print-xps";
 
-// Enables per monitor DPI for supported Windows versions.
-const char kEnablePerMonitorDpi[]           = "enable-per-monitor-dpi";
-
 // Force-enables the profile shortcut manager. This is needed for tests since
 // they use a custom-user-data-dir which disables this.
 const char kEnableProfileShortcutManager[]  = "enable-profile-shortcut-manager";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 6d9cb19e..d983d8c8 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -314,9 +314,7 @@
 #endif  // defined(OS_MACOSX)
 
 #if defined(OS_WIN)
-extern const char kDisablePerMonitorDpi[];
 extern const char kEnableCloudPrintXps[];
-extern const char kEnablePerMonitorDpi[];
 extern const char kEnableProfileShortcutManager[];
 extern const char kHideIcons[];
 extern const char kNoNetworkProfileWarning[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 39fd326..2b006a2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3184,6 +3184,7 @@
     "../browser/policy/profile_policy_connector_unittest.cc",
     "../browser/predictors/autocomplete_action_predictor_table_unittest.cc",
     "../browser/predictors/autocomplete_action_predictor_unittest.cc",
+    "../browser/predictors/loading_predictor_unittest.cc",
     "../browser/predictors/resource_prefetch_common_unittest.cc",
     "../browser/predictors/resource_prefetch_predictor_tables_unittest.cc",
     "../browser/predictors/resource_prefetch_predictor_test_util.cc",
diff --git a/chrome/test/data/webui/i18n_behavior_test.html b/chrome/test/data/webui/i18n_behavior_test.html
index 0bd41fd..bcbad9a 100644
--- a/chrome/test/data/webui/i18n_behavior_test.html
+++ b/chrome/test/data/webui/i18n_behavior_test.html
@@ -35,11 +35,17 @@
   I18nBehavior.i18nAdvanced('customTag', {tags: ['X-FOO']});
 }
 
+function testI18nDynamic() {
+  var locale = 'en';
+  assertEquals("I'm just text, nobody should have a problem with me!",
+      I18nBehavior.i18nDynamic(locale, 'text'));
+}
+
 function testI18nExists() {
   assertTrue(I18nBehavior.i18nExists('text'));
   assertFalse(I18nBehavior.i18nExists('missingText'));
 }
- 
+
 </script>
 </body>
 </html>
diff --git a/components/autofill/core/browser/autofill_data_util.cc b/components/autofill/core/browser/autofill_data_util.cc
index 13501e55..0c06eed 100644
--- a/components/autofill/core/browser/autofill_data_util.cc
+++ b/components/autofill/core/browser/autofill_data_util.cc
@@ -33,6 +33,7 @@
      IDS_AUTOFILL_CC_DINERS},
     {autofill::kDiscoverCard, "discover", IDR_AUTOFILL_CC_DISCOVER,
      IDS_AUTOFILL_CC_DISCOVER},
+    {autofill::kEloCard, "elo", IDR_AUTOFILL_CC_ELO, IDS_AUTOFILL_CC_ELO},
     {autofill::kJCBCard, "jcb", IDR_AUTOFILL_CC_JCB, IDS_AUTOFILL_CC_JCB},
     {autofill::kMasterCard, "mastercard", IDR_AUTOFILL_CC_MASTERCARD,
      IDS_AUTOFILL_CC_MASTERCARD},
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index fdec3b3..33dc123 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -79,6 +79,8 @@
     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS);
   if (network == kDiscoverCard)
     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER);
+  if (network == kEloCard)
+    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_ELO);
   if (network == kJCBCard)
     return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB);
   if (network == kMasterCard)
@@ -146,6 +148,8 @@
     return IDR_AUTOFILL_CC_DINERS;
   if (network == kDiscoverCard)
     return IDR_AUTOFILL_CC_DISCOVER;
+  if (network == kEloCard)
+    return IDR_AUTOFILL_CC_ELO;
   if (network == kJCBCard)
     return IDR_AUTOFILL_CC_JCB;
   if (network == kMasterCard)
@@ -166,27 +170,24 @@
 // static
 const char* CreditCard::GetCardNetwork(const base::string16& number) {
   // Credit card number specifications taken from:
-  // http://en.wikipedia.org/wiki/Credit_card_numbers,
-  // http://en.wikipedia.org/wiki/List_of_Issuer_Identification_Numbers,
-  // http://www.discovernetwork.com/merchants/images/Merchant_Marketing_PDF.pdf,
+  // https://en.wikipedia.org/wiki/Payment_card_number,
   // http://www.regular-expressions.info/creditcard.html,
-  // http://developer.ean.com/general_info/Valid_Credit_Card_Types,
-  // http://www.bincodes.com/,
-  // http://www.fraudpractice.com/FL-binCC.html, and
-  // http://www.beachnet.com/~hstiles/cardtype.html
+  // https://developer.ean.com/general-info/valid-card-types,
+  // http://www.bincodes.com/, and
+  // http://www.fraudpractice.com/FL-binCC.html.
+  // (Last updated: May 29, 2017)
   //
-  // The last site is currently unavailable, but a cached version remains at
-  // http://web.archive.org/web/20120923111349/http://www.beachnet.com/~hstiles/cardtype.html
-  //
-  // Card Type              Prefix(es)                      Length
-  // ---------------------------------------------------------------
-  // Visa                   4                               13,16
-  // American Express       34,37                           15
-  // Diners Club            300-305,3095,36,38-39           14
-  // Discover Card          6011,644-649,65                 16
-  // JCB                    3528-3589                       16
-  // Mastercard             51-55                           16
-  // UnionPay               62                              16-19
+  // Card Type              Prefix(es)                                  Length
+  // --------------------------------------------------------------------------
+  // Visa                   4                                          13,16,19
+  // American Express       34,37                                      15
+  // Diners Club            300-305,309,36,38-39                       14
+  // Discover Card          6011,644-649,65                            16
+  // Elo                    431274,451416,5067,5090,627780,636297      16
+  // JCB                    3528-3589                                  16
+  // Mastercard             2221-2720, 51-55                           16
+  // MIR                    2200-2204                                  16
+  // UnionPay               62                                         16-19
 
   // Check for prefixes of length 1.
   if (number.empty())
@@ -203,9 +204,6 @@
   if (!base::StringToInt(number.substr(0, 2), &first_two_digits))
     return kGenericCard;
 
-  if (first_two_digits == 22)
-    return kMirCard;
-
   if (first_two_digits == 34 || first_two_digits == 37)
     return kAmericanExpressCard;
 
@@ -231,7 +229,8 @@
   if (!base::StringToInt(number.substr(0, 3), &first_three_digits))
     return kGenericCard;
 
-  if (first_three_digits >= 300 && first_three_digits <= 305)
+  if ((first_three_digits >= 300 && first_three_digits <= 305) ||
+      first_three_digits == 309)
     return kDinersCard;
 
   if (first_three_digits >= 644 && first_three_digits <= 649)
@@ -245,15 +244,35 @@
   if (!base::StringToInt(number.substr(0, 4), &first_four_digits))
     return kGenericCard;
 
-  if (first_four_digits == 3095)
-    return kDinersCard;
+  if (first_four_digits >= 2200 && first_four_digits <= 2204)
+    return kMirCard;
+
+  if (first_four_digits >= 2221 && first_four_digits <= 2720)
+    return kMasterCard;
 
   if (first_four_digits >= 3528 && first_four_digits <= 3589)
     return kJCBCard;
 
+  if (first_four_digits == 5067 || first_four_digits == 5090)
+    return kEloCard;
+
   if (first_four_digits == 6011)
     return kDiscoverCard;
 
+  // Check for prefixes of length 6.
+  if (number.size() < 6)
+    return kGenericCard;
+
+  int first_six_digits = 0;
+  if (!base::StringToInt(number.substr(0, 6), &first_six_digits))
+    return kGenericCard;
+
+  if (first_six_digits == 431274 ||
+      first_six_digits == 451416 ||
+      first_six_digits == 627780 ||
+      first_six_digits == 636297)
+    return kEloCard;
+
   return kGenericCard;
 }
 
@@ -930,12 +949,10 @@
                           credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
 }
 
-// These values must match the values in WebKitPlatformSupportImpl in
-// webkit/glue. We send these strings to WebKit, which then asks
-// WebKitPlatformSupportImpl to load the image data.
 const char kAmericanExpressCard[] = "americanExpressCC";
 const char kDinersCard[] = "dinersCC";
 const char kDiscoverCard[] = "discoverCC";
+const char kEloCard[] = "eloCC";
 const char kGenericCard[] = "genericCC";
 const char kJCBCard[] = "jcbCC";
 const char kMasterCard[] = "masterCardCC";
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h
index 5b1ba15..4dc8bb9 100644
--- a/components/autofill/core/browser/credit_card.h
+++ b/components/autofill/core/browser/credit_card.h
@@ -272,6 +272,7 @@
 extern const char kAmericanExpressCard[];
 extern const char kDinersCard[];
 extern const char kDiscoverCard[];
+extern const char kEloCard[];
 extern const char kGenericCard[];
 extern const char kJCBCard[];
 extern const char kMasterCard[];
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index f677189..3857613b 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -53,7 +53,10 @@
   "5019717010103742",
   "6331101999990016",
   "6247130048162403",
+  "4532261615476013542",
+  "6362970000457013",
 };
+
 const char* const kInvalidNumbers[] = {
   "4111 1111 112", /* too short */
   "41111111111111111115", /* too long */
@@ -407,9 +410,6 @@
   EXPECT_LT(0, b.Compare(a));
 }
 
-// This method is not compiled for iOS because these resources are not used and
-// should not be shipped.
-#if !defined(OS_IOS)
 // Test we get the correct icon for each card type.
 TEST(CreditCardTest, IconResourceId) {
   EXPECT_EQ(IDR_AUTOFILL_CC_AMEX,
@@ -418,6 +418,8 @@
             CreditCard::IconResourceId(kDinersCard));
   EXPECT_EQ(IDR_AUTOFILL_CC_DISCOVER,
             CreditCard::IconResourceId(kDiscoverCard));
+  EXPECT_EQ(IDR_AUTOFILL_CC_ELO,
+            CreditCard::IconResourceId(kEloCard));
   EXPECT_EQ(IDR_AUTOFILL_CC_JCB,
             CreditCard::IconResourceId(kJCBCard));
   EXPECT_EQ(IDR_AUTOFILL_CC_MASTERCARD,
@@ -429,7 +431,6 @@
   EXPECT_EQ(IDR_AUTOFILL_CC_VISA,
             CreditCard::IconResourceId(kVisaCard));
 }
-#endif  // #if !defined(OS_IOS)
 
 TEST(CreditCardTest, UpdateFromImportedCard) {
   CreditCard original_card(base::GenerateGUID(), "https://www.example.com");
@@ -687,6 +688,7 @@
         GetCardNetworkTestCase{"4111111111111111", kVisaCard, true},
         GetCardNetworkTestCase{"4012888888881881", kVisaCard, true},
         GetCardNetworkTestCase{"4222222222222", kVisaCard, true},
+        GetCardNetworkTestCase{"4532261615476013542", kVisaCard, true},
 
         // The relevant sample numbers from
         // https://www.auricsystems.com/sample-credit-card-numbers/
@@ -703,13 +705,12 @@
         GetCardNetworkTestCase{"6500000000000002", kDiscoverCard, true},
         GetCardNetworkTestCase{"3566002020360505", kJCBCard, true},
         GetCardNetworkTestCase{"3528000000000007", kJCBCard, true},
+        GetCardNetworkTestCase{"2222400061240016", kMasterCard, true},
+        GetCardNetworkTestCase{"2223000048400011", kMasterCard, true},
         GetCardNetworkTestCase{"5500005555555559", kMasterCard, true},
         GetCardNetworkTestCase{"5555555555555557", kMasterCard, true},
         GetCardNetworkTestCase{"5454545454545454", kMasterCard, true},
-        GetCardNetworkTestCase{"5555515555555551", kMasterCard, true},
-        GetCardNetworkTestCase{"5405222222222226", kMasterCard, true},
         GetCardNetworkTestCase{"5478050000000007", kMasterCard, true},
-        GetCardNetworkTestCase{"5111005111051128", kMasterCard, true},
         GetCardNetworkTestCase{"5112345112345114", kMasterCard, true},
         GetCardNetworkTestCase{"5115915115915118", kMasterCard, true},
         GetCardNetworkTestCase{"6247130048162403", kUnionPay, true},
@@ -719,6 +720,12 @@
         GetCardNetworkTestCase{"2200111234567898", kMirCard, true},
         GetCardNetworkTestCase{"2200481349288130", kMirCard, true},
 
+        // The relevant sample numbers from
+        // https://www.bincodes.com/bank-creditcard-generator/ and
+        // https://www.ebanx.com/business/en/developers/integrations/testing/credit-card-test-numbers
+        GetCardNetworkTestCase{"5067001446391275", kEloCard, true},
+        GetCardNetworkTestCase{"6362970000457013", kEloCard, true},
+
         // Empty string
         GetCardNetworkTestCase{std::string(), kGenericCard, false},
 
@@ -753,7 +760,11 @@
 
         // Issuer Identification Numbers (IINs) that Chrome recognizes.
         GetCardNetworkTestCase{"4", kVisaCard, false},
-        GetCardNetworkTestCase{"22", kMirCard, false},
+        GetCardNetworkTestCase{"2200", kMirCard, false},
+        GetCardNetworkTestCase{"2202", kMirCard, false},
+        GetCardNetworkTestCase{"2204", kMirCard, false},
+        GetCardNetworkTestCase{"2221", kMasterCard, false},
+        GetCardNetworkTestCase{"2720", kMasterCard, false},
         GetCardNetworkTestCase{"34", kAmericanExpressCard, false},
         GetCardNetworkTestCase{"37", kAmericanExpressCard, false},
         GetCardNetworkTestCase{"300", kDinersCard, false},
@@ -762,7 +773,7 @@
         GetCardNetworkTestCase{"303", kDinersCard, false},
         GetCardNetworkTestCase{"304", kDinersCard, false},
         GetCardNetworkTestCase{"305", kDinersCard, false},
-        GetCardNetworkTestCase{"3095", kDinersCard, false},
+        GetCardNetworkTestCase{"309", kDinersCard, false},
         GetCardNetworkTestCase{"36", kDinersCard, false},
         GetCardNetworkTestCase{"38", kDinersCard, false},
         GetCardNetworkTestCase{"39", kDinersCard, false},
@@ -774,6 +785,9 @@
         GetCardNetworkTestCase{"648", kDiscoverCard, false},
         GetCardNetworkTestCase{"649", kDiscoverCard, false},
         GetCardNetworkTestCase{"65", kDiscoverCard, false},
+        GetCardNetworkTestCase{"5067", kEloCard, false},
+        GetCardNetworkTestCase{"5090", kEloCard, false},
+        GetCardNetworkTestCase{"636297", kEloCard, false},
         GetCardNetworkTestCase{"3528", kJCBCard, false},
         GetCardNetworkTestCase{"3531", kJCBCard, false},
         GetCardNetworkTestCase{"3589", kJCBCard, false},
@@ -788,7 +802,6 @@
         GetCardNetworkTestCase{"2", kGenericCard, false},
         GetCardNetworkTestCase{"3", kGenericCard, false},
         GetCardNetworkTestCase{"30", kGenericCard, false},
-        GetCardNetworkTestCase{"309", kGenericCard, false},
         GetCardNetworkTestCase{"35", kGenericCard, false},
         GetCardNetworkTestCase{"5", kGenericCard, false},
         GetCardNetworkTestCase{"6", kGenericCard, false},
@@ -817,9 +830,6 @@
         GetCardNetworkTestCase{"306", kGenericCard, false},
         GetCardNetworkTestCase{"307", kGenericCard, false},
         GetCardNetworkTestCase{"308", kGenericCard, false},
-        GetCardNetworkTestCase{"3091", kGenericCard, false},
-        GetCardNetworkTestCase{"3094", kGenericCard, false},
-        GetCardNetworkTestCase{"3096", kGenericCard, false},
         GetCardNetworkTestCase{"31", kGenericCard, false},
         GetCardNetworkTestCase{"32", kGenericCard, false},
         GetCardNetworkTestCase{"33", kGenericCard, false},
diff --git a/components/autofill/core/browser/validation.cc b/components/autofill/core/browser/validation.cc
index 4588a13b..60726b8e 100644
--- a/components/autofill/core/browser/validation.cc
+++ b/components/autofill/core/browser/validation.cc
@@ -46,11 +46,11 @@
 bool IsValidCreditCardNumber(const base::string16& text) {
   base::string16 number = CreditCard::StripSeparators(text);
 
-  // Credit card numbers are at most 19 digits in length [1]. 12 digits seems to
-  // be a fairly safe lower-bound [2].  Specific card issuers have more rigidly
-  // defined sizes.
-  // [1] http://www.merriampark.com/anatomycc.htm
-  // [2] http://en.wikipedia.org/wiki/Bank_card_number
+  // Credit card numbers are at most 19 digits in length, 12 digits seems to
+  // be a fairly safe lower-bound [1].  Specific card issuers have more rigidly
+  // defined sizes. 
+  // (Last updated: May 29, 2017)
+  // [1] https://en.wikipedia.org/wiki/Payment_card_number.
   // CardEditor.isCardNumberLengthMaxium() needs to be kept in sync.
   const char* const type = CreditCard::GetCardNetwork(text);
   if (type == kAmericanExpressCard && number.size() != 15)
@@ -59,6 +59,8 @@
     return false;
   if (type == kDiscoverCard && number.size() != 16)
     return false;
+  if (type == kEloCard && number.size() != 16)
+    return false;
   if (type == kJCBCard && number.size() != 16)
     return false;
   if (type == kMasterCard && number.size() != 16)
@@ -67,7 +69,8 @@
     return false;
   if (type == kUnionPay && (number.size() < 16 || number.size() > 19))
     return false;
-  if (type == kVisaCard && number.size() != 13 && number.size() != 16)
+  if (type == kVisaCard && number.size() != 13 && number.size() != 16 &&
+      number.size() != 19)
     return false;
   if (type == kGenericCard && (number.size() < 12 || number.size() > 19))
     return false;
diff --git a/components/autofill/core/browser/validation_unittest.cc b/components/autofill/core/browser/validation_unittest.cc
index ee36fbc4..8c4b95ce 100644
--- a/components/autofill/core/browser/validation_unittest.cc
+++ b/components/autofill/core/browser/validation_unittest.cc
@@ -56,6 +56,8 @@
     "5019717010103742",
     "6331101999990016",
     "6247130048162403",
+    "4532261615476013542", // Visa, 19 digits.
+    "6362970000457013", // Elo
 };
 const char* const kInvalidNumbers[] = {
   "4111 1111 112", /* too short */
@@ -346,7 +348,7 @@
 }
 
 const static std::set<std::string> kAllBasicCardNetworks{
-    "amex",       "discover", "diners",   "jcb",
+    "amex",       "discover", "diners",   "elo",  "jcb",
     "mastercard", "mir",      "unionpay", "visa"};
 
 INSTANTIATE_TEST_CASE_P(
@@ -384,6 +386,8 @@
                      IDS_PAYMENTS_VALIDATION_UNSUPPORTED_CREDIT_CARD_TYPE),
 
         CCNumberCase(kValidNumbers[17], kAllBasicCardNetworks, true, 0),
+        CCNumberCase(kValidNumbers[18], kAllBasicCardNetworks, true, 0),
+        CCNumberCase(kValidNumbers[19], kAllBasicCardNetworks, true, 0),
 
         CCNumberCase(kInvalidNumbers[0],
                      kAllBasicCardNetworks,
@@ -436,6 +440,7 @@
         GetCvcLengthForCardTypeCase{kAmericanExpressCard, AMEX_CVC_LENGTH},
         GetCvcLengthForCardTypeCase{kDinersCard, GENERAL_CVC_LENGTH},
         GetCvcLengthForCardTypeCase{kDiscoverCard, GENERAL_CVC_LENGTH},
+        GetCvcLengthForCardTypeCase{kEloCard, GENERAL_CVC_LENGTH},
         GetCvcLengthForCardTypeCase{kGenericCard, GENERAL_CVC_LENGTH},
         GetCvcLengthForCardTypeCase{kJCBCard, GENERAL_CVC_LENGTH},
         GetCvcLengthForCardTypeCase{kMasterCard, GENERAL_CVC_LENGTH},
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 06c0901..bea84fe 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -63,6 +63,9 @@
   <message name="IDS_AUTOFILL_CC_DISCOVER" desc="Discover credit card name." formatter_data="android_java">
     Discover
   </message>
+  <message name="IDS_AUTOFILL_CC_ELO" desc="Elo credit card name." formatter_data="android_java">
+    Elo
+  </message>
   <message name="IDS_AUTOFILL_CC_JCB" desc="JCB credit card name." formatter_data="android_java">
     JCB
   </message>
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java
index 90fd308..bc453c140 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java
@@ -37,7 +37,7 @@
     }
 
     @VisibleForTesting
-    static void setSchedulerForTesting(BackgroundTaskScheduler scheduler) {
+    public static void setSchedulerForTesting(BackgroundTaskScheduler scheduler) {
         sInstance = scheduler;
     }
 
diff --git a/components/browser_watcher/BUILD.gn b/components/browser_watcher/BUILD.gn
index a45c0c8..7e459f07 100644
--- a/components/browser_watcher/BUILD.gn
+++ b/components/browser_watcher/BUILD.gn
@@ -107,6 +107,8 @@
       "stability_data_names.h",
       "stability_debugging.cc",
       "stability_debugging.h",
+      "stability_metrics.cc",
+      "stability_metrics.h",
       "stability_paths.cc",
       "stability_paths.h",
     ]
diff --git a/components/browser_watcher/postmortem_report_collector.cc b/components/browser_watcher/postmortem_report_collector.cc
index 8929fe46..ef21d84 100644
--- a/components/browser_watcher/postmortem_report_collector.cc
+++ b/components/browser_watcher/postmortem_report_collector.cc
@@ -214,10 +214,9 @@
     return false;
   }
 
-  // Report collection is successful. We may increment |unclean_system_cnt|.
+  LogCollectionStatus(SUCCESS);
   if (report_proto.system_state().session_state() == SystemState::UNCLEAN)
     *system_unclean = true;
-
   return true;
 }
 
diff --git a/components/browser_watcher/stability_metrics.cc b/components/browser_watcher/stability_metrics.cc
new file mode 100644
index 0000000..0ec6675
--- /dev/null
+++ b/components/browser_watcher/stability_metrics.cc
@@ -0,0 +1,21 @@
+// 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/browser_watcher/stability_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace browser_watcher {
+
+void LogCollectOnCrashEvent(CollectOnCrashEvent event) {
+  UMA_HISTOGRAM_ENUMERATION("ActivityTracker.CollectCrash.Event", event,
+                            CollectOnCrashEvent::kCollectOnCrashEventMax);
+}
+
+void LogStabilityRecordEvent(StabilityRecordEvent event) {
+  UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Record.Event", event,
+                            StabilityRecordEvent::kStabilityRecordEventMax);
+}
+
+}  // namespace browser_watcher
diff --git a/components/browser_watcher/stability_metrics.h b/components/browser_watcher/stability_metrics.h
new file mode 100644
index 0000000..1daf70a
--- /dev/null
+++ b/components/browser_watcher/stability_metrics.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_BROWSER_WATCHER_STABILITY_METRICS_H_
+#define COMPONENTS_BROWSER_WATCHER_STABILITY_METRICS_H_
+
+namespace browser_watcher {
+
+// DO NOT REMOVE OR REORDER VALUES. This is logged persistently in a histogram.
+enum class CollectOnCrashEvent {
+  kCollectAttempt,
+  kUserDataDirNotEmpty,
+  kPathExists,
+  kReportExtractionSuccess,
+  kPmaSetDeletedFailed,
+  kOpenForDeleteFailed,
+  kSuccess,
+  // New values go here.
+  kCollectOnCrashEventMax
+};
+
+// DO NOT REMOVE OR REORDER VALUES. This is logged persistently in a histogram.
+enum class StabilityRecordEvent {
+  kRecordAttempt,
+  kStabilityDirectoryExists,
+  kGotStabilityPath,
+  kGotTracker,
+  kMarkDeleted,
+  kMarkDeletedGotFile,
+  kOpenForDeleteFailed,
+  // New values go here.
+  kStabilityRecordEventMax
+};
+
+void LogCollectOnCrashEvent(CollectOnCrashEvent event);
+void LogStabilityRecordEvent(StabilityRecordEvent event);
+
+}  // namespace browser_watcher
+
+#endif  // COMPONENTS_BROWSER_WATCHER_STABILITY_METRICS_H_
diff --git a/components/browser_watcher/stability_paths.cc b/components/browser_watcher/stability_paths.cc
index 66805fa..329d89c 100644
--- a/components/browser_watcher/stability_paths.cc
+++ b/components/browser_watcher/stability_paths.cc
@@ -8,20 +8,30 @@
 #include <windows.h>
 #endif  // defined(OS_WIN)
 
+#include <memory>
 #include <string>
+#include <utility>
 
+#include "base/debug/activity_tracker.h"
 #include "base/feature_list.h"
 #include "base/files/file.h"
+#include "base/files/memory_mapped_file.h"
 #include "base/metrics/persistent_memory_allocator.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "components/browser_watcher/features.h"
+#include "components/browser_watcher/stability_metrics.h"
 
 #if defined(OS_WIN)
 
 #include "third_party/crashpad/crashpad/util/win/time.h"
 
 namespace browser_watcher {
+
+using base::FilePersistentMemoryAllocator;
+using base::MemoryMappedFile;
+using base::PersistentMemoryAllocator;
+
 namespace {
 
 bool GetCreationTime(const base::Process& process, FILETIME* creation_time) {
@@ -30,6 +40,21 @@
                            &ignore) != 0;
 }
 
+bool SetPmaFileDeleted(const base::FilePath& file_path) {
+  // Map the file read-write so it can guarantee consistency between
+  // the analyzer and any trackers that may still be active.
+  std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
+  mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE);
+  if (!mmfile->IsValid())
+    return false;
+  if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true))
+    return false;
+  FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0,
+                                          base::StringPiece(), true);
+  allocator.SetMemoryState(PersistentMemoryAllocator::MEMORY_DELETED);
+  return true;
+}
+
 }  // namespace
 
 base::FilePath GetStabilityDir(const base::FilePath& user_data_dir) {
@@ -72,25 +97,40 @@
          base::PersistentMemoryAllocator::kFileExtension;
 }
 
-void MarkStabilityFileForDeletion(const base::FilePath& user_data_dir) {
-  if (!base::FeatureList::IsEnabled(
-          browser_watcher::kStabilityDebuggingFeature)) {
-    return;
-  }
+void MarkOwnStabilityFileDeleted(const base::FilePath& user_data_dir) {
+  base::debug::GlobalActivityTracker* global_tracker =
+      base::debug::GlobalActivityTracker::Get();
+  if (!global_tracker)
+    return;  // No stability instrumentation.
 
-  base::FilePath stability_file;
-  if (!GetStabilityFileForProcess(base::Process::Current(), user_data_dir,
-                                  &stability_file)) {
-    // TODO(manzagop): add a metric for this.
-    return;
-  }
+  global_tracker->MarkDeleted();
+  LogStabilityRecordEvent(StabilityRecordEvent::kMarkDeleted);
 
   // Open (with delete) and then immediately close the file by going out of
   // scope. This should cause the stability debugging file to be deleted prior
   // to the next execution.
-  base::File file(stability_file, base::File::FLAG_OPEN |
-                                      base::File::FLAG_READ |
-                                      base::File::FLAG_DELETE_ON_CLOSE);
+  base::FilePath stability_file;
+  if (!GetStabilityFileForProcess(base::Process::Current(), user_data_dir,
+                                  &stability_file)) {
+    return;
+  }
+  LogStabilityRecordEvent(StabilityRecordEvent::kMarkDeletedGotFile);
+
+  base::File deleter(stability_file, base::File::FLAG_OPEN |
+                                         base::File::FLAG_READ |
+                                         base::File::FLAG_DELETE_ON_CLOSE);
+  if (!deleter.IsValid())
+    LogStabilityRecordEvent(StabilityRecordEvent::kOpenForDeleteFailed);
+}
+
+void MarkStabilityFileDeletedOnCrash(const base::FilePath& file_path) {
+  if (!SetPmaFileDeleted(file_path))
+    LogCollectOnCrashEvent(CollectOnCrashEvent::kPmaSetDeletedFailed);
+
+  base::File deleter(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
+                                    base::File::FLAG_DELETE_ON_CLOSE);
+  if (!deleter.IsValid())
+    LogCollectOnCrashEvent(CollectOnCrashEvent::kOpenForDeleteFailed);
 }
 
 }  // namespace browser_watcher
diff --git a/components/browser_watcher/stability_paths.h b/components/browser_watcher/stability_paths.h
index 07216f1f..7941c37 100644
--- a/components/browser_watcher/stability_paths.h
+++ b/components/browser_watcher/stability_paths.h
@@ -35,8 +35,15 @@
 // Returns a pattern that matches file names returned by GetFileForProcess.
 base::FilePath::StringType GetStabilityFilePattern();
 
-// Marks the stability file for deletion.
-void MarkStabilityFileForDeletion(const base::FilePath& user_data_dir);
+// Sets the current process's stability file's state to deleted (via the
+// GlobalActivityTracker) and opens the file for deletion. Metrics pertaining to
+// stability recording are logged.
+void MarkOwnStabilityFileDeleted(const base::FilePath& user_data_dir);
+
+// Sets another process's stability file's state to deleted, then opens it for
+// deletion. This function is meant for use by the crashpad handler; it logs
+// metrics labelled as in the context of crash collection.
+void MarkStabilityFileDeletedOnCrash(const base::FilePath& file_path);
 
 #endif  // defined(OS_WIN)
 
diff --git a/components/browser_watcher/stability_report_user_stream_data_source.cc b/components/browser_watcher/stability_report_user_stream_data_source.cc
index 62fdf22..5dab22a84 100644
--- a/components/browser_watcher/stability_report_user_stream_data_source.cc
+++ b/components/browser_watcher/stability_report_user_stream_data_source.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "components/browser_watcher/minidump_user_streams.h"
+#include "components/browser_watcher/stability_metrics.h"
 #include "components/browser_watcher/stability_paths.h"
 #include "components/browser_watcher/stability_report_extractor.h"
 #include "third_party/crashpad/crashpad/minidump/minidump_user_extension_stream_data_source.h"
@@ -73,6 +74,8 @@
       data_.size() ? data_.data() : nullptr, data_.size());
 }
 
+// TODO(manzagop): Collection should factor in whether this is a true crash or
+// dump without crashing.
 std::unique_ptr<BufferExtensionStreamDataSource> CollectReport(
     const base::FilePath& path) {
   StabilityReport report;
@@ -81,20 +84,17 @@
                             COLLECTION_STATUS_MAX);
   if (status != SUCCESS)
     return nullptr;
+  LogCollectOnCrashEvent(CollectOnCrashEvent::kReportExtractionSuccess);
 
-  // Open (with delete) and then immediately close the file by going out of
-  // scope. This should cause the stability debugging file to be deleted prior
-  // to the next execution.
-  // TODO(manzagop): set the persistent allocator file's state to deleted in
-  //     case the file can't be deleted.
-  base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ |
-                            base::File::FLAG_DELETE_ON_CLOSE);
-  UMA_HISTOGRAM_BOOLEAN("ActivityTracker.CollectCrash.OpenForDeleteSuccess",
-                        file.IsValid());
+  MarkStabilityFileDeletedOnCrash(path);
 
   std::unique_ptr<BufferExtensionStreamDataSource> source(
       new BufferExtensionStreamDataSource(kStabilityReportStreamType));
-  return source->Init(report) ? std::move(source) : nullptr;
+  if (!source->Init(report))
+    return nullptr;
+
+  LogCollectOnCrashEvent(CollectOnCrashEvent::kSuccess);
+  return source;
 }
 
 }  // namespace
@@ -107,9 +107,11 @@
 StabilityReportUserStreamDataSource::ProduceStreamData(
     crashpad::ProcessSnapshot* process_snapshot) {
   DCHECK(process_snapshot);
+  LogCollectOnCrashEvent(CollectOnCrashEvent::kCollectAttempt);
 
   if (user_data_dir_.empty())
     return nullptr;
+  LogCollectOnCrashEvent(CollectOnCrashEvent::kUserDataDirNotEmpty);
 
   base::FilePath stability_file =
       GetStabilityFileName(user_data_dir_, process_snapshot);
@@ -118,6 +120,7 @@
     // processes can be instrumented), or the stability file cannot be found.
     return nullptr;
   }
+  LogCollectOnCrashEvent(CollectOnCrashEvent::kPathExists);
 
   return CollectReport(stability_file);
 }
diff --git a/components/download/content/download_driver_impl.cc b/components/download/content/download_driver_impl.cc
index 0d1d281..17f6840 100644
--- a/components/download/content/download_driver_impl.cc
+++ b/components/download/content/download_driver_impl.cc
@@ -81,7 +81,9 @@
   return client_ && download_manager_;
 }
 
-void DownloadDriverImpl::Start(const DownloadParams& params) {
+void DownloadDriverImpl::Start(
+    const DownloadParams& params,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(!params.request_params.url.is_empty());
   DCHECK(!params.guid.empty());
   if (!download_manager_)
@@ -106,7 +108,8 @@
   download_url_params->set_method(params.request_params.method);
   download_url_params->set_file_path(file_dir_.AppendASCII(params.guid));
 
-  download_manager_->DownloadUrl(std::move(download_url_params));
+  download_manager_->DownloadUrl(std::move(download_url_params),
+                                 traffic_annotation);
 }
 
 void DownloadDriverImpl::Cancel(const std::string& guid) {
diff --git a/components/download/content/download_driver_impl.h b/components/download/content/download_driver_impl.h
index c7c5b1c..bc3c8074 100644
--- a/components/download/content/download_driver_impl.h
+++ b/components/download/content/download_driver_impl.h
@@ -12,6 +12,7 @@
 #include "components/download/public/download_params.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_manager.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace download {
 
@@ -34,7 +35,9 @@
   // DownloadDriver implementation.
   void Initialize(DownloadDriver::Client* client) override;
   bool IsReady() const override;
-  void Start(const DownloadParams& params) override;
+  void Start(
+      const DownloadParams& params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
   void Cancel(const std::string& guid) override;
   void Pause(const std::string& guid) override;
   void Resume(const std::string& guid) override;
diff --git a/components/download/internal/download_driver.h b/components/download/internal/download_driver.h
index 3c83807..704233ec 100644
--- a/components/download/internal/download_driver.h
+++ b/components/download/internal/download_driver.h
@@ -9,6 +9,7 @@
 
 #include "base/optional.h"
 #include "components/download/internal/driver_entry.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace base {
 class FilePath;
@@ -57,7 +58,9 @@
   virtual bool IsReady() const = 0;
 
   // Starts a new download.
-  virtual void Start(const DownloadParams& params) = 0;
+  virtual void Start(
+      const DownloadParams& params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
 
   // Cancels an existing download, all data associated with this download should
   // be removed.
diff --git a/components/download/internal/test/test_download_driver.cc b/components/download/internal/test/test_download_driver.cc
index 3f67629..beffa6a69d 100644
--- a/components/download/internal/test/test_download_driver.cc
+++ b/components/download/internal/test/test_download_driver.cc
@@ -54,7 +54,9 @@
   return is_ready_;
 }
 
-void TestDownloadDriver::Start(const DownloadParams& params) {
+void TestDownloadDriver::Start(
+    const DownloadParams& params,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DriverEntry entry;
   entry.guid = params.guid;
   entry.state = DriverEntry::State::IN_PROGRESS;
diff --git a/components/download/internal/test/test_download_driver.h b/components/download/internal/test/test_download_driver.h
index 010777a..5e540f65 100644
--- a/components/download/internal/test/test_download_driver.h
+++ b/components/download/internal/test/test_download_driver.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "components/download/internal/download_driver.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace download {
 namespace test {
@@ -33,7 +34,9 @@
   // DownloadDriver implementation.
   void Initialize(DownloadDriver::Client* client) override;
   bool IsReady() const override;
-  void Start(const DownloadParams& params) override;
+  void Start(
+      const DownloadParams& params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
   void Cancel(const std::string& guid) override;
   void Pause(const std::string& guid) override;
   void Resume(const std::string& guid) override;
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 273a742..7f1d352 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -16,6 +16,7 @@
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
+#include "ui/base/cursor/cursor_util.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/display/screen.h"
@@ -34,7 +35,16 @@
 namespace exo {
 namespace {
 
+// TODO(oshima): Some accessibility features, including large cursors, disable
+// hardware cursors. Ash does not support compositing for custom cursors, so it
+// replaces them with the default cursor. As a result, this scale has no effect
+// for now. See crbug.com/708378.
 const float kLargeCursorScale = 2.8f;
+
+// Scale at which cursor snapshot is captured. The resulting bitmap is scaled on
+// displays whose DSF does not match this scale.
+const float kCursorCaptureScale = 2.0f;
+
 const double kLocatedEventEpsilonSquared = 1.0 / (2000.0 * 2000.0);
 
 // Synthesized events typically lack floating point precision so to avoid
@@ -113,17 +123,14 @@
       // snapshot. Where in the tree is not important but we might as well use
       // the cursor container.
       WMHelper::GetInstance()
-          ->GetContainer(ash::kShellWindowId_MouseCursorContainer)
+          ->GetPrimaryDisplayContainer(ash::kShellWindowId_MouseCursorContainer)
           ->AddChild(surface_->window());
     }
     cursor_changed = true;
   }
 
-  // Update hotspot.
-  if (hotspot != hotspot_) {
-    hotspot_ = hotspot;
+  if (hotspot != hotspot_)
     cursor_changed = true;
-  }
 
   // Early out if cursor did not change.
   if (!cursor_changed)
@@ -132,10 +139,10 @@
   // If |surface_| is set then asynchronously capture a snapshot of cursor,
   // otherwise cancel pending capture and immediately set the cursor to "none".
   if (surface_) {
-    CaptureCursor();
+    CaptureCursor(hotspot);
   } else {
+    cursor_bitmap_.reset();
     cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
-    cursor_ = ui::CursorType::kNone;
     UpdateCursor();
   }
 }
@@ -251,7 +258,6 @@
   }
 
   last_event_type_ = event->type();
-  UpdateCursorScale();
 }
 
 void Pointer::OnScrollEvent(ui::ScrollEvent* event) {
@@ -263,7 +269,12 @@
 
 void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
   if (focus_)
-    UpdateCursorScale();
+    UpdateCursor();
+}
+
+void Pointer::OnCursorDisplayChanged(const display::Display& display) {
+  if (focus_)
+    UpdateCursor();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -275,7 +286,7 @@
 
   // Capture new cursor to reflect result of commit.
   if (focus_)
-    CaptureCursor();
+    CaptureCursor(hotspot_);
 }
 
 bool Pointer::IsSurfaceSynchronized() const {
@@ -307,62 +318,25 @@
   return delegate_->CanAcceptPointerEventsForSurface(target) ? target : nullptr;
 }
 
-void Pointer::UpdateCursorScale() {
-  DCHECK(focus_);
-
-  display::Screen* screen = display::Screen::GetScreen();
-  WMHelper* helper = WMHelper::GetInstance();
-
-  // Update cursor scale if the effective UI scale has changed.
-  display::Display display = screen->GetDisplayNearestWindow(focus_->window());
-  float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale();
-
-  if (display::Display::HasInternalDisplay()) {
-    float primary_device_scale_factor =
-        screen->GetPrimaryDisplay().device_scale_factor();
-    // The size of the cursor surface is the quotient of its physical size and
-    // the DSF of the primary display. The physical size is proportional to the
-    // DSF of the internal display. For external displays (and the internal
-    // display when secondary to a display with a different DSF), scale the
-    // cursor so its physical size matches with the single display case.
-    if (!display.IsInternal() ||
-        display.device_scale_factor() != primary_device_scale_factor) {
-      scale *= primary_device_scale_factor /
-               helper->GetDisplayInfo(display::Display::InternalDisplayId())
-                   .device_scale_factor();
-    }
-  }
-
-  if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
-    scale *= kLargeCursorScale;
-
-  if (scale != cursor_scale_) {
-    cursor_scale_ = scale;
-    if (surface_)
-      CaptureCursor();
-  }
-}
-
-void Pointer::CaptureCursor() {
+void Pointer::CaptureCursor(const gfx::Point& hotspot) {
   DCHECK(surface_);
   DCHECK(focus_);
 
-  // Set UI scale before submitting capture request.
-  surface_->window()->layer()->SetTransform(
-      gfx::GetScaleTransform(gfx::Point(), cursor_scale_));
-
-  float primary_device_scale_factor =
-      display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor();
+  // Surface size is in DIPs, while layer size is in pseudo-DIP units that
+  // depend on the DSF of the display mode. Scale the layer to capture the
+  // surface at a constant pixel size, regardless of the primary display's
+  // UI scale and display mode DSF.
+  display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
+  auto* helper = WMHelper::GetInstance();
+  float scale = helper->GetDisplayInfo(display.id()).GetEffectiveUIScale() *
+                kCursorCaptureScale / display.device_scale_factor();
+  surface_->window()->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale));
 
   std::unique_ptr<cc::CopyOutputRequest> request =
       cc::CopyOutputRequest::CreateBitmapRequest(
           base::Bind(&Pointer::OnCursorCaptured,
-                     cursor_capture_weak_ptr_factory_.GetWeakPtr(),
-                     gfx::ScaleToFlooredPoint(
-                         hotspot_,
-                         // |hotspot_| is in surface coordinate space so apply
-                         // both device scale and UI scale.
-                         cursor_scale_ * primary_device_scale_factor)));
+                     cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot));
+
   request->set_source(cursor_capture_source_id_);
   surface_->window()->layer()->RequestCopyOfOutput(std::move(request));
 }
@@ -372,19 +346,46 @@
   if (!focus_)
     return;
 
-  cursor_ = ui::CursorType::kNone;
-  if (!result->IsEmpty()) {
+  if (result->IsEmpty()) {
+    cursor_bitmap_.reset();
+  } else {
     DCHECK(result->HasBitmap());
-    std::unique_ptr<SkBitmap> bitmap = result->TakeBitmap();
+    cursor_bitmap_ = *result->TakeBitmap();
+    hotspot_ = hotspot;
+  }
+
+  UpdateCursor();
+}
+
+void Pointer::UpdateCursor() {
+  DCHECK(focus_);
+
+  if (cursor_bitmap_.drawsNothing()) {
+    cursor_ = ui::CursorType::kNone;
+  } else {
+    SkBitmap bitmap = cursor_bitmap_;
+    gfx::Point hotspot =
+        gfx::ScaleToFlooredPoint(hotspot_, kCursorCaptureScale);
+
+    auto* helper = WMHelper::GetInstance();
+    const display::Display& display = helper->GetCursorDisplay();
+    float scale = helper->GetDisplayInfo(display.id()).device_scale_factor() /
+                  kCursorCaptureScale;
+
+    if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
+      scale *= kLargeCursorScale;
+
+    ui::ScaleAndRotateCursorBitmapAndHotpoint(scale, display.rotation(),
+                                              &bitmap, &hotspot);
 
     ui::PlatformCursor platform_cursor;
 #if defined(USE_OZONE)
     // TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
     // and use that here instead of the current bitmap API. crbug.com/686600
     platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
-        *bitmap.get(), hotspot, cursor_scale_);
+        bitmap, hotspot, 0);
 #elif defined(USE_X11)
-    XcursorImage* image = ui::SkBitmapToXcursorImage(bitmap.get(), hotspot);
+    XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot);
     platform_cursor = ui::CreateReffedCustomXCursor(image);
 #endif
     cursor_ = ui::CursorType::kCustom;
@@ -396,12 +397,6 @@
 #endif
   }
 
-  UpdateCursor();
-}
-
-void Pointer::UpdateCursor() {
-  DCHECK(focus_);
-
   aura::Window* root_window = focus_->window()->GetRootWindow();
   if (!root_window)
     return;
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 07cf6bd..33ef21e 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -13,6 +13,7 @@
 #include "components/exo/surface_delegate.h"
 #include "components/exo/surface_observer.h"
 #include "components/exo/wm_helper.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/event_handler.h"
@@ -59,6 +60,7 @@
 
   // Overridden from WMHelper::CursorObserver:
   void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
+  void OnCursorDisplayChanged(const display::Display& display) override;
 
   // Overridden from SurfaceDelegate:
   void OnSurfaceCommit() override;
@@ -71,17 +73,14 @@
   // Returns the effective target for |event|.
   Surface* GetEffectiveTargetForEvent(ui::Event* event) const;
 
-  // Recompute cursor scale and update cursor if scale changed.
-  void UpdateCursorScale();
-
   // Asynchronously update the cursor by capturing a snapshot of |surface_|.
-  void CaptureCursor();
+  void CaptureCursor(const gfx::Point& hotspot);
 
   // Called when cursor snapshot has been captured.
   void OnCursorCaptured(const gfx::Point& hotspot,
                         std::unique_ptr<cc::CopyOutputResult> result);
 
-  // Update cursor to reflect the current value of |cursor_|.
+  // Update |cursor_| to |cursor_bitmap_| transformed for the current display.
   void UpdateCursor();
 
   // The delegate instance that all events are dispatched to.
@@ -96,12 +95,12 @@
   // The location of the pointer in the current focus surface.
   gfx::PointF location_;
 
-  // The scale applied to the cursor to compensate for the UI scale.
-  float cursor_scale_ = 1.0f;
-
   // The position of the pointer surface relative to the pointer location.
   gfx::Point hotspot_;
 
+  // Latest cursor snapshot.
+  SkBitmap cursor_bitmap_;
+
   // The current cursor.
   ui::Cursor cursor_;
 
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 534e506a..240197fe 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -1148,7 +1148,8 @@
   params.show_state = show_state;
   // Make shell surface a transient child if |parent_| has been set.
   params.parent =
-      parent_ ? parent_ : WMHelper::GetInstance()->GetContainer(container_);
+      parent_ ? parent_
+              : WMHelper::GetInstance()->GetPrimaryDisplayContainer(container_);
   params.bounds = gfx::Rect(origin_, gfx::Size());
   bool activatable = activatable_;
   // ShellSurfaces in system modal container are only activatable if input
diff --git a/components/exo/wm_helper.cc b/components/exo/wm_helper.cc
index 46faffd..a24aa2f 100644
--- a/components/exo/wm_helper.cc
+++ b/components/exo/wm_helper.cc
@@ -103,6 +103,11 @@
     observer.OnCursorSetChanged(cursor_set);
 }
 
+void WMHelper::NotifyCursorDisplayChanged(const display::Display& display) {
+  for (CursorObserver& observer : cursor_observers_)
+    observer.OnCursorDisplayChanged(display);
+}
+
 void WMHelper::NotifyMaximizeModeStarted() {
   for (MaximizeModeObserver& observer : maximize_mode_observers_)
     observer.OnMaximizeModeStarted();
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index 84245f6b..d68237c 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -14,6 +14,7 @@
 }
 
 namespace display {
+class Display;
 class ManagedDisplayInfo;
 }
 
@@ -48,6 +49,7 @@
    public:
     virtual void OnCursorVisibilityChanged(bool is_visible) {}
     virtual void OnCursorSetChanged(ui::CursorSetType cursor_set) {}
+    virtual void OnCursorDisplayChanged(const display::Display& display) {}
 
    protected:
     virtual ~CursorObserver() {}
@@ -98,12 +100,13 @@
   void RemoveDisplayConfigurationObserver(
       DisplayConfigurationObserver* observer);
 
-  virtual const display::ManagedDisplayInfo GetDisplayInfo(
+  virtual const display::ManagedDisplayInfo& GetDisplayInfo(
       int64_t display_id) const = 0;
-  virtual aura::Window* GetContainer(int container_id) = 0;
+  virtual aura::Window* GetPrimaryDisplayContainer(int container_id) = 0;
   virtual aura::Window* GetActiveWindow() const = 0;
   virtual aura::Window* GetFocusedWindow() const = 0;
   virtual ui::CursorSetType GetCursorSet() const = 0;
+  virtual const display::Display& GetCursorDisplay() const = 0;
   virtual void AddPreTargetHandler(ui::EventHandler* handler) = 0;
   virtual void PrependPreTargetHandler(ui::EventHandler* handler) = 0;
   virtual void RemovePreTargetHandler(ui::EventHandler* handler) = 0;
@@ -120,6 +123,7 @@
                            aura::Window* lost_focus);
   void NotifyCursorVisibilityChanged(bool is_visible);
   void NotifyCursorSetChanged(ui::CursorSetType cursor_set);
+  void NotifyCursorDisplayChanged(const display::Display& display);
   void NotifyMaximizeModeStarted();
   void NotifyMaximizeModeEnding();
   void NotifyMaximizeModeEnded();
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc
index 68965bd..a6d30c4 100644
--- a/components/exo/wm_helper_ash.cc
+++ b/components/exo/wm_helper_ash.cc
@@ -51,14 +51,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WMHelperAsh, private:
 
-const display::ManagedDisplayInfo WMHelperAsh::GetDisplayInfo(
+const display::ManagedDisplayInfo& WMHelperAsh::GetDisplayInfo(
     int64_t display_id) const {
   return ash::Shell::Get()->display_manager()->GetDisplayInfo(display_id);
 }
 
-aura::Window* WMHelperAsh::GetContainer(int container_id) {
-  // TODO(domlaskowski): Use target root window once multi-display support lands
-  // in ARC. See crbug.com/718627.
+aura::Window* WMHelperAsh::GetPrimaryDisplayContainer(int container_id) {
   return ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
                                   container_id);
 }
@@ -80,6 +78,15 @@
   return ash::Shell::Get()->cursor_manager()->GetCursorSet();
 }
 
+const display::Display& WMHelperAsh::GetCursorDisplay() const {
+  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+  if (ash::ShellPort::Get()->GetAshConfig() == ash::Config::MUS) {
+    static const display::Display display;
+    return display;
+  }
+  return ash::Shell::Get()->cursor_manager()->GetDisplay();
+}
+
 void WMHelperAsh::AddPreTargetHandler(ui::EventHandler* handler) {
   ash::Shell::Get()->AddPreTargetHandler(handler);
 }
@@ -126,6 +133,10 @@
   NotifyCursorSetChanged(cursor_set);
 }
 
+void WMHelperAsh::OnCursorDisplayChanged(const display::Display& display) {
+  NotifyCursorDisplayChanged(display);
+}
+
 void WMHelperAsh::OnMaximizeModeStarted() {
   NotifyMaximizeModeStarted();
 }
diff --git a/components/exo/wm_helper_ash.h b/components/exo/wm_helper_ash.h
index 340fdd4..9b9c7fa0 100644
--- a/components/exo/wm_helper_ash.h
+++ b/components/exo/wm_helper_ash.h
@@ -29,12 +29,13 @@
   ~WMHelperAsh() override;
 
   // Overridden from WMHelper:
-  const display::ManagedDisplayInfo GetDisplayInfo(
+  const display::ManagedDisplayInfo& GetDisplayInfo(
       int64_t display_id) const override;
-  aura::Window* GetContainer(int container_id) override;
+  aura::Window* GetPrimaryDisplayContainer(int container_id) override;
   aura::Window* GetActiveWindow() const override;
   aura::Window* GetFocusedWindow() const override;
   ui::CursorSetType GetCursorSet() const override;
+  const display::Display& GetCursorDisplay() const override;
   void AddPreTargetHandler(ui::EventHandler* handler) override;
   void PrependPreTargetHandler(ui::EventHandler* handler) override;
   void RemovePreTargetHandler(ui::EventHandler* handler) override;
@@ -54,6 +55,7 @@
   // Overridden from aura::client::CursorClientObserver:
   void OnCursorVisibilityChanged(bool is_visible) override;
   void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
+  void OnCursorDisplayChanged(const display::Display& display) override;
 
   // Overridden from ash::ShellObserver:
   void OnMaximizeModeStarted() override;
diff --git a/components/exo/wm_helper_mus.cc b/components/exo/wm_helper_mus.cc
index 64eebe87..99028b75 100644
--- a/components/exo/wm_helper_mus.cc
+++ b/components/exo/wm_helper_mus.cc
@@ -9,6 +9,7 @@
 #include "ui/aura/mus/focus_synchronizer.h"
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
+#include "ui/display/display.h"
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/views/mus/mus_client.h"
 #include "ui/wm/public/activation_client.h"
@@ -37,13 +38,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WMHelperMus, private:
 
-const display::ManagedDisplayInfo WMHelperMus::GetDisplayInfo(
+const display::ManagedDisplayInfo& WMHelperMus::GetDisplayInfo(
     int64_t display_id) const {
   // TODO(penghuang): Return real display info when it is supported in mus.
-  return display::ManagedDisplayInfo(display_id, "", false);
+  static const display::ManagedDisplayInfo info;
+  return info;
 }
 
-aura::Window* WMHelperMus::GetContainer(int container_id) {
+aura::Window* WMHelperMus::GetPrimaryDisplayContainer(int container_id) {
   NOTIMPLEMENTED();
   return nullptr;
 }
@@ -61,6 +63,13 @@
   return ui::CursorSetType::CURSOR_SET_NORMAL;
 }
 
+const display::Display& WMHelperMus::GetCursorDisplay() const {
+  NOTIMPLEMENTED();
+  // TODO(penghuang): Return real display when supported in mus.
+  static const display::Display display;
+  return display;
+}
+
 void WMHelperMus::AddPreTargetHandler(ui::EventHandler* handler) {
   aura::Env::GetInstance()->AddPreTargetHandler(handler);
 }
diff --git a/components/exo/wm_helper_mus.h b/components/exo/wm_helper_mus.h
index 4f1b9faa..017d33f 100644
--- a/components/exo/wm_helper_mus.h
+++ b/components/exo/wm_helper_mus.h
@@ -28,12 +28,13 @@
   ~WMHelperMus() override;
 
   // Overridden from WMHelper:
-  const display::ManagedDisplayInfo GetDisplayInfo(
+  const display::ManagedDisplayInfo& GetDisplayInfo(
       int64_t display_id) const override;
-  aura::Window* GetContainer(int container_id) override;
+  aura::Window* GetPrimaryDisplayContainer(int container_id) override;
   aura::Window* GetActiveWindow() const override;
   aura::Window* GetFocusedWindow() const override;
   ui::CursorSetType GetCursorSet() const override;
+  const display::Display& GetCursorDisplay() const override;
   void AddPreTargetHandler(ui::EventHandler* handler) override;
   void PrependPreTargetHandler(ui::EventHandler* handler) override;
   void RemovePreTargetHandler(ui::EventHandler* handler) override;
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
index 6910f40..66a3306 100644
--- a/components/ntp_snippets/features.cc
+++ b/components/ntp_snippets/features.cc
@@ -18,6 +18,7 @@
                                         &kBookmarkSuggestionsFeature,
                                         &kCategoryOrder,
                                         &kCategoryRanker,
+                                        &kContentSuggestionsPushFeature,
                                         &kForeignSessionsSuggestionsFeature,
                                         &kIncreasedVisibility,
                                         &kNotificationsFeature,
@@ -45,6 +46,9 @@
 const base::Feature kForeignSessionsSuggestionsFeature{
     "NTPForeignSessionsSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kContentSuggestionsPushFeature{
+    "ContentSuggestionsPush", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kPreferAmpUrlsFeature{"NTPPreferAmpUrls",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h
index 9946e7c2d..8295e88f 100644
--- a/components/ntp_snippets/features.h
+++ b/components/ntp_snippets/features.h
@@ -40,6 +40,9 @@
 // Feature to prefer AMP URLs over regular URLs when available.
 extern const base::Feature kPreferAmpUrlsFeature;
 
+// Feature to listen for GCM push updates from the server.
+extern const base::Feature kContentSuggestionsPushFeature;
+
 // Feature to choose a category ranker.
 extern const base::Feature kCategoryRanker;
 
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.cc b/components/password_manager/core/browser/password_reuse_detection_manager.cc
index dba2a52c..d4942acf 100644
--- a/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -37,9 +37,14 @@
     const GURL& main_frame_url) {
   main_frame_url_ = main_frame_url;
   input_characters_.clear();
+  reuse_on_this_page_was_found_ = false;
 }
 
 void PasswordReuseDetectionManager::OnKeyPressed(const base::string16& text) {
+  // Do not check reuse if it was already found on this page.
+  if (reuse_on_this_page_was_found_)
+    return;
+
   // Clear the buffer if last keystoke was more than kMaxInactivityTime ago.
   Time now = clock_->Now();
   if (!last_keystroke_time_.is_null() &&
@@ -72,6 +77,7 @@
     const std::string& legitimate_domain,
     int saved_passwords,
     int number_matches) {
+  reuse_on_this_page_was_found_ = true;
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
   if (password_manager_util::IsLoggingActive(client_)) {
     logger.reset(
@@ -80,9 +86,14 @@
                       legitimate_domain);
   }
 
-  metrics_util::LogPasswordReuse(
-      password.size(), saved_passwords, number_matches,
-      client_->GetPasswordManager()->IsPasswordFieldDetectedOnPage());
+  // PasswordManager could be nullptr in tests.
+  bool password_field_detected =
+      client_->GetPasswordManager()
+          ? client_->GetPasswordManager()->IsPasswordFieldDetectedOnPage()
+          : false;
+
+  metrics_util::LogPasswordReuse(password.size(), saved_passwords,
+                                 number_matches, password_field_detected);
 #if defined(SAFE_BROWSING_DB_LOCAL)
   // TODO(jialiul): After CSD whitelist being added to Android, we should gate
   // this by either SAFE_BROWSING_DB_LOCAL or SAFE_BROWSING_DB_REMOTE.
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.h b/components/password_manager/core/browser/password_reuse_detection_manager.h
index f6e1fd4..bad3370f 100644
--- a/components/password_manager/core/browser/password_reuse_detection_manager.h
+++ b/components/password_manager/core/browser/password_reuse_detection_manager.h
@@ -44,6 +44,7 @@
   base::Time last_keystroke_time_;
   // Used to retrieve the current time, in base::Time units.
   std::unique_ptr<base::Clock> clock_;
+  bool reuse_on_this_page_was_found_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordReuseDetectionManager);
 };
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc b/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
index 151c1fa..50e0c89 100644
--- a/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
@@ -130,6 +130,26 @@
   manager.OnKeyPressed(base::ASCIIToUTF16("2"));
 }
 
+// Verify that after reuse found, no reuse checking happens till next main frame
+// navigation.
+TEST_F(PasswordReuseDetectionManagerTest, NoReuseCheckingAfterReuseFound) {
+  EXPECT_CALL(client_, GetPasswordStore())
+      .WillRepeatedly(testing::Return(store_.get()));
+  PasswordReuseDetectionManager manager(&client_);
+
+  // Simulate that reuse found.
+  manager.OnReuseFound(base::string16(), std::string(), 0, 0);
+
+  // Expect no checking of reuse.
+  EXPECT_CALL(*store_, CheckReuse(_, _, _)).Times(0);
+  manager.OnKeyPressed(base::ASCIIToUTF16("1"));
+
+  // Expect that after main frame navigation checking is restored.
+  manager.DidNavigateMainFrame(GURL("https://www.example.com"));
+  EXPECT_CALL(*store_, CheckReuse(base::ASCIIToUTF16("1"), _, _));
+  manager.OnKeyPressed(base::ASCIIToUTF16("1"));
+}
+
 }  // namespace
 
 }  // namespace password_manager
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 5e093d1..27a36f0 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -364,4 +364,7 @@
   <message name="IDS_POLICY_RISK_TAG_GOOGLE_SHARING" desc="Title of a group/tag whose policies enable functionality that might share user data with trusted Google services.">
     Sharing with Google
   </message>
+  <message name="IDS_OPTIONS_CONTROLLED_SETTING_POLICY" desc="Text displayed in the controlled settings bubble when a setting's value is enforced by policy.">
+    This setting is enforced by your administrator.
+  </message>
 </grit-part>
diff --git a/components/resources/OWNERS b/components/resources/OWNERS
index f846201..1c722be6 100644
--- a/components/resources/OWNERS
+++ b/components/resources/OWNERS
@@ -20,8 +20,8 @@
 per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS
 per-file proximity_auth*=tengs@chromium.org
 per-file security_interstitials_resources.grdp=file://components/security_interstitials/OWNERS
-per-file supervised_user_error_page.grpd=file://components/supervised_user_error_page/OWNERS
-per-file sync_driver_resources.grdp=file:components/sync/OWNERS
+per-file supervised_user_error_page_resources.grdp=file://components/supervised_user_error_page/OWNERS
+per-file sync_driver_resources.grdp=file://components/sync/OWNERS
 per-file version_ui*=achuith@chromium.org
 per-file version_ui*=bauerb@chromium.org
 per-file version_ui*=dbeam@chromium.org
diff --git a/components/resources/autofill_scaled_resources.grdp b/components/resources/autofill_scaled_resources.grdp
index 5eedb43..f4c1b62 100644
--- a/components/resources/autofill_scaled_resources.grdp
+++ b/components/resources/autofill_scaled_resources.grdp
@@ -3,6 +3,7 @@
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_AMEX" file="autofill/amex.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_DINERS" file="autofill/diners.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_DISCOVER" file="autofill/discover.png" />
+  <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_ELO" file="autofill/elo.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_GENERIC" file="autofill/cc-generic.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_JCB" file="autofill/jcb.png" />
   <structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_MASTERCARD" file="autofill/mastercard.png" />
diff --git a/components/resources/default_100_percent/autofill/elo.png b/components/resources/default_100_percent/autofill/elo.png
new file mode 100644
index 0000000..346d0f4
--- /dev/null
+++ b/components/resources/default_100_percent/autofill/elo.png
Binary files differ
diff --git a/components/resources/default_200_percent/autofill/elo.png b/components/resources/default_200_percent/autofill/elo.png
new file mode 100644
index 0000000..ba88605
--- /dev/null
+++ b/components/resources/default_200_percent/autofill/elo.png
Binary files differ
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 27f8fa23..bc68d18 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -75,6 +75,7 @@
 using base::android::ScopedJavaLocalRef;
 using blink::WebContextMenuData;
 using blink::WebGestureEvent;
+using blink::WebContextMenuData;
 using blink::WebInputEvent;
 
 namespace content {
@@ -573,9 +574,13 @@
     Java_ContentViewCore_requestDisallowInterceptTouchEvent(env, obj);
 }
 
-bool ContentViewCoreImpl::ShowPastePopup(const ContextMenuParams& params) {
+bool ContentViewCoreImpl::ShowSelectionMenu(const ContextMenuParams& params) {
   // Display paste pop-up only when selection is empty and editable.
-  if (!(params.is_editable && params.selection_text.empty()))
+  const bool from_touch = params.source_type == ui::MENU_SOURCE_TOUCH ||
+                          params.source_type == ui::MENU_SOURCE_LONG_PRESS ||
+                          params.source_type == ui::MENU_SOURCE_TOUCH_HANDLE ||
+                          params.source_type == ui::MENU_SOURCE_STYLUS;
+  if (!from_touch || (!params.is_editable && params.selection_text.empty()))
     return false;
 
   RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
@@ -591,13 +596,21 @@
       !!(params.edit_flags & WebContextMenuData::kCanSelectAll);
   const bool can_edit_richly =
       !!(params.edit_flags & blink::WebContextMenuData::kCanEditRichly);
-
   int handle_height = GetRenderWidgetHostViewAndroid()->GetTouchHandleHeight();
-  Java_ContentViewCore_showPastePopup(
+  const bool is_password_type =
+      params.input_field_type ==
+      blink::WebContextMenuData::kInputFieldTypePassword;
+  const ScopedJavaLocalRef<jstring> jselected_text =
+      ConvertUTF16ToJavaString(env, params.selection_text);
+  const bool should_suggest = params.source_type == ui::MENU_SOURCE_TOUCH ||
+                              params.source_type == ui::MENU_SOURCE_LONG_PRESS;
+
+  Java_ContentViewCore_showSelectionMenu(
       env, obj, params.selection_rect.x(), params.selection_rect.y(),
       params.selection_rect.right(),
-      params.selection_rect.bottom() + handle_height, can_select_all,
-      can_edit_richly);
+      params.selection_rect.bottom() + handle_height, params.is_editable,
+      is_password_type, jselected_text, can_select_all, can_edit_richly,
+      should_suggest);
   return true;
 }
 
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index 51de3a2..1c22899a 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -56,7 +56,7 @@
   base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
   WebContents* GetWebContents() const override;
   ui::WindowAndroid* GetWindowAndroid() const override;
-  bool ShowPastePopup(const ContextMenuParams& params) override;
+  bool ShowSelectionMenu(const ContextMenuParams& params) override;
 
   void AddObserver(ContentViewCoreImplObserver* observer);
   void RemoveObserver(ContentViewCoreImplObserver* observer);
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index c4496e14..ab3b8c3 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -13,6 +13,7 @@
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/blob_handle.h"
 #include "content/public/browser/browser_context.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/origin.h"
 
@@ -158,7 +159,7 @@
   if (request_context_getter_) {
     // Start fetching the |initial_requests| immediately. At some point in the
     // future we may want a more elaborate scheduling mechanism here.
-    controller->Start(std::move(initial_requests));
+    controller->Start(std::move(initial_requests), NO_TRAFFIC_ANNOTATION_YET);
   }
 
   active_fetches_.insert(
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index 3f9ae19..950e43120 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -59,7 +59,9 @@
   base::WeakPtr<Core> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
 
   // Starts fetching the |request| with the download manager.
-  void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request) {
+  void StartRequest(
+      scoped_refptr<BackgroundFetchRequestInfo> request,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(request_context_);
     DCHECK(request);
@@ -108,7 +110,8 @@
                                                  weak_ptr_factory_.GetWeakPtr(),
                                                  std::move(request)));
 
-    download_manager->DownloadUrl(std::move(download_parameters));
+    download_manager->DownloadUrl(std::move(download_parameters),
+                                  traffic_annotation);
   }
 
   // DownloadItem::Observer overrides:
@@ -236,7 +239,8 @@
 BackgroundFetchJobController::~BackgroundFetchJobController() = default;
 
 void BackgroundFetchJobController::Start(
-    std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests) {
+    std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_LE(initial_requests.size(), kMaximumBackgroundFetchParallelRequests);
   DCHECK_EQ(state_, State::INITIALIZED);
@@ -244,16 +248,17 @@
   state_ = State::FETCHING;
 
   for (const auto& request : initial_requests)
-    StartRequest(request);
+    StartRequest(request, traffic_annotation);
 }
 
 void BackgroundFetchJobController::StartRequest(
-    scoped_refptr<BackgroundFetchRequestInfo> request) {
+    scoped_refptr<BackgroundFetchRequestInfo> request,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(state_, State::FETCHING);
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&Core::StartRequest, ui_core_ptr_, std::move(request)));
+  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                          base::Bind(&Core::StartRequest, ui_core_ptr_,
+                                     std::move(request), traffic_annotation));
 }
 
 void BackgroundFetchJobController::DidStartRequest(
@@ -285,7 +290,7 @@
 
   // If a |request| has been given, start downloading the file and bail.
   if (request) {
-    StartRequest(std::move(request));
+    StartRequest(std::move(request), NO_TRAFFIC_ANNOTATION_YET);
     return;
   }
 
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h
index 4c33c76..a6e598c 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.h
+++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -17,6 +17,7 @@
 #include "content/common/background_fetch/background_fetch_types.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class URLRequestContextGetter;
@@ -49,7 +50,8 @@
   // Starts fetching the |initial_fetches|. The controller will continue to
   // fetch new content until all requests have been handled.
   void Start(
-      std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests);
+      std::vector<scoped_refptr<BackgroundFetchRequestInfo>> initial_requests,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Updates the representation of this Background Fetch in the user interface
   // to match the given |title|.
@@ -73,7 +75,8 @@
   class Core;
 
   // Requests the download manager to start fetching |request|.
-  void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request);
+  void StartRequest(scoped_refptr<BackgroundFetchRequestInfo> request,
+                    const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Called when the given |request| has started fetching, after having been
   // assigned the |download_guid| by the download system.
diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
index d2678142..55853a3 100644
--- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/fake_download_item.h"
 #include "content/public/test/mock_download_manager.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -148,7 +149,8 @@
   EXPECT_EQ(controller->state(),
             BackgroundFetchJobController::State::INITIALIZED);
 
-  controller->Start(initial_requests /* deliberate copy */);
+  controller->Start(initial_requests /* deliberate copy */,
+                    TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(controller->state(), BackgroundFetchJobController::State::FETCHING);
 
   // Mark the single download item as finished, completing the job.
@@ -192,7 +194,8 @@
     base::RunLoop run_loop;
     job_completed_closure_ = run_loop.QuitClosure();
 
-    controller->Start(initial_requests /* deliberate copy */);
+    controller->Start(initial_requests /* deliberate copy */,
+                      TRAFFIC_ANNOTATION_FOR_TESTS);
     EXPECT_EQ(controller->state(),
               BackgroundFetchJobController::State::FETCHING);
 
@@ -223,7 +226,8 @@
     base::RunLoop run_loop;
     job_completed_closure_ = run_loop.QuitClosure();
 
-    controller->Start(initial_requests /* deliberate copy */);
+    controller->Start(initial_requests /* deliberate copy */,
+                      TRAFFIC_ANNOTATION_FOR_TESTS);
     EXPECT_EQ(controller->state(),
               BackgroundFetchJobController::State::FETCHING);
 
diff --git a/content/browser/background_fetch/background_fetch_test_base.cc b/content/browser/background_fetch/background_fetch_test_base.cc
index 9314f19..f925c74 100644
--- a/content/browser/background_fetch/background_fetch_test_base.cc
+++ b/content/browser/background_fetch/background_fetch_test_base.cc
@@ -125,7 +125,9 @@
 
   // Called when the Background Fetch system starts a download, all information
   // for which is contained in the |params|.
-  void DownloadUrl(std::unique_ptr<DownloadUrlParameters> params) override {
+  void DownloadUrl(
+      std::unique_ptr<DownloadUrlParameters> params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     auto iter = registered_responses_.find(params->url());
     if (iter == registered_responses_.end())
       return;
diff --git a/content/browser/devtools/protocol/service_worker_handler.cc b/content/browser/devtools/protocol/service_worker_handler.cc
index 242d33e..31abe59 100644
--- a/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/content/browser/devtools/protocol/service_worker_handler.cc
@@ -371,10 +371,13 @@
         protocol::Array<std::string>::create();
     for (const auto& client : version.clients) {
       if (client.second.type == SERVICE_WORKER_PROVIDER_FOR_WINDOW) {
-        RenderFrameHostImpl* render_frame_host = RenderFrameHostImpl::FromID(
-            client.second.process_id, client.second.route_id);
+        // PlzNavigate: a navigation may not yet be associated with a
+        // RenderFrameHost. Use the |web_contents_getter| instead.
         WebContents* web_contents =
-            WebContents::FromRenderFrameHost(render_frame_host);
+            client.second.web_contents_getter
+                ? client.second.web_contents_getter.Run()
+                : WebContents::FromRenderFrameHost(RenderFrameHostImpl::FromID(
+                      client.second.process_id, client.second.route_id));
         // There is a possibility that the frame is already deleted
         // because of the thread hopping.
         if (!web_contents)
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index a5debca..b2a20a7 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -63,6 +63,7 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "ppapi/features/features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -2347,7 +2348,8 @@
       DownloadUrlParameters::CreateForWebContentsMainFrame(
           shell()->web_contents(), origin_two.GetURL("/bar")));
   std::unique_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
-  DownloadManagerForShell(shell())->DownloadUrl(std::move(download_parameters));
+  DownloadManagerForShell(shell())->DownloadUrl(std::move(download_parameters),
+                                                TRAFFIC_ANNOTATION_FOR_TESTS);
   observer->WaitForFinished();
 
   // Get the important info from other threads and check it.
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index ecd6d88..238508c 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -51,6 +51,7 @@
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/log/net_log_source_type.h"
 #include "net/log/net_log_with_source.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context.h"
 #include "storage/browser/blob/blob_url_request_job_factory.h"
 #include "url/origin.h"
@@ -66,7 +67,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   std::unique_ptr<net::URLRequest> url_request =
-      DownloadRequestCore::CreateRequestOnIOThread(download_id, params.get());
+      DownloadRequestCore::CreateRequestOnIOThread(download_id, params.get(),
+                                                   NO_TRAFFIC_ANNOTATION_YET);
   std::unique_ptr<storage::BlobDataHandle> blob_data_handle =
       params->GetBlobDataHandle();
   if (blob_data_handle) {
@@ -606,7 +608,8 @@
 }
 
 void DownloadManagerImpl::DownloadUrl(
-    std::unique_ptr<DownloadUrlParameters> params) {
+    std::unique_ptr<DownloadUrlParameters> params,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   if (params->post_id() >= 0) {
     // Check this here so that the traceback is more useful.
     DCHECK(params->prefer_cache());
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index e9b13f6..23e6ba7 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -27,6 +27,7 @@
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/download_url_parameters.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class NetLog;
@@ -79,7 +80,9 @@
       const base::Callback<bool(const GURL&)>& url_filter,
       base::Time remove_begin,
       base::Time remove_end) override;
-  void DownloadUrl(std::unique_ptr<DownloadUrlParameters> params) override;
+  void DownloadUrl(
+      std::unique_ptr<DownloadUrlParameters> params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
   content::DownloadItem* CreateDownloadItem(
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index fef2ca6..34783e6 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -115,7 +115,8 @@
 // static
 std::unique_ptr<net::URLRequest> DownloadRequestCore::CreateRequestOnIOThread(
     uint32_t download_id,
-    DownloadUrlParameters* params) {
+    DownloadUrlParameters* params,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(download_id == DownloadItem::kInvalidId ||
          !params->content_initiated())
@@ -128,7 +129,8 @@
   std::unique_ptr<net::URLRequest> request(
       params->url_request_context_getter()
           ->GetURLRequestContext()
-          ->CreateRequest(params->url(), net::DEFAULT_PRIORITY, nullptr));
+          ->CreateRequest(params->url(), net::DEFAULT_PRIORITY, nullptr,
+                          traffic_annotation));
   request->set_method(params->method());
 
   if (!params->post_body().empty()) {
diff --git a/content/browser/download/download_request_core.h b/content/browser/download/download_request_core.h
index fc2ccd2..e2a9f80 100644
--- a/content/browser/download/download_request_core.h
+++ b/content/browser/download/download_request_core.h
@@ -19,6 +19,7 @@
 #include "content/public/browser/download_save_info.h"
 #include "content/public/browser/download_url_parameters.h"
 #include "device/wake_lock/public/interfaces/wake_lock_service.mojom.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace net {
 class HttpResponseHeaders;
@@ -105,7 +106,8 @@
 
   static std::unique_ptr<net::URLRequest> CreateRequestOnIOThread(
       uint32_t download_id,
-      DownloadUrlParameters* params);
+      DownloadUrlParameters* params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Size of the buffer used between the DownloadRequestCore and the
   // downstream receiver of its output.
diff --git a/content/browser/download/download_request_core_unittest.cc b/content/browser/download/download_request_core_unittest.cc
index f2eba00..2be6a58 100644
--- a/content/browser/download/download_request_core_unittest.cc
+++ b/content/browser/download/download_request_core_unittest.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/download_url_parameters.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/http/http_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -47,7 +48,7 @@
 
   void CreateRequestOnIOThread(DownloadUrlParameters* params) {
     url_request_ = DownloadRequestCore::CreateRequestOnIOThread(
-        DownloadItem::kInvalidId, params);
+        DownloadItem::kInvalidId, params, TRAFFIC_ANNOTATION_FOR_TESTS);
     DCHECK(url_request_.get());
   }
 
diff --git a/content/browser/download/download_worker.cc b/content/browser/download/download_worker.cc
index 5eff1cf..c1fea18 100644
--- a/content/browser/download/download_worker.cc
+++ b/content/browser/download/download_worker.cc
@@ -7,6 +7,7 @@
 #include "content/browser/download/download_create_info.h"
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "content/public/browser/web_contents.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace content {
 namespace {
@@ -38,8 +39,8 @@
   // Build the URLRequest, BlobDataHandle is hold in original request for image
   // download.
   std::unique_ptr<net::URLRequest> url_request =
-      DownloadRequestCore::CreateRequestOnIOThread(DownloadItem::kInvalidId,
-                                                   params.get());
+      DownloadRequestCore::CreateRequestOnIOThread(
+          DownloadItem::kInvalidId, params.get(), NO_TRAFFIC_ANNOTATION_YET);
 
   return std::unique_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread>(
       UrlDownloader::BeginDownload(delegate, std::move(url_request),
diff --git a/content/browser/download/drag_download_file.cc b/content/browser/download/drag_download_file.cc
index 40c76535..88b159e 100644
--- a/content/browser/download/drag_download_file.cc
+++ b/content/browser/download/drag_download_file.cc
@@ -20,6 +20,7 @@
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_save_info.h"
 #include "content/public/browser/download_url_parameters.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace content {
 
@@ -77,7 +78,7 @@
     params->set_file_path(file_path);
     params->set_file(std::move(file));  // Nulls file.
     BrowserContext::GetDownloadManager(web_contents_->GetBrowserContext())
-        ->DownloadUrl(std::move(params));
+        ->DownloadUrl(std::move(params), NO_TRAFFIC_ANNOTATION_YET);
   }
 
   void Cancel() {
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index 9ce4131..ac1b31f 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -135,7 +135,8 @@
   RenderProcessHostWatcher crash_observer(
       shell()->web_contents(),
       RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-  NavigateToURL(shell(), GURL(kChromeUICrashURL));
+  ASSERT_TRUE(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->Shutdown(0, true));
   crash_observer.Wait();
 
   // The frame tree should be cleared.
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index bbbb37d..42dde36 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -30,6 +30,7 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/cookie_options.h"
 #include "net/cookies/cookie_store.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ppapi/features/features.h"
@@ -89,7 +90,8 @@
   DownloadManager* download_manager =
       BrowserContext::GetDownloadManager(browser_context);
   RecordDownloadSource(INITIATED_BY_RENDERER);
-  download_manager->DownloadUrl(std::move(parameters));
+  download_manager->DownloadUrl(std::move(parameters),
+                                NO_TRAFFIC_ANNOTATION_YET);
 }
 
 // Common functionality for converting a sync renderer message to a callback
diff --git a/content/browser/indexed_db/indexed_db_internals_ui.cc b/content/browser/indexed_db/indexed_db_internals_ui.cc
index 8e304fa..4545865 100644
--- a/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/common/url_constants.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "storage/common/database/database_identifier.h"
 #include "third_party/zlib/google/zip.h"
 #include "ui/base/text/bytes_formatting.h"
@@ -299,7 +300,7 @@
 
   BrowserContext* context = web_contents->GetBrowserContext();
   BrowserContext::GetDownloadManager(context)->DownloadUrl(
-      std::move(dl_params));
+      std::move(dl_params), NO_TRAFFIC_ANNOTATION_YET);
 }
 
 // The entire purpose of this class is to delete the temp file after
diff --git a/content/browser/loader/resource_scheduler.h b/content/browser/loader/resource_scheduler.h
index 4ebc7341..9e112298 100644
--- a/content/browser/loader/resource_scheduler.h
+++ b/content/browser/loader/resource_scheduler.h
@@ -109,12 +109,6 @@
                            net::RequestPriority new_priority);
 
  private:
-  // Returns the maximum number of delayable requests to all be in-flight at
-  // any point in time (across all hosts).
-  size_t max_num_delayable_requests() const {
-    return max_num_delayable_requests_;
-  }
-
   class RequestQueue;
   class ScheduledResourceRequest;
   struct RequestPriorityParams;
@@ -138,7 +132,6 @@
   Client* GetClient(int child_id, int route_id);
 
   ClientMap client_map_;
-  size_t max_num_delayable_requests_;
   RequestSet unowned_requests_;
 
   // True if requests to servers that support priorities (e.g., H2/QUIC) can
diff --git a/content/browser/loader/upload_progress_tracker.cc b/content/browser/loader/upload_progress_tracker.cc
index 6633e61..f9fe05ba0 100644
--- a/content/browser/loader/upload_progress_tracker.cc
+++ b/content/browser/loader/upload_progress_tracker.cc
@@ -19,7 +19,7 @@
     const tracked_objects::Location& location,
     UploadProgressReportCallback report_progress,
     net::URLRequest* request,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
     : request_(request), report_progress_(std::move(report_progress)) {
   DCHECK(report_progress_);
 
@@ -40,6 +40,11 @@
   progress_timer_.Stop();
 }
 
+// static
+base::TimeDelta UploadProgressTracker::GetUploadProgressIntervalForTesting() {
+  return kUploadProgressInterval;
+}
+
 base::TimeTicks UploadProgressTracker::GetCurrentTime() const {
   return base::TimeTicks::Now();
 }
diff --git a/content/browser/loader/upload_progress_tracker.h b/content/browser/loader/upload_progress_tracker.h
index 6840f5a6..236ced27 100644
--- a/content/browser/loader/upload_progress_tracker.h
+++ b/content/browser/loader/upload_progress_tracker.h
@@ -10,17 +10,13 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "content/common/content_export.h"
 #include "net/base/upload_progress.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace tracked_objects {
 class Location;
 }
@@ -41,13 +37,15 @@
   UploadProgressTracker(const tracked_objects::Location& location,
                         UploadProgressReportCallback report_progress,
                         net::URLRequest* request,
-                        scoped_refptr<base::SingleThreadTaskRunner>
-                            task_runner = base::ThreadTaskRunnerHandle::Get());
+                        scoped_refptr<base::SequencedTaskRunner> task_runner =
+                            base::SequencedTaskRunnerHandle::Get());
   ~UploadProgressTracker();
 
   void OnAckReceived();
   void OnUploadCompleted();
 
+  static base::TimeDelta GetUploadProgressIntervalForTesting();
+
  private:
   // Overridden by tests to use a fake time and progress.
   virtual base::TimeTicks GetCurrentTime() const;
diff --git a/content/browser/loader/upload_progress_tracker_unittest.cc b/content/browser/loader/upload_progress_tracker_unittest.cc
index cf556db..363ae990 100644
--- a/content/browser/loader/upload_progress_tracker_unittest.cc
+++ b/content/browser/loader/upload_progress_tracker_unittest.cc
@@ -9,7 +9,8 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "net/base/upload_progress.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -54,13 +55,13 @@
 class UploadProgressTrackerTest : public ::testing::Test {
  public:
   UploadProgressTrackerTest()
-      : task_runner_(new base::TestSimpleTaskRunner),
+      : task_runner_handle_(mock_task_runner_),
         upload_progress_tracker_(
             FROM_HERE,
             base::BindRepeating(
                 &UploadProgressTrackerTest::OnUploadProgressReported,
                 base::Unretained(this)),
-            task_runner_) {}
+            mock_task_runner_) {}
 
  private:
   void OnUploadProgressReported(const net::UploadProgress& progress) {
@@ -74,7 +75,12 @@
   int64_t reported_position_ = 0;
   int64_t reported_total_size_ = 0;
 
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  // Mocks the current thread's task runner which will also be used as the
+  // UploadProgressTracker's task runner.
+  scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_ =
+      new base::TestMockTimeTaskRunner;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
+
   TestingUploadProgressTracker upload_progress_tracker_;
 
   DISALLOW_COPY_AND_ASSIGN(UploadProgressTrackerTest);
@@ -85,7 +91,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(500, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -94,7 +101,8 @@
 
   // The second timer task does nothing, since the first report didn't send the
   // ACK.
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
 }
 
@@ -103,7 +111,8 @@
 
   // UploadProgressTracker does nothing on the empty upload content.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(0, report_count_);
 }
 
@@ -112,7 +121,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(500, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -122,7 +132,8 @@
   // The second time doesn't call ReportUploadProgress since there's no
   // progress.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
 }
 
@@ -131,7 +142,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(999, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -142,7 +154,8 @@
   // The second timer task calls ReportUploadProgress for reporting the
   // completion.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(2, report_count_);
   EXPECT_EQ(1000, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -153,7 +166,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(500, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -164,7 +178,8 @@
   // The second timer task calls ReportUploadProgress since the progress is
   // big enough to report.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(2, report_count_);
   EXPECT_EQ(750, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -175,7 +190,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(500, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -186,7 +202,8 @@
   // The second timer task doesn't call ReportUploadProgress since the progress
   // is too small to report it.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
 
   upload_progress_tracker_.set_current_time(base::TimeTicks::Now() +
@@ -195,7 +212,8 @@
   // The third timer task calls ReportUploadProgress since it's been long time
   // from the last report.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(2, report_count_);
   EXPECT_EQ(501, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -206,7 +224,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(500, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -217,7 +236,8 @@
   // The second timer task doesn't call ReportUploadProgress since the progress
   // was rewound.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
 
   upload_progress_tracker_.set_current_time(base::TimeTicks::Now() +
@@ -226,7 +246,8 @@
   // Even after a good amount of time passed, the rewound progress should not be
   // reported.
   EXPECT_EQ(1, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
 }
 
@@ -235,7 +256,8 @@
 
   // The first timer task calls ReportUploadProgress.
   EXPECT_EQ(0, report_count_);
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(1, report_count_);
   EXPECT_EQ(500, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
@@ -248,9 +270,10 @@
   EXPECT_EQ(1000, reported_position_);
   EXPECT_EQ(1000, reported_total_size_);
 
-  task_runner_->RunPendingTasks();
+  mock_task_runner_->FastForwardBy(
+      UploadProgressTracker::GetUploadProgressIntervalForTesting());
   EXPECT_EQ(2, report_count_);
-  EXPECT_FALSE(task_runner_->HasPendingTask());
+  EXPECT_FALSE(mock_task_runner_->HasPendingTask());
 }
 
 }  // namespace context
diff --git a/content/browser/renderer_host/input/stylus_text_selector.cc b/content/browser/renderer_host/input/stylus_text_selector.cc
index 65f8afbf..18285e64 100644
--- a/content/browser/renderer_host/input/stylus_text_selector.cc
+++ b/content/browser/renderer_host/input/stylus_text_selector.cc
@@ -83,7 +83,7 @@
     case MotionEvent::ACTION_CANCEL:
       if (drag_state_ == DRAGGING_WITH_BUTTON_PRESSED ||
           drag_state_ == DRAGGING_WITH_BUTTON_RELEASED)
-        client_->OnStylusSelectEnd();
+        client_->OnStylusSelectEnd(event.GetX(), event.GetY());
       drag_state_ = NO_DRAG;
       break;
 
diff --git a/content/browser/renderer_host/input/stylus_text_selector.h b/content/browser/renderer_host/input/stylus_text_selector.h
index 1c1a9d1..96142c3 100644
--- a/content/browser/renderer_host/input/stylus_text_selector.h
+++ b/content/browser/renderer_host/input/stylus_text_selector.h
@@ -31,7 +31,7 @@
   // (x0, y0) and (x1, y1) indicate the bounds of the initial selection.
   virtual void OnStylusSelectBegin(float x0, float y0, float x1, float y1) = 0;
   virtual void OnStylusSelectUpdate(float x, float y) = 0;
-  virtual void OnStylusSelectEnd() = 0;
+  virtual void OnStylusSelectEnd(float x, float y) = 0;
   virtual void OnStylusSelectTap(base::TimeTicks time, float x, float y) = 0;
 };
 
diff --git a/content/browser/renderer_host/input/stylus_text_selector_unittest.cc b/content/browser/renderer_host/input/stylus_text_selector_unittest.cc
index 41be095..9097947 100644
--- a/content/browser/renderer_host/input/stylus_text_selector_unittest.cc
+++ b/content/browser/renderer_host/input/stylus_text_selector_unittest.cc
@@ -50,7 +50,9 @@
     event_log_.push_back(ss.str());
   }
 
-  void OnStylusSelectEnd() override { event_log_.push_back("End"); }
+  void OnStylusSelectEnd(float x, float y) override {
+    event_log_.push_back("End");
+  }
 
   void OnStylusSelectTap(base::TimeTicks time, float x, float y) override {
     event_log_.push_back("Tap");
diff --git a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
index 8fb31d74..199df16 100644
--- a/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
+++ b/content/browser/renderer_host/input/touch_selection_controller_client_aura.cc
@@ -170,6 +170,12 @@
     UpdateQuickMenu();
     return true;
   }
+
+  const bool from_touch = params.source_type == ui::MENU_SOURCE_LONG_PRESS ||
+                          params.source_type == ui::MENU_SOURCE_TOUCH;
+  if (from_touch && !params.selection_text.empty())
+    return true;
+
   rwhva_->selection_controller()->HideAndDisallowShowingAutomatically();
   return false;
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 8eb52bed..df540b7 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1866,10 +1866,11 @@
     host_->MoveCaret(point);
 }
 
-void RenderWidgetHostViewAndroid::ShowContextMenuAtTouchHandle(
-    const gfx::Point& point) {
+void RenderWidgetHostViewAndroid::ShowContextMenuAtPoint(
+    const gfx::Point& point,
+    ui::MenuSourceType source_type) {
   if (host_)
-    host_->ShowContextMenuAtPoint(point, ui::MENU_SOURCE_TOUCH_HANDLE);
+    host_->ShowContextMenuAtPoint(point, source_type);
 }
 
 void RenderWidgetHostViewAndroid::DismissTextHandles() {
@@ -2173,6 +2174,10 @@
   MoveRangeSelectionExtent(gfx::PointF(x, y));
 }
 
+void RenderWidgetHostViewAndroid::OnStylusSelectEnd(float x, float y) {
+  ShowContextMenuAtPoint(gfx::Point(x, y), ui::MENU_SOURCE_STYLUS);
+}
+
 void RenderWidgetHostViewAndroid::OnStylusSelectTap(base::TimeTicks time,
                                                     float x,
                                                     float y) {
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 25c9185..b1816871 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -35,6 +35,7 @@
 #include "ui/android/view_android.h"
 #include "ui/android/view_client.h"
 #include "ui/android/window_android_observer.h"
+#include "ui/base/ui_base_types.h"
 #include "ui/events/gesture_detection/filtered_gesture_provider.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/vector2d_f.h"
@@ -210,7 +211,7 @@
   // StylusTextSelectorClient implementation.
   void OnStylusSelectBegin(float x0, float y0, float x1, float y1) override;
   void OnStylusSelectUpdate(float x, float y) override;
-  void OnStylusSelectEnd() override {};
+  void OnStylusSelectEnd(float x, float y) override;
   void OnStylusSelectTap(base::TimeTicks time, float x, float y) override;
 
   // ui::TouchSelectionControllerClient implementation.
@@ -264,7 +265,7 @@
   bool HasValidFrame() const;
 
   void MoveCaret(const gfx::Point& point);
-  void ShowContextMenuAtTouchHandle(const gfx::Point& point);
+  void ShowContextMenuAtPoint(const gfx::Point& point, ui::MenuSourceType);
   void DismissTextHandles();
   void SetTextHandlesTemporarilyHidden(bool hidden);
   void OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip);
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 0a9c1c3..63b362f2 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -664,6 +664,7 @@
 
   void TimeoutWorkerOnIOThread() {
     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+    EXPECT_TRUE(version_->timeout_timer_.IsRunning());
     version_->SimulatePingTimeoutForTesting();
   }
 
@@ -1177,7 +1178,6 @@
 
   // Simulate execution timeout. Use a delay to prevent killing the worker
   // before it's started execution.
-  EXPECT_TRUE(version_->timeout_timer_.IsRunning());
   RunOnIOThreadWithDelay(
       base::Bind(&self::TimeoutWorkerOnIOThread, base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(100));
@@ -1211,7 +1211,6 @@
 
   // Simulate execution timeout. Use a delay to prevent killing the worker
   // before it's started execution.
-  EXPECT_TRUE(version_->timeout_timer_.IsRunning());
   RunOnIOThreadWithDelay(
       base::Bind(&self::TimeoutWorkerOnIOThread, base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(100));
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index 407b6dcb..72e7e6d 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -846,11 +846,11 @@
     ServiceWorkerProviderHost* provider_host) {
   if (!observer_list_)
     return;
-  observer_list_->Notify(FROM_HERE,
-                         &ServiceWorkerContextObserver::OnControlleeAdded,
-                         version->version_id(), provider_host->client_uuid(),
-                         provider_host->process_id(), provider_host->route_id(),
-                         provider_host->provider_type());
+  observer_list_->Notify(
+      FROM_HERE, &ServiceWorkerContextObserver::OnControlleeAdded,
+      version->version_id(), provider_host->client_uuid(),
+      provider_host->process_id(), provider_host->route_id(),
+      provider_host->web_contents_getter(), provider_host->provider_type());
 }
 
 void ServiceWorkerContextCore::OnControlleeRemoved(
diff --git a/content/browser/service_worker/service_worker_context_observer.h b/content/browser/service_worker/service_worker_context_observer.h
index 65361d7..d0564d4 100644
--- a/content/browser/service_worker/service_worker_context_observer.h
+++ b/content/browser/service_worker/service_worker_context_observer.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "base/callback.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_info.h"
@@ -72,11 +73,14 @@
                                       int process_id,
                                       int thread_id,
                                       const ConsoleMessage& message) {}
-  virtual void OnControlleeAdded(int64_t version_id,
-                                 const std::string& uuid,
-                                 int process_id,
-                                 int route_id,
-                                 ServiceWorkerProviderType type) {}
+  // |web_contents_getter| is only set in PlzNavigate.
+  virtual void OnControlleeAdded(
+      int64_t version_id,
+      const std::string& uuid,
+      int process_id,
+      int route_id,
+      const base::Callback<WebContents*(void)>& web_contents_getter,
+      ServiceWorkerProviderType type) {}
   virtual void OnControlleeRemoved(int64_t version_id,
                                    const std::string& uuid) {}
   virtual void OnRegistrationStored(int64_t registration_id,
diff --git a/content/browser/service_worker/service_worker_context_watcher.cc b/content/browser/service_worker/service_worker_context_watcher.cc
index 3dd810a..98d4fc2 100644
--- a/content/browser/service_worker/service_worker_context_watcher.cc
+++ b/content/browser/service_worker/service_worker_context_watcher.cc
@@ -276,13 +276,14 @@
     const std::string& uuid,
     int process_id,
     int route_id,
+    const base::Callback<WebContents*(void)>& web_contents_getter,
     ServiceWorkerProviderType type) {
   auto it = version_info_map_.find(version_id);
   if (it == version_info_map_.end())
     return;
   ServiceWorkerVersionInfo* version = it->second.get();
-  version->clients[uuid] =
-      ServiceWorkerVersionInfo::ClientInfo(process_id, route_id, type);
+  version->clients[uuid] = ServiceWorkerVersionInfo::ClientInfo(
+      process_id, route_id, web_contents_getter, type);
   SendVersionInfo(*version);
 }
 
diff --git a/content/browser/service_worker/service_worker_context_watcher.h b/content/browser/service_worker/service_worker_context_watcher.h
index afca96b2..189bf84 100644
--- a/content/browser/service_worker/service_worker_context_watcher.h
+++ b/content/browser/service_worker/service_worker_context_watcher.h
@@ -90,11 +90,13 @@
                               int process_id,
                               int thread_id,
                               const ConsoleMessage& message) override;
-  void OnControlleeAdded(int64_t version_id,
-                         const std::string& uuid,
-                         int process_id,
-                         int route_id,
-                         ServiceWorkerProviderType type) override;
+  void OnControlleeAdded(
+      int64_t version_id,
+      const std::string& uuid,
+      int process_id,
+      int route_id,
+      const base::Callback<WebContents*(void)>& web_contents_getter,
+      ServiceWorkerProviderType type) override;
   void OnControlleeRemoved(int64_t version_id,
                            const std::string& uuid) override;
   void OnRegistrationStored(int64_t registration_id,
diff --git a/content/browser/service_worker/service_worker_info.cc b/content/browser/service_worker/service_worker_info.cc
index 8ba8ac2..ba62c7e 100644
--- a/content/browser/service_worker/service_worker_info.cc
+++ b/content/browser/service_worker/service_worker_info.cc
@@ -6,6 +6,7 @@
 
 #include "content/browser/service_worker/embedded_worker_status.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/child_process_host.h"
 #include "ipc/ipc_message.h"
 
@@ -14,13 +15,21 @@
 ServiceWorkerVersionInfo::ClientInfo::ClientInfo()
     : ClientInfo(ChildProcessHost::kInvalidUniqueID,
                  MSG_ROUTING_NONE,
+                 base::Callback<WebContents*(void)>(),
                  SERVICE_WORKER_PROVIDER_UNKNOWN) {}
 
-ServiceWorkerVersionInfo::ClientInfo::ClientInfo(int process_id,
-                                                 int route_id,
-                                                 ServiceWorkerProviderType type)
-    : process_id(process_id), route_id(route_id), type(type) {
-}
+ServiceWorkerVersionInfo::ClientInfo::ClientInfo(
+    int process_id,
+    int route_id,
+    const base::Callback<WebContents*(void)>& web_contents_getter,
+    ServiceWorkerProviderType type)
+    : process_id(process_id),
+      route_id(route_id),
+      web_contents_getter(web_contents_getter),
+      type(type) {}
+
+ServiceWorkerVersionInfo::ClientInfo::ClientInfo(
+    const ServiceWorkerVersionInfo::ClientInfo& other) = default;
 
 ServiceWorkerVersionInfo::ClientInfo::~ClientInfo() {
 }
diff --git a/content/browser/service_worker/service_worker_info.h b/content/browser/service_worker/service_worker_info.h
index 4616575..6145c27 100644
--- a/content/browser/service_worker/service_worker_info.h
+++ b/content/browser/service_worker/service_worker_info.h
@@ -9,6 +9,7 @@
 
 #include <vector>
 
+#include "base/callback.h"
 #include "base/time/time.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/common/content_export.h"
@@ -24,10 +25,16 @@
   struct CONTENT_EXPORT ClientInfo {
    public:
     ClientInfo();
-    ClientInfo(int process_id, int route_id, ServiceWorkerProviderType type);
+    ClientInfo(int process_id,
+               int route_id,
+               const base::Callback<WebContents*(void)>& web_contents_getter,
+               ServiceWorkerProviderType type);
+    ClientInfo(const ClientInfo& other);
     ~ClientInfo();
     int process_id;
     int route_id;
+    // |web_contents_getter| is only set for PlzNavigate.
+    base::Callback<WebContents*(void)> web_contents_getter;
     ServiceWorkerProviderType type;
   };
 
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index c8fed4d..f6354f2 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -1803,7 +1803,7 @@
   // Allow the activation to continue. It will fail, and the worker
   // should not be promoted to ACTIVATED because failure occur
   // during shutdown.
-  runner->RunUntilIdle();
+  runner->RunPendingTasks();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(new_version.get(), registration->active_version());
   EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, new_version->status());
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index e72bc88..59ece4d 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -369,7 +369,8 @@
     info.clients.insert(std::make_pair(
         host->client_uuid(),
         ServiceWorkerVersionInfo::ClientInfo(
-            host->process_id(), host->route_id(), host->provider_type())));
+            host->process_id(), host->route_id(), host->web_contents_getter(),
+            host->provider_type())));
   }
   if (!main_script_http_info_)
     return info;
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 90990f3..3b2550c2 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -653,7 +653,8 @@
     int y) {
   RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
   if (view)
-    view->ShowContextMenuAtTouchHandle(gfx::Point(x, y));
+    view->ShowContextMenuAtPoint(gfx::Point(x, y),
+                                 ui::MENU_SOURCE_TOUCH_HANDLE);
 }
 
 void WebContentsAndroid::SetHasPersistentVideo(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index ed882eff..626c4c8 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -127,6 +127,7 @@
 #include "net/base/url_util.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction_factory.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ppapi/features/features.h"
@@ -3209,7 +3210,7 @@
     }
   }
   BrowserContext::GetDownloadManager(GetBrowserContext())
-      ->DownloadUrl(std::move(params));
+      ->DownloadUrl(std::move(params), NO_TRAFFIC_ANNOTATION_YET);
 }
 
 void WebContentsImpl::GenerateMHTML(
diff --git a/content/browser/webrtc/webrtc_image_capture_browsertest.cc b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
index ca3751d..d5641934 100644
--- a/content/browser/webrtc/webrtc_image_capture_browsertest.cc
+++ b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
@@ -39,10 +39,9 @@
 // platforms where the ImageCaptureCode is landed, https://crbug.com/656810
 static struct TargetCamera {
   bool use_fake;
-} const kTestParameters[] = {
-    {true},
-#if defined(OS_LINUX)
-    {false}
+} const kTestParameters[] = {{true},
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_ANDROID)
+                             {false}
 #endif
 };
 
diff --git a/content/child/assert_matching_enums.cc b/content/child/assert_matching_enums.cc
index 1c784bc..5b587ad3 100644
--- a/content/child/assert_matching_enums.cc
+++ b/content/child/assert_matching_enums.cc
@@ -100,5 +100,6 @@
 STATIC_ASSERT_ENUM(blink::kMenuSourceLongPress, ui::MENU_SOURCE_LONG_PRESS);
 STATIC_ASSERT_ENUM(blink::kMenuSourceLongTap, ui::MENU_SOURCE_LONG_TAP);
 STATIC_ASSERT_ENUM(blink::kMenuSourceTouchHandle, ui::MENU_SOURCE_TOUCH_HANDLE);
+STATIC_ASSERT_ENUM(blink::kMenuSourceStylus, ui::MENU_SOURCE_STYLUS);
 
 } // namespace content
diff --git a/content/common/DEPS b/content/common/DEPS
index 78ec7ec7..2ecbdeb 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -27,6 +27,7 @@
   "+third_party/WebKit/public/platform/WebKeyboardEvent.h",
   "+third_party/WebKit/public/platform/WebMixedContentContextType.h",
   "+third_party/WebKit/public/platform/WebMouseWheelEvent.h",
+  "+third_party/WebKit/public/platform/WebPointerProperties.h",
   "+third_party/WebKit/public/platform/WebOriginTrialTokenStatus.h",
   "+third_party/WebKit/public/platform/WebPageVisibilityState.h",
   "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 999987f..6d4ce02 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -28,6 +28,7 @@
 #include "content/common/input/synthetic_tap_gesture_params.h"
 #include "ipc/ipc_message_macros.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/WebKit/public/platform/WebPointerProperties.h"
 #include "ui/events/blink/did_overscroll_params.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
@@ -64,6 +65,11 @@
 IPC_ENUM_TRAITS_MAX_VALUE(content::InputEventDispatchType,
                           content::InputEventDispatchType::DISPATCH_TYPE_MAX)
 IPC_ENUM_TRAITS_MAX_VALUE(cc::TouchAction, cc::kTouchActionMax)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(blink::WebPointerProperties::Button,
+                              blink::WebPointerProperties::Button::kNoButton,
+                              blink::WebPointerProperties::Button::kLastEntry)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPointerProperties::PointerType,
+                          blink::WebPointerProperties::PointerType::kLastEntry)
 
 IPC_STRUCT_TRAITS_BEGIN(ui::DidOverscrollParams)
   IPC_STRUCT_TRAITS_MEMBER(accumulated_overscroll)
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 558677d..8bf444f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1678,10 +1678,11 @@
     }
 
     @CalledByNative
-    private void showPastePopup(
-            int left, int top, int right, int bottom, boolean canSelectAll, boolean canEditRichly) {
-        mSelectionPopupController.createAndShowPastePopup(
-                left, top, right, bottom, canSelectAll, canEditRichly);
+    private void showSelectionMenu(int left, int top, int right, int bottom, boolean isEditable,
+            boolean isPasswordType, String selectionText, boolean canSelectAll,
+            boolean canEditRichly, boolean shouldSuggest) {
+        mSelectionPopupController.showSelectionMenu(left, top, right, bottom, isEditable,
+                isPasswordType, selectionText, canSelectAll, canEditRichly, shouldSuggest);
     }
 
     private void destroyPastePopup() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
index 4b7f15f..db2ef0f4 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
@@ -118,10 +118,6 @@
     private boolean mUnselectAllOnDismiss;
     private String mLastSelectedText;
 
-    // Tracks whether a selection is currently active.  When applied to selected text, indicates
-    // whether the last selected text is still highlighted.
-    private boolean mHasSelection;
-
     // Lazily created paste popup menu, triggered either via long press in an
     // editable region or from tapping the insertion handle.
     private PastePopupMenu mPastePopupMenu;
@@ -176,6 +172,7 @@
         mSelectionClient =
                 SmartSelectionClient.create(new SmartSelectionCallback(), window, webContents);
 
+        mLastSelectedText = "";
         // TODO(timav): Use android.R.id.textAssist for the Assist item id once we switch to
         // Android O SDK and remove |mAssistMenuItemId|.
         if (BuildInfo.isAtLeastO()) {
@@ -223,6 +220,31 @@
         mAllowedMenuItems = allowedMenuItems;
     }
 
+    public void showSelectionMenu(int left, int top, int right, int bottom, boolean isEditable,
+            boolean isPasswordType, String selectionText, boolean canSelectAll,
+            boolean canRichlyEdit, boolean shouldSuggest) {
+        mSelectionRect.set(left, top, right, bottom);
+        mEditable = isEditable;
+        mLastSelectedText = selectionText;
+        mIsPasswordType = isPasswordType;
+        mCanSelectAllForPastePopup = canSelectAll;
+        mCanEditRichlyForPastePopup = canRichlyEdit;
+        mUnselectAllOnDismiss = true;
+        if (hasSelection()) {
+            if (mSelectionClient != null
+                    && mSelectionClient.requestSelectionPopupUpdates(shouldSuggest)) {
+                // Rely on |mSelectionClient| sending a classification request and the request
+                // always calling onClassified() callback.
+                mPendingShowActionMode = true;
+            } else {
+                showActionModeOrClearOnFailure();
+            }
+
+        } else {
+            createAndShowPastePopup();
+        }
+    }
+
     /**
      * Show (activate) android action mode by starting it.
      *
@@ -268,17 +290,13 @@
         return actionMode;
     }
 
-    void createAndShowPastePopup(
-            int left, int top, int right, int bottom, boolean canSelectAll, boolean canEditRichly) {
+    private void createAndShowPastePopup() {
         if (mView.getParent() == null || mView.getVisibility() != View.VISIBLE) {
             return;
         }
 
         if (!supportsFloatingActionMode() && !canPaste()) return;
         destroyPastePopup();
-        mSelectionRect.set(left, top, right, bottom);
-        mCanSelectAllForPastePopup = canSelectAll;
-        mCanEditRichlyForPastePopup = canEditRichly;
         PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() {
             @Override
             public void paste() {
@@ -494,7 +512,7 @@
             descriptor.removeItem(R.id.select_action_menu_paste);
         }
 
-        if (isInsertion()) {
+        if (!hasSelection()) {
             descriptor.removeItem(R.id.select_action_menu_select_all);
             descriptor.removeItem(R.id.select_action_menu_cut);
             descriptor.removeItem(R.id.select_action_menu_copy);
@@ -731,8 +749,6 @@
     void selectAll() {
         mWebContents.selectAll();
         mClassificationResult = null;
-        if (needsActionMenuUpdate()) showActionModeOrClearOnFailure();
-
         // Even though the above statement logged a SelectAll user action, we want to
         // track whether the focus was in an editable field, so log that too.
         if (isSelectionEditable()) {
@@ -934,17 +950,6 @@
         if (top == bottom) ++bottom;
         switch (eventType) {
             case SelectionEventType.SELECTION_HANDLES_SHOWN:
-                mSelectionRect.set(left, top, right, bottom);
-                mHasSelection = true;
-                mUnselectAllOnDismiss = true;
-                if (mSelectionClient != null
-                        && mSelectionClient.requestSelectionPopupUpdates(true /* suggest */)) {
-                    // Rely on |mSelectionClient| sending a classification request and the request
-                    // always calling onClassified() callback.
-                    mPendingShowActionMode = true;
-                } else {
-                    showActionModeOrClearOnFailure();
-                }
                 break;
 
             case SelectionEventType.SELECTION_HANDLES_MOVED:
@@ -957,7 +962,7 @@
                 break;
 
             case SelectionEventType.SELECTION_HANDLES_CLEARED:
-                mHasSelection = false;
+                mLastSelectedText = "";
                 mUnselectAllOnDismiss = false;
                 mSelectionRect.setEmpty();
                 if (mSelectionClient != null) mSelectionClient.cancelAllRequests();
@@ -969,13 +974,7 @@
                 break;
 
             case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
-                if (mSelectionClient != null
-                        && mSelectionClient.requestSelectionPopupUpdates(false /* suggest */)) {
-                    // Rely on |mSelectionClient| sending a classification request and the request
-                    // always calling onClassified() callback.
-                } else {
-                    hideActionMode(false);
-                }
+                mWebContents.showContextMenuAtTouchHandle(left, bottom);
                 break;
 
             case SelectionEventType.INSERTION_HANDLE_SHOWN:
@@ -1097,12 +1096,12 @@
      */
     @VisibleForTesting
     public boolean hasSelection() {
-        return mHasSelection;
+        return mLastSelectedText.length() != 0;
     }
 
     @Override
     public String getSelectedText() {
-        return hasSelection() ? mLastSelectedText : "";
+        return mLastSelectedText;
     }
 
     private boolean isShareAvailable() {
diff --git a/content/public/browser/android/content_view_core.h b/content/public/browser/android/content_view_core.h
index 2ef4861..781f20ba 100644
--- a/content/public/browser/android/content_view_core.h
+++ b/content/public/browser/android/content_view_core.h
@@ -35,7 +35,7 @@
 
   // May return null reference.
   virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() = 0;
-  virtual bool ShowPastePopup(const ContextMenuParams& params) = 0;
+  virtual bool ShowSelectionMenu(const ContextMenuParams& params) = 0;
 
   virtual ui::WindowAndroid* GetWindowAndroid() const = 0;
 
diff --git a/content/public/browser/download_manager.h b/content/public/browser/download_manager.h
index f6080fe5..038195b 100644
--- a/content/public/browser/download_manager.h
+++ b/content/public/browser/download_manager.h
@@ -40,6 +40,7 @@
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_url_parameters.h"
 #include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 class GURL;
 
@@ -121,7 +122,8 @@
 
   // See DownloadUrlParameters for details about controlling the download.
   virtual void DownloadUrl(
-      std::unique_ptr<DownloadUrlParameters> parameters) = 0;
+      std::unique_ptr<DownloadUrlParameters> parameters,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
 
   // Allow objects to observe the download creation process.
   virtual void AddObserver(Observer* observer) = 0;
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 5ff2bb0f..fcf333ed 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -78,9 +78,10 @@
 IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::ViewportStyle,
                               content::ViewportStyle::DEFAULT,
                               content::ViewportStyle::LAST)
-IPC_ENUM_TRAITS_MIN_MAX_VALUE(content::AutoplayPolicy,
-                              content::AutoplayPolicy::kNoUserGestureRequired,
-                              content::AutoplayPolicy::kUserGestureRequired)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(
+    content::AutoplayPolicy,
+    content::AutoplayPolicy::kNoUserGestureRequired,
+    content::AutoplayPolicy::kUserGestureRequiredForCrossOrigin)
 
 IPC_STRUCT_TRAITS_BEGIN(blink::WebPoint)
   IPC_STRUCT_TRAITS_MEMBER(x)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 22b857bc..22ad539 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -333,6 +333,10 @@
 const char kDisableAcceleratedJpegDecoding[] =
     "disable-accelerated-jpeg-decoding";
 
+// Logs Runtime Call Stats for Blink. --single-process also needs to be
+// used along with this for the stats to be logged.
+const char kDumpBlinkRuntimeCallStats[] = "dump-blink-runtime-call-stats";
+
 // Enables LCD text.
 const char kEnableLCDText[]                 = "enable-lcd-text";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 849e9fd..79c9571 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -106,6 +106,7 @@
 CONTENT_EXPORT extern const char kDisableZeroCopyDxgiVideo[];
 CONTENT_EXPORT extern const char kDomAutomationController[];
 extern const char kDisable2dCanvasClipAntialiasing[];
+CONTENT_EXPORT extern const char kDumpBlinkRuntimeCallStats[];
 CONTENT_EXPORT extern const char kEnableAggressiveDOMStorageFlushing[];
 CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kEnableBlinkFeatures[];
diff --git a/content/public/test/mock_download_manager.h b/content/public/test/mock_download_manager.h
index f462fa1..642aaa3 100644
--- a/content/public/test/mock_download_manager.h
+++ b/content/public/test/mock_download_manager.h
@@ -13,6 +13,7 @@
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/download_save_info.h"
 #include "content/public/browser/download_url_parameters.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -112,7 +113,9 @@
                    base::Time remove_begin,
                    base::Time remove_end));
   MOCK_METHOD1(DownloadUrlMock, void(DownloadUrlParameters*));
-  void DownloadUrl(std::unique_ptr<DownloadUrlParameters> params) override {
+  void DownloadUrl(
+      std::unique_ptr<DownloadUrlParameters> params,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     DownloadUrlMock(params.get());
   }
   MOCK_METHOD1(AddObserver, void(Observer* observer));
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 74ae9287..604b384b 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -932,6 +932,10 @@
   // evaluation and debugging.
   blink::MainThreadIsolate()->DumpAndResetStats();
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDumpBlinkRuntimeCallStats))
+    blink::LogRuntimeCallStats();
+
   // In a single-process mode, we cannot call _exit(0) in Shutdown() because
   // it will exit the process before the browser side is ready to exit.
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/content/shell/browser/shell_web_contents_view_delegate_android.cc b/content/shell/browser/shell_web_contents_view_delegate_android.cc
index 14248721..7917d51 100644
--- a/content/shell/browser/shell_web_contents_view_delegate_android.cc
+++ b/content/shell/browser/shell_web_contents_view_delegate_android.cc
@@ -32,7 +32,7 @@
   content::ContentViewCore* content_view_core =
       ContentViewCore::FromWebContents(web_contents_);
   if (content_view_core)
-    content_view_core->ShowPastePopup(params);
+    content_view_core->ShowSelectionMenu(params);
 }
 
 }  // namespace content
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index df450df..beba5c0 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -69,6 +69,7 @@
         framebuffer_completeness_cache,
     const scoped_refptr<FeatureInfo>& feature_info,
     bool bind_generates_resource,
+    ImageManager* image_manager,
     gpu::ImageFactory* image_factory,
     ProgressReporter* progress_reporter,
     const GpuFeatureInfo& gpu_feature_info,
@@ -84,7 +85,7 @@
       // TODO(tobiasjs): determine whether GPU switching is possible
       // programmatically, rather than just hardcoding this behaviour
       // for OS X.
-      framebuffer_completeness_cache_(NULL),
+      framebuffer_completeness_cache_(nullptr),
 #else
       framebuffer_completeness_cache_(framebuffer_completeness_cache),
 #endif
@@ -107,8 +108,9 @@
       max_transform_feedback_separate_attribs_(0u),
       max_uniform_buffer_bindings_(0u),
       uniform_buffer_offset_alignment_(1u),
-      program_cache_(NULL),
+      program_cache_(nullptr),
       feature_info_(feature_info),
+      image_manager_(image_manager),
       image_factory_(image_factory),
       passthrough_resources_(new PassthroughResources),
       progress_reporter_(progress_reporter),
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index bc22303..3f9073e 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -36,6 +36,7 @@
 class ProgramCache;
 class BufferManager;
 class GLES2Decoder;
+class ImageManager;
 class MailboxManager;
 class RenderbufferManager;
 class PathManager;
@@ -65,6 +66,7 @@
           framebuffer_completeness_cache,
       const scoped_refptr<FeatureInfo>& feature_info,
       bool bind_generates_resource,
+      ImageManager* image_manager,
       gpu::ImageFactory* image_factory,
       ProgressReporter* progress_reporter,
       const GpuFeatureInfo& gpu_feature_info,
@@ -157,7 +159,9 @@
     return feature_info_.get();
   }
 
-  gpu::ImageFactory* image_factory() { return image_factory_; }
+  ImageManager* image_manager() const { return image_manager_; }
+
+  gpu::ImageFactory* image_factory() const { return image_factory_; }
 
   const GpuPreferences& gpu_preferences() const {
     return gpu_preferences_;
@@ -295,9 +299,11 @@
 
   scoped_refptr<FeatureInfo> feature_info_;
 
+  ImageManager* image_manager_;
+
   gpu::ImageFactory* image_factory_;
 
-  std::vector<base::WeakPtr<gles2::GLES2Decoder> > decoders_;
+  std::vector<base::WeakPtr<gles2::GLES2Decoder>> decoders_;
 
   // Mappings from client side IDs to service side IDs.
   base::hash_map<GLuint, GLsync> syncs_id_map_;
diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc
index 1cb3a3ce..263a778 100644
--- a/gpu/command_buffer/service/context_group_unittest.cc
+++ b/gpu/command_buffer/service/context_group_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/service_discardable_manager.h"
 #include "gpu/command_buffer/service/test_helper.h"
@@ -43,13 +44,17 @@
     GpuServiceTest::SetUp();
     decoder_.reset(new MockGLES2Decoder());
     scoped_refptr<FeatureInfo> feature_info = new FeatureInfo;
-    group_ = scoped_refptr<ContextGroup>(
-        new ContextGroup(gpu_preferences_, NULL, NULL, NULL, NULL, feature_info,
-                         kBindGeneratesResource, nullptr, nullptr,
-                         GpuFeatureInfo(), &discardable_manager_));
+    group_ = scoped_refptr<ContextGroup>(new ContextGroup(
+        gpu_preferences_, nullptr /* mailbox_manager */,
+        nullptr /* memory_tracker */, nullptr /* shader_translator_cache */,
+        nullptr /* framebuffer_completeness_cache */, feature_info,
+        kBindGeneratesResource, &image_manager_, nullptr /* image_factory */,
+        nullptr /* progress_reporter */, GpuFeatureInfo(),
+        &discardable_manager_));
   }
 
   GpuPreferences gpu_preferences_;
+  ImageManager image_manager_;
   ServiceDiscardableManager discardable_manager_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
   scoped_refptr<ContextGroup> group_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 5dbc207..4464551e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -576,7 +576,9 @@
   VertexArrayManager* GetVertexArrayManager() override {
     return vertex_array_manager_.get();
   }
-  ImageManager* GetImageManager() override { return image_manager_.get(); }
+  ImageManager* GetImageManagerForTest() override {
+    return group_->image_manager();
+  }
 
   bool HasPendingQueries() const override;
   void ProcessPendingQueries(bool did_finish) override;
@@ -755,7 +757,7 @@
     return group_->mailbox_manager();
   }
 
-  ImageManager* image_manager() { return image_manager_.get(); }
+  ImageManager* image_manager() { return group_->image_manager(); }
 
   VertexArrayManager* vertex_array_manager() {
     return vertex_array_manager_.get();
@@ -2340,8 +2342,6 @@
 
   std::unique_ptr<VertexArrayManager> vertex_array_manager_;
 
-  std::unique_ptr<ImageManager> image_manager_;
-
   FenceSyncReleaseCallback fence_sync_release_callback_;
   WaitSyncTokenCallback wait_sync_token_callback_;
   NoParamCallback deschedule_until_finished_callback_;
@@ -3279,8 +3279,6 @@
 
   query_manager_.reset(new QueryManager(this, feature_info_.get()));
 
-  image_manager_.reset(new ImageManager);
-
   util_.set_num_compressed_texture_formats(
       validators_->compressed_texture_format.GetValues().size());
 
@@ -4887,8 +4885,6 @@
     transform_feedback_manager_.reset();
   }
 
-  image_manager_.reset();
-
   offscreen_target_frame_buffer_.reset();
   offscreen_target_color_texture_.reset();
   offscreen_target_color_render_buffer_.reset();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index f0b1b82..85b6acc5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -217,7 +217,7 @@
   virtual VertexArrayManager* GetVertexArrayManager() = 0;
 
   // Gets the ImageManager for this context.
-  virtual ImageManager* GetImageManager() = 0;
+  virtual ImageManager* GetImageManagerForTest() = 0;
 
   // Returns false if there are no pending queries.
   virtual bool HasPendingQueries() const = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index aa4940f7..c2629a3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -95,7 +95,7 @@
   MOCK_METHOD0(
       GetTransformFeedbackManager, gpu::gles2::TransformFeedbackManager*());
   MOCK_METHOD0(GetVertexArrayManager, gpu::gles2::VertexArrayManager*());
-  MOCK_METHOD0(GetImageManager, gpu::gles2::ImageManager*());
+  MOCK_METHOD0(GetImageManagerForTest, gpu::gles2::ImageManager*());
   MOCK_METHOD1(
       SetResizeCallback, void(const base::Callback<void(gfx::Size, float)>&));
   MOCK_METHOD1(SetIgnoreCachedStateForTest, void(bool ignore));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index 8e032b1..a3bf1c2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -192,8 +192,6 @@
     return false;
   }
 
-  image_manager_.reset(new ImageManager());
-
   bind_generates_resource_ = group_->bind_generates_resource();
 
   resources_ = group_->passthrough_resources();
@@ -233,8 +231,6 @@
     FlushErrors();
   }
 
-  image_manager_.reset();
-
   DeleteServiceObjects(
       &framebuffer_id_map_, have_context,
       [](GLuint framebuffer) { glDeleteFramebuffersEXT(1, &framebuffer); });
@@ -474,8 +470,9 @@
   return nullptr;
 }
 
-gpu::gles2::ImageManager* GLES2DecoderPassthroughImpl::GetImageManager() {
-  return image_manager_.get();
+gpu::gles2::ImageManager*
+GLES2DecoderPassthroughImpl::GetImageManagerForTest() {
+  return group_->image_manager();
 }
 
 bool GLES2DecoderPassthroughImpl::HasPendingQueries() const {
@@ -891,7 +888,7 @@
     return error::kNoError;
   }
 
-  gl::GLImage* image = image_manager_->LookupImage(imageId);
+  gl::GLImage* image = group_->image_manager()->LookupImage(imageId);
   if (image == nullptr) {
     InsertError(GL_INVALID_OPERATION, "No image found with the given ID");
     return error::kNoError;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index 354cce7..a73c57b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -168,7 +168,7 @@
   VertexArrayManager* GetVertexArrayManager() override;
 
   // Gets the ImageManager for this context.
-  ImageManager* GetImageManager() override;
+  ImageManager* GetImageManagerForTest() override;
 
   // Returns false if there are no pending queries.
   bool HasPendingQueries() const override;
@@ -331,9 +331,6 @@
   scoped_refptr<gl::GLContext> context_;
   bool offscreen_;
 
-  // Managers
-  std::unique_ptr<ImageManager> image_manager_;
-
   // The ContextGroup for this decoder uses to track resources.
   scoped_refptr<ContextGroup> group_;
   scoped_refptr<FeatureInfo> feature_info_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index 57cfae74..09e1944 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -3579,7 +3579,7 @@
     return error::kNoError;
   }
 
-  gl::GLImage* image = image_manager_->LookupImage(imageId);
+  gl::GLImage* image = group_->image_manager()->LookupImage(imageId);
   if (image == nullptr) {
     InsertError(GL_INVALID_OPERATION, "No image found with the given ID");
     return error::kNoError;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 0cfbb104..74be9a9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -196,12 +196,13 @@
     feature_info = new FeatureInfo(*command_line, gpu_driver_bug_workaround);
   }
 
-  group_ = scoped_refptr<ContextGroup>(
-      new ContextGroup(gpu_preferences_, NULL, memory_tracker_,
-                       new ShaderTranslatorCache(gpu_preferences_),
-                       new FramebufferCompletenessCache, feature_info,
-                       normalized_init.bind_generates_resource, nullptr,
-                       nullptr, GpuFeatureInfo(), &discardable_manager_));
+  group_ = scoped_refptr<ContextGroup>(new ContextGroup(
+      gpu_preferences_, nullptr /* mailbox_manager */, memory_tracker_,
+      new ShaderTranslatorCache(gpu_preferences_),
+      new FramebufferCompletenessCache, feature_info,
+      normalized_init.bind_generates_resource, &image_manager_,
+      nullptr /* image_factory */, nullptr /* progress_reporter */,
+      GpuFeatureInfo(), &discardable_manager_));
   bool use_default_textures = normalized_init.bind_generates_resource;
 
   InSequence sequence;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 038545f..edefc80b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -21,6 +21,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/program_manager.h"
 #include "gpu/command_buffer/service/query_manager.h"
 #include "gpu/command_buffer/service/renderbuffer_manager.h"
@@ -172,7 +173,9 @@
     return decoder_->GetFramebufferManager();
   }
 
-  ImageManager* GetImageManager() { return decoder_->GetImageManager(); }
+  ImageManager* GetImageManagerForTest() {
+    return decoder_->GetImageManagerForTest();
+  }
 
   void DoCreateProgram(GLuint client_id, GLuint service_id);
   void DoCreateShader(GLenum shader_type, GLuint client_id, GLuint service_id);
@@ -755,6 +758,7 @@
 
   std::unique_ptr<FakeCommandBufferServiceBase> command_buffer_service_;
   GpuPreferences gpu_preferences_;
+  gles2::ImageManager image_manager_;
   ServiceDiscardableManager discardable_manager_;
   scoped_refptr<ContextGroup> group_;
   MockGLStates gl_states_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index 6e25022e..81d43dd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -3312,8 +3312,8 @@
   EXPECT_EQ(kServiceTextureId, texture->service_id());
 
   scoped_refptr<gl::GLImage> image(new gl::GLImageStub);
-  GetImageManager()->AddImage(image.get(), 1);
-  EXPECT_FALSE(GetImageManager()->LookupImage(1) == NULL);
+  GetImageManagerForTest()->AddImage(image.get(), 1);
+  EXPECT_FALSE(GetImageManagerForTest()->LookupImage(1) == NULL);
 
   GLsizei width;
   GLsizei height;
@@ -3348,7 +3348,7 @@
 
 TEST_P(GLES2DecoderTest, BindTexImage2DCHROMIUMCubeMapNotAllowed) {
   scoped_refptr<gl::GLImage> image(new gl::GLImageStub);
-  GetImageManager()->AddImage(image.get(), 1);
+  GetImageManagerForTest()->AddImage(image.get(), 1);
   DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId);
 
   BindTexImage2DCHROMIUM bind_tex_image_2d_cmd;
@@ -3359,7 +3359,7 @@
 
 TEST_P(GLES2DecoderTest, OrphanGLImageWithTexImage2D) {
   scoped_refptr<gl::GLImage> image(new gl::GLImageStub);
-  GetImageManager()->AddImage(image.get(), 1);
+  GetImageManagerForTest()->AddImage(image.get(), 1);
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
 
   DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1);
@@ -3382,7 +3382,7 @@
       feature_info()->workarounds().texsubimage_faster_than_teximage);
 
   scoped_refptr<gl::GLImage> image(new gl::GLImageStub);
-  GetImageManager()->AddImage(image.get(), 1);
+  GetImageManagerForTest()->AddImage(image.get(), 1);
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
 
   GLenum target = GL_TEXTURE_2D;
@@ -3427,7 +3427,7 @@
 
 TEST_P(GLES2DecoderTest, GLImageAttachedAfterClearLevel) {
   scoped_refptr<gl::GLImage> image(new gl::GLImageStub);
-  GetImageManager()->AddImage(image.get(), 1);
+  GetImageManagerForTest()->AddImage(image.get(), 1);
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
 
   GLenum target = GL_TEXTURE_2D;
@@ -3480,8 +3480,8 @@
   EXPECT_EQ(kServiceTextureId, texture->service_id());
 
   scoped_refptr<gl::GLImage> image(new gl::GLImageStub);
-  GetImageManager()->AddImage(image.get(), 1);
-  EXPECT_FALSE(GetImageManager()->LookupImage(1) == NULL);
+  GetImageManagerForTest()->AddImage(image.get(), 1);
+  EXPECT_FALSE(GetImageManagerForTest()->LookupImage(1) == NULL);
 
   GLsizei width;
   GLsizei height;
@@ -3560,7 +3560,7 @@
 
   const int32_t kImageId = 1;
   scoped_refptr<MockGLImage> image(new MockGLImage);
-  GetImageManager()->AddImage(image.get(), kImageId);
+  GetImageManagerForTest()->AddImage(image.get(), kImageId);
 
   // Bind image to texture.
   EXPECT_CALL(*image.get(), BindTexImage(GL_TEXTURE_2D))
@@ -4425,8 +4425,8 @@
         image = new EmulatingRGBImageStub;
       else
         image = new gl::GLImageStub;
-      GetImageManager()->AddImage(image.get(), image_id);
-      EXPECT_FALSE(GetImageManager()->LookupImage(image_id) == NULL);
+      GetImageManagerForTest()->AddImage(image.get(), image_id);
+      EXPECT_FALSE(GetImageManagerForTest()->LookupImage(image_id) == NULL);
       DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
 
       DoBindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
diff --git a/gpu/command_buffer/service/service_discardable_manager_unittest.cc b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
index b09a3596..86eed6d534 100644
--- a/gpu/command_buffer/service/service_discardable_manager_unittest.cc
+++ b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/mocks.h"
@@ -67,9 +68,10 @@
     GpuServiceTest::SetUp();
     decoder_.reset(new MockGLES2Decoder());
     feature_info_ = new FeatureInfo();
-    context_group_ = scoped_refptr<ContextGroup>(new ContextGroup(
-        gpu_preferences_, nullptr, nullptr, nullptr, nullptr, feature_info_,
-        false, nullptr, nullptr, GpuFeatureInfo(), &discardable_manager_));
+    context_group_ = scoped_refptr<ContextGroup>(
+        new ContextGroup(gpu_preferences_, nullptr, nullptr, nullptr, nullptr,
+                         feature_info_, false, &image_manager_, nullptr,
+                         nullptr, GpuFeatureInfo(), &discardable_manager_));
     TestHelper::SetupContextGroupInitExpectations(
         gl_.get(), DisallowedFeatures(), "", "", CONTEXT_TYPE_OPENGLES2, false);
     context_group_->Initialize(decoder_.get(), CONTEXT_TYPE_OPENGLES2,
@@ -110,6 +112,7 @@
         .RetiresOnSaturation();
   }
 
+  gles2::ImageManager image_manager_;
   ServiceDiscardableManager discardable_manager_;
   GpuPreferences gpu_preferences_;
   scoped_refptr<FeatureInfo> feature_info_;
@@ -452,4 +455,4 @@
 }
 
 }  // namespace gles2
-}  // namespace gpu
\ No newline at end of file
+}  // namespace gpu
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index 38dda8e..e010a447 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -22,6 +22,7 @@
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/logger.h"
 #include "gpu/command_buffer/service/mailbox_manager_impl.h"
 #include "gpu/command_buffer/service/service_discardable_manager.h"
@@ -89,7 +90,6 @@
  public:
   CommandBufferSetup()
       : atexit_manager_(),
-        sync_point_manager_(new SyncPointManager()),
         mailbox_manager_(new gles2::MailboxManagerImpl),
         share_group_(new gl::GLShareGroup) {
     logging::SetMinLogLevel(logging::LOG_FATAL);
@@ -136,8 +136,9 @@
     scoped_refptr<gles2::FeatureInfo> feature_info =
         new gles2::FeatureInfo();
     scoped_refptr<gles2::ContextGroup> context_group = new gles2::ContextGroup(
-        gpu_preferences_, mailbox_manager_.get(), nullptr, translator_cache_,
-        completeness_cache_, feature_info, true /* bind_generates_resource */,
+        gpu_preferences_, mailbox_manager_.get(), nullptr /* memory_tracker */,
+        translator_cache_, completeness_cache_, feature_info,
+        true /* bind_generates_resource */, &image_manager_,
         nullptr /* image_factory */, nullptr /* progress_reporter */,
         GpuFeatureInfo(), &discardable_manager_);
     decoder_.reset(gles2::GLES2Decoder::Create(context_group.get()));
@@ -145,7 +146,7 @@
         context_group->transfer_buffer_manager(), decoder_.get(),
         base::Bind(&gles2::GLES2Decoder::MakeCurrent,
                    base::Unretained(decoder_.get())),
-        sync_point_manager_.get()));
+        &sync_point_manager_));
     InitializeInitialCommandBuffer();
 
     decoder_->set_command_buffer_service(command_buffer_->service());
@@ -252,9 +253,10 @@
 
   GpuPreferences gpu_preferences_;
 
-  std::unique_ptr<SyncPointManager> sync_point_manager_;
   scoped_refptr<gles2::MailboxManager> mailbox_manager_;
   scoped_refptr<gl::GLShareGroup> share_group_;
+  SyncPointManager sync_point_manager_;
+  gles2::ImageManager image_manager_;
   ServiceDiscardableManager discardable_manager_;
 
   bool recreate_context_ = false;
diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
index 3429111b..b994f45 100644
--- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
+++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
@@ -227,7 +227,8 @@
       glCreateImageCHROMIUM(buffer->AsClientBuffer(), kImageWidth, kImageHeight,
                             InternalFormat(GetParam()));
   ASSERT_NE(0u, image_id);
-  ASSERT_TRUE(gl_.decoder()->GetImageManager()->LookupImage(image_id) != NULL);
+  ASSERT_TRUE(gl_.decoder()->GetImageManagerForTest()->LookupImage(image_id) !=
+              NULL);
 
   // Bind the image.
   glBindTexImage2DCHROMIUM(GL_TEXTURE_2D, image_id);
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 422c89b..33b7b2f 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -31,10 +31,8 @@
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
-#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager_impl.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
-#include "gpu/command_buffer/service/service_discardable_manager.h"
 #include "gpu/command_buffer/service/service_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
@@ -211,7 +209,7 @@
 
 GLManager::Options::Options() = default;
 
-GLManager::GLManager() : discardable_manager_(new ServiceDiscardableManager()) {
+GLManager::GLManager() {
   SetupBaseContext();
 }
 
@@ -317,11 +315,12 @@
     scoped_refptr<gles2::FeatureInfo> feature_info =
         new gles2::FeatureInfo(command_line, gpu_driver_bug_workaround);
     context_group = new gles2::ContextGroup(
-        gpu_preferences_, mailbox_manager_.get(), nullptr,
+        gpu_preferences_, mailbox_manager_.get(), nullptr /* memory_tracker */,
         new gpu::gles2::ShaderTranslatorCache(gpu_preferences_),
         new gpu::gles2::FramebufferCompletenessCache, feature_info,
-        options.bind_generates_resource, options.image_factory, nullptr,
-        GpuFeatureInfo(), discardable_manager_.get());
+        options.bind_generates_resource, &image_manager_, options.image_factory,
+        nullptr /* progress_reporter */, GpuFeatureInfo(),
+        &discardable_manager_);
   }
 
   decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group));
@@ -497,16 +496,12 @@
 
   static int32_t next_id = 1;
   int32_t new_id = next_id++;
-  gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
-  DCHECK(image_manager);
-  image_manager->AddImage(gl_image.get(), new_id);
+  image_manager_.AddImage(gl_image.get(), new_id);
   return new_id;
 }
 
 void GLManager::DestroyImage(int32_t id) {
-  gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
-  DCHECK(image_manager);
-  image_manager->RemoveImage(id);
+  image_manager_.RemoveImage(id);
 }
 
 void GLManager::SignalQuery(uint32_t query, const base::Closure& callback) {
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index 12144a2..9b6c20e 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -15,6 +15,8 @@
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/service_discardable_manager.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
@@ -34,7 +36,6 @@
 
 class CommandBufferDirect;
 class ImageFactory;
-class ServiceDiscardableManager;
 class SyncPointManager;
 class TransferBuffer;
 
@@ -157,7 +158,6 @@
 
   scoped_refptr<gles2::MailboxManager> mailbox_manager_;
   scoped_refptr<gl::GLShareGroup> share_group_;
-  std::unique_ptr<ServiceDiscardableManager> discardable_manager_;
   std::unique_ptr<CommandBufferDirect> command_buffer_;
   std::unique_ptr<gles2::GLES2Decoder> decoder_;
   scoped_refptr<gl::GLSurface> surface_;
@@ -166,6 +166,9 @@
   std::unique_ptr<TransferBuffer> transfer_buffer_;
   std::unique_ptr<gles2::GLES2Implementation> gles2_implementation_;
 
+  gles2::ImageManager image_manager_;
+  ServiceDiscardableManager discardable_manager_;
+
   uint64_t next_fence_sync_release_ = 1;
 
   bool use_iosurface_memory_buffers_ = false;
diff --git a/gpu/gles2_conform_support/egl/context.cc b/gpu/gles2_conform_support/egl/context.cc
index 02e7bea..de8cdbdc 100644
--- a/gpu/gles2_conform_support/egl/context.cc
+++ b/gpu/gles2_conform_support/egl/context.cc
@@ -13,6 +13,7 @@
 #include "gpu/command_buffer/client/shared_memory_limits.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
 #include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/command_buffer/service/service_discardable_manager.h"
@@ -53,7 +54,6 @@
       config_(config),
       is_current_in_some_thread_(false),
       is_destroyed_(false),
-      discardable_manager_(new gpu::ServiceDiscardableManager()),
       gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()) {}
 
 Context::~Context() {
@@ -258,10 +258,13 @@
   scoped_refptr<gpu::gles2::FeatureInfo> feature_info(
       new gpu::gles2::FeatureInfo(gpu_driver_bug_workarounds_));
   scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup(
-      gpu_preferences_, nullptr, nullptr,
+      gpu_preferences_, nullptr /* mailbox_manager */,
+      nullptr /* memory_tracker */,
       new gpu::gles2::ShaderTranslatorCache(gpu_preferences_),
-      new gpu::gles2::FramebufferCompletenessCache, feature_info, true, nullptr,
-      nullptr, gpu::GpuFeatureInfo(), discardable_manager_.get()));
+      new gpu::gles2::FramebufferCompletenessCache, feature_info, true,
+      &image_manager_, nullptr /* image_factory */,
+      nullptr /* progress_reporter */, gpu::GpuFeatureInfo(),
+      &discardable_manager_));
 
   std::unique_ptr<gpu::gles2::GLES2Decoder> decoder(
       gpu::gles2::GLES2Decoder::Create(group.get()));
diff --git a/gpu/gles2_conform_support/egl/context.h b/gpu/gles2_conform_support/egl/context.h
index 64c1434..f90ad445 100644
--- a/gpu/gles2_conform_support/egl/context.h
+++ b/gpu/gles2_conform_support/egl/context.h
@@ -15,6 +15,8 @@
 #include "gpu/command_buffer/service/command_buffer_direct.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/service_discardable_manager.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gl/gl_context.h"
@@ -103,7 +105,6 @@
   bool is_current_in_some_thread_;
   bool is_destroyed_;
   gpu::GpuPreferences gpu_preferences_;
-  std::unique_ptr<gpu::ServiceDiscardableManager> discardable_manager_;
   const gpu::GpuDriverBugWorkarounds gpu_driver_bug_workarounds_;
   std::unique_ptr<gpu::TransferBufferManager> transfer_buffer_manager_;
   std::unique_ptr<gpu::CommandBufferDirect> command_buffer_;
@@ -114,6 +115,10 @@
   scoped_refptr<gl::GLContext> gl_context_;
 
   std::unique_ptr<gpu::gles2::GLES2Interface> client_gl_context_;
+
+  gpu::gles2::ImageManager image_manager_;
+  gpu::ServiceDiscardableManager discardable_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(Context);
 };
 
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 1fcfeeb..4212fde 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -178,6 +178,12 @@
   return program_cache_.get();
 }
 
+gles2::ImageManager* InProcessCommandBuffer::Service::image_manager() {
+  if (!image_manager_)
+    image_manager_.reset(new gles2::ImageManager());
+  return image_manager_.get();
+}
+
 ServiceDiscardableManager*
 InProcessCommandBuffer::Service::discardable_manager() {
   if (!discardable_manager_) {
@@ -300,11 +306,13 @@
       params.context_group
           ? params.context_group->decoder_->GetContextGroup()
           : new gles2::ContextGroup(
-                service_->gpu_preferences(), service_->mailbox_manager(), NULL,
+                service_->gpu_preferences(), service_->mailbox_manager(),
+                nullptr /* memory_tracker */,
                 service_->shader_translator_cache(),
                 service_->framebuffer_completeness_cache(), feature_info,
-                bind_generates_resource, nullptr, nullptr, GpuFeatureInfo(),
-                service_->discardable_manager());
+                bind_generates_resource, service_->image_manager(),
+                nullptr /* image_factory */, nullptr /* progress_reporter */,
+                GpuFeatureInfo(), service_->discardable_manager());
 
   decoder_.reset(gles2::GLES2Decoder::Create(context_group_.get()));
 
@@ -772,10 +780,7 @@
     gfx::BufferFormat format,
     uint32_t internalformat,
     uint64_t fence_sync) {
-  if (!decoder_)
-    return;
-
-  gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
+  gles2::ImageManager* image_manager = service_->image_manager();
   DCHECK(image_manager);
   if (image_manager->LookupImage(id)) {
     LOG(ERROR) << "Image already exists with same ID.";
@@ -834,10 +839,7 @@
 }
 
 void InProcessCommandBuffer::DestroyImageOnGpuThread(int32_t id) {
-  if (!decoder_)
-    return;
-
-  gpu::gles2::ImageManager* image_manager = decoder_->GetImageManager();
+  gles2::ImageManager* image_manager = service_->image_manager();
   DCHECK(image_manager);
   if (!image_manager->LookupImage(id)) {
     LOG(ERROR) << "Image with ID doesn't exist.";
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index 5e10bb1c..39dbaa7 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -179,7 +179,7 @@
   class Service {
    public:
     Service(const gpu::GpuPreferences& gpu_preferences);
-    Service(gpu::gles2::MailboxManager* mailbox_manager,
+    Service(gles2::MailboxManager* mailbox_manager,
             scoped_refptr<gl::GLShareGroup> share_group);
 
     virtual ~Service();
@@ -204,7 +204,8 @@
     const GpuDriverBugWorkarounds& gpu_driver_bug_workarounds();
     scoped_refptr<gl::GLShareGroup> share_group();
     scoped_refptr<gles2::MailboxManager> mailbox_manager();
-    gpu::gles2::ProgramCache* program_cache();
+    gles2::ProgramCache* program_cache();
+    gles2::ImageManager* image_manager();
     ServiceDiscardableManager* discardable_manager();
     virtual bool BlockThreadOnWaitSyncToken() const = 0;
 
@@ -213,9 +214,10 @@
     const GpuDriverBugWorkarounds gpu_driver_bug_workarounds_;
     scoped_refptr<gles2::MailboxManager> mailbox_manager_;
     scoped_refptr<gl::GLShareGroup> share_group_;
-    std::unique_ptr<gpu::gles2::ProgramCache> program_cache_;
+    std::unique_ptr<gles2::ProgramCache> program_cache_;
     // No-op default initialization is used in in-process mode.
     GpuProcessActivityFlags activity_flags_;
+    std::unique_ptr<gles2::ImageManager> image_manager_;
     std::unique_ptr<ServiceDiscardableManager> discardable_manager_;
   };
 
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index 0c5e0869..a93b4ebf 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -32,6 +32,7 @@
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/service/image_factory.h"
+#include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/preemption_flag.h"
 #include "gpu/command_buffer/service/scheduler.h"
@@ -777,6 +778,7 @@
       io_task_runner_(io_task_runner),
       share_group_(share_group),
       mailbox_manager_(mailbox_manager),
+      image_manager_(new gles2::ImageManager()),
       watchdog_(watchdog),
       discardable_manager_(std::move(discardable_manager)),
       is_gpu_host_(is_gpu_host),
diff --git a/gpu/ipc/service/gpu_channel.h b/gpu/ipc/service/gpu_channel.h
index 0c47dd1..a6953e23 100644
--- a/gpu/ipc/service/gpu_channel.h
+++ b/gpu/ipc/service/gpu_channel.h
@@ -116,6 +116,8 @@
 
   GpuWatchdogThread* watchdog() const { return watchdog_; }
 
+  gles2::ImageManager* image_manager() const { return image_manager_.get(); }
+
   const scoped_refptr<gles2::MailboxManager>& mailbox_manager() const {
     return mailbox_manager_;
   }
@@ -275,6 +277,8 @@
 
   scoped_refptr<gles2::MailboxManager> mailbox_manager_;
 
+  std::unique_ptr<gles2::ImageManager> image_manager_;
+
   GpuWatchdogThread* const watchdog_;
 
   ServiceDiscardableManager* discardable_manager_;
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index 89ba24c..b9bdf6ac 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -576,7 +576,7 @@
             init_params.attribs.context_type, channel_->task_runner()),
         manager->shader_translator_cache(),
         manager->framebuffer_completeness_cache(), feature_info,
-        init_params.attribs.bind_generates_resource,
+        init_params.attribs.bind_generates_resource, channel_->image_manager(),
         gmb_factory ? gmb_factory->AsImageFactory() : nullptr,
         channel_->watchdog() /* progress_reporter */,
         manager->gpu_feature_info(), channel_->discardable_manager());
@@ -1116,10 +1116,7 @@
   const uint32_t internalformat = params.internal_format;
   const uint64_t image_release_count = params.image_release_count;
 
-  if (!decoder_)
-    return;
-
-  gles2::ImageManager* image_manager = decoder_->GetImageManager();
+  gles2::ImageManager* image_manager = channel_->image_manager();
   DCHECK(image_manager);
   if (image_manager->LookupImage(id)) {
     LOG(ERROR) << "Image already exists with same ID.";
@@ -1156,10 +1153,7 @@
 void GpuCommandBufferStub::OnDestroyImage(int32_t id) {
   TRACE_EVENT0("gpu", "GpuCommandBufferStub::OnDestroyImage");
 
-  if (!decoder_)
-    return;
-
-  gles2::ImageManager* image_manager = decoder_->GetImageManager();
+  gles2::ImageManager* image_manager = channel_->image_manager();
   DCHECK(image_manager);
   if (!image_manager->LookupImage(id)) {
     LOG(ERROR) << "Image with ID doesn't exist.";
diff --git a/ios/chrome/browser/passwords/password_generation_prompt_view.mm b/ios/chrome/browser/passwords/password_generation_prompt_view.mm
index bc54326..5f7ef74 100644
--- a/ios/chrome/browser/passwords/password_generation_prompt_view.mm
+++ b/ios/chrome/browser/passwords/password_generation_prompt_view.mm
@@ -18,7 +18,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
@@ -184,7 +184,7 @@
 
 - (UILabel*)titleLabel {
   NSMutableDictionary* attrsDictionary = [NSMutableDictionary
-      dictionaryWithObject:[[MDFRobotoFontLoader sharedInstance]
+      dictionaryWithObject:[[MDCTypography fontLoader]
                                mediumFontOfSize:kTitleLabelFontSize]
                     forKey:NSFontAttributeName];
   [attrsDictionary setObject:UIColorFromRGB(kTitleLabelFontColor)
@@ -206,7 +206,7 @@
   base::scoped_nsobject<UILabel> passwordLabel([[UILabel alloc] init]);
   [passwordLabel setText:password];
   [passwordLabel setTextColor:UIColorFromRGB(kPasswordLabelFontColor)];
-  [passwordLabel setFont:[[MDFRobotoFontLoader sharedInstance]
+  [passwordLabel setFont:[[MDCTypography fontLoader]
                              regularFontOfSize:kPasswordLabelFontSize]];
   [passwordLabel setNumberOfLines:1];
   [passwordLabel sizeToFit];
@@ -228,7 +228,7 @@
                         UIColorFromRGB(kDescriptionLabelFontColor),
                         NSForegroundColorAttributeName, paragraphStyle.get(),
                         NSParagraphStyleAttributeName,
-                        [[MDFRobotoFontLoader sharedInstance]
+                        [[MDCTypography fontLoader]
                             regularFontOfSize:kDescriptionLabelFontSize],
                         NSFontAttributeName, nil];
 
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index 946d04b..011ca2b 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -636,7 +636,7 @@
 }
 
 // Tests that the Translate infobar is displayed after translation.
-- (void)testTranslateInfobar {
+- (void)DISABLED_testTranslateInfobar {
   const GURL URL =
       web::test::HttpServer::MakeUrl("http://scenarioTranslateInfobar");
   std::map<GURL, std::string> responses;
@@ -679,6 +679,16 @@
   [[EarlGrey selectElementWithMatcher:switchOn]
       assertWithMatcher:grey_notNil()];
 
+  // Assert that Spanish to English translation is not enabled after tapping
+  // the switch (should only be saved when "Done" button is tapped).
+  GREYAssert(!translatePrefs->IsLanguagePairWhitelisted("es", "en"),
+             @"Translate Spanish is disabled");
+
+  // Tap the "Done" button to save the preference.
+  [[EarlGrey
+      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabel(
+                                   @"Done")] performAction:grey_tap()];
+
   // Assert that Spanish to English translation is enabled.
   GREYAssert(translatePrefs->IsLanguagePairWhitelisted("es", "en"),
              @"Translate Spanish is disabled");
diff --git a/ios/chrome/browser/ui/alert_coordinator/loading_alert_coordinator.mm b/ios/chrome/browser/ui/alert_coordinator/loading_alert_coordinator.mm
index 8d9d363..35b2909 100644
--- a/ios/chrome/browser/ui/alert_coordinator/loading_alert_coordinator.mm
+++ b/ios/chrome/browser/ui/alert_coordinator/loading_alert_coordinator.mm
@@ -14,7 +14,7 @@
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Dialogs/src/MaterialDialogs.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -119,7 +119,7 @@
 
   // Title.
   NSMutableDictionary* attrsDictionary = [NSMutableDictionary
-      dictionaryWithObject:[[MDFRobotoFontLoader sharedInstance]
+      dictionaryWithObject:[[MDCTypography fontLoader]
                                mediumFontOfSize:kTitleLabelFontSize]
                     forKey:NSFontAttributeName];
   [attrsDictionary setObject:UIColorFromRGB(kTitleLabelFontColor)
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index e5e7ed51..f83d9890 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -53,7 +53,7 @@
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #import "ui/base/l10n/l10n_util.h"
 
 namespace {
@@ -840,10 +840,10 @@
 }
 
 - (void)layoutButtons:(const AuthenticationViewConstants&)constants {
-  [_primaryButton titleLabel].font = [[MDFRobotoFontLoader sharedInstance]
-      mediumFontOfSize:constants.SecondaryFontSize];
-  [_secondaryButton titleLabel].font = [[MDFRobotoFontLoader sharedInstance]
-      mediumFontOfSize:constants.SecondaryFontSize];
+  [_primaryButton titleLabel].font =
+      [[MDCTypography fontLoader] mediumFontOfSize:constants.SecondaryFontSize];
+  [_secondaryButton titleLabel].font =
+      [[MDCTypography fontLoader] mediumFontOfSize:constants.SecondaryFontSize];
 
   LayoutRect primaryButtonLayout = LayoutRectZero;
   primaryButtonLayout.boundingWidth = CGRectGetWidth(self.view.bounds);
diff --git a/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm b/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm
index fd12324a..6b4e19d8 100644
--- a/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/autofill_edit_item.mm
@@ -7,7 +7,7 @@
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -98,11 +98,10 @@
     _textField.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_textField];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
 
-    _textField.font = [[MDFRobotoFontLoader sharedInstance] lightFontOfSize:16];
+    _textField.font = [[MDCTypography fontLoader] lightFontOfSize:16];
     _textField.textColor = [[MDCPalette greyPalette] tint500];
     _textField.autocapitalizationType = UITextAutocapitalizationTypeWords;
     _textField.autocorrectionType = UITextAutocorrectionTypeNo;
diff --git a/ios/chrome/browser/ui/autofill/cells/cvc_item.mm b/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
index 62de222a..978a106 100644
--- a/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
@@ -11,7 +11,7 @@
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/text_field_styling.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -117,7 +117,7 @@
 
     _instructionsTextLabel = [[UILabel alloc] init];
     _instructionsTextLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+        [[MDCTypography fontLoader] mediumFontOfSize:14];
     _instructionsTextLabel.textColor = [[MDCPalette greyPalette] tint500];
     _instructionsTextLabel.numberOfLines = 0;
     _instructionsTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
@@ -125,8 +125,7 @@
     [contentView addSubview:_instructionsTextLabel];
 
     _errorLabel = [[UILabel alloc] init];
-    _errorLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12];
+    _errorLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
     _errorLabel.textColor = [[MDCPalette cr_redPalette] tint500];
     _errorLabel.numberOfLines = 0;
     _errorLabel.lineBreakMode = NSLineBreakByWordWrapping;
@@ -180,7 +179,7 @@
 
     _buttonForNewCard = [UIButton buttonWithType:UIButtonTypeCustom];
     _buttonForNewCard.titleLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12];
+        [[MDCTypography fontLoader] regularFontOfSize:12];
     [_buttonForNewCard
         setTitle:l10n_util::GetNSString(IDS_AUTOFILL_CARD_UNMASK_NEW_CARD_LINK)
         forState:UIControlStateNormal];
diff --git a/ios/chrome/browser/ui/autofill/cells/status_item.mm b/ios/chrome/browser/ui/autofill/cells/status_item.mm
index a9664472..b26a595 100644
--- a/ios/chrome/browser/ui/autofill/cells/status_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/status_item.mm
@@ -10,7 +10,7 @@
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -88,8 +88,7 @@
     [verticalCenteringView addSubview:_errorImageView];
 
     _textLabel = [[UILabel alloc] init];
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:16];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:16];
     _textLabel.numberOfLines = 0;
     _textLabel.lineBreakMode = NSLineBreakByWordWrapping;
     // The label's position will be centered with Auto Layout but this ensures
diff --git a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm b/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
index 560e4c8..eb34c2e 100644
--- a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
@@ -9,7 +9,7 @@
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -73,8 +73,7 @@
 
     _textLabel.text = l10n_util::GetNSString(
         IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX);
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint500];
     _textLabel.numberOfLines = 0;
     [_textLabel
diff --git a/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm b/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm
index fc266c7..216034f4 100644
--- a/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm
+++ b/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "components/strings/grit/components_strings.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -33,8 +33,7 @@
     [self setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.9]];
     [[self layer] setCornerRadius:kCornerRadius];
     [[self layer] setMasksToBounds:YES];
-    [self setFont:[[MDFRobotoFontLoader sharedInstance]
-                      regularFontOfSize:kFontSize]];
+    [self setFont:[[MDCTypography fontLoader] regularFontOfSize:kFontSize]];
     [self setNumberOfLines:0];  // Allows multi-line layout.
   }
   return self;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view_background.mm b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view_background.mm
index 38461e5..32fb365 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view_background.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view_background.mm
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/ui/bookmarks/bookmark_collection_view_background.h"
 
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -62,8 +62,8 @@
 - (UILabel*)newEmptyBookmarkLabel {
   UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
   label.backgroundColor = [UIColor clearColor];
-  label.font = [[MDFRobotoFontLoader sharedInstance]
-      mediumFontOfSize:kEmptyBookmarkTextSize];
+  label.font =
+      [[MDCTypography fontLoader] mediumFontOfSize:kEmptyBookmarkTextSize];
   label.textColor = [UIColor colorWithWhite:0 alpha:110.0 / 255];
   label.textAlignment = NSTextAlignmentCenter;
   return label;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_promo_cell.mm b/ios/chrome/browser/ui/bookmarks/bookmark_promo_cell.mm
index 6b2534dc..319f817 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_promo_cell.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_promo_cell.mm
@@ -15,7 +15,7 @@
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #import "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -76,8 +76,7 @@
     UILabel* titleLabel = [[UILabel alloc] init];
     _titleLabel = titleLabel;
     _titleLabel.textColor = bookmark_utils_ios::darkTextColor();
-    _titleLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:16];
+    _titleLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:16];
     _titleLabel.numberOfLines = 0;
     SetTextWithLineHeight(_titleLabel,
                           l10n_util::GetNSString(IDS_IOS_BOOKMARK_PROMO_TITLE),
@@ -89,8 +88,7 @@
     UILabel* subtitleLabel = [[UILabel alloc] init];
     _subtitleLabel = subtitleLabel;
     _subtitleLabel.textColor = bookmark_utils_ios::darkTextColor();
-    _subtitleLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+    _subtitleLabel.font = [[MDCTypography fontLoader] regularFontOfSize:14];
     _subtitleLabel.numberOfLines = 0;
     SetTextWithLineHeight(
         _subtitleLabel, l10n_util::GetNSString(IDS_IOS_BOOKMARK_PROMO_MESSAGE),
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
index a78aa4f..1e5b3e3 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -62,15 +62,14 @@
   _decorationLabel = [[UILabel alloc] init];
   _decorationLabel.translatesAutoresizingMaskIntoConstraints = NO;
   _decorationLabel.text = l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_BUTTON);
-  _decorationLabel.font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12];
+  _decorationLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
   _decorationLabel.textColor = bookmark_utils_ios::lightTextColor();
   [self.contentView addSubview:_decorationLabel];
 
   _parentFolderNameLabel = [[UILabel alloc] init];
   _parentFolderNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
   _parentFolderNameLabel.font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16];
+      [[MDCTypography fontLoader] regularFontOfSize:16];
   _parentFolderNameLabel.textColor =
       [UIColor colorWithWhite:33.0 / 255.0 alpha:1.0];
   _parentFolderNameLabel.textAlignment = NSTextAlignmentNatural;
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index ef6384d..9e4e1b4 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1113,11 +1113,8 @@
 
 // Whether the sharing menu should be shown.
 - (BOOL)canShowShareMenu {
-  Tab* tab = [_model currentTab];
-  // TODO(shreyasv): Make it so the URL returned by the tab is always valid and
-  // remove check on net::NSURLWithGURL(tab.url) ( http://crbug.com/400999 ).
-  return tab && !tab.url.SchemeIs(kChromeUIScheme) &&
-         net::NSURLWithGURL(tab.url);
+  const GURL& URL = [_model currentTab].lastCommittedURL;
+  return URL.is_valid() && !web::GetWebClient()->IsAppSpecificURL(URL);
 }
 
 - (BOOL)canShowFindBar {
@@ -1596,7 +1593,7 @@
     // Create the new page image, and load with the new tab page snapshot.
     CGFloat newPageOffset = 0;
     UIImageView* newPage;
-    if (tab.url == GURL(kChromeUINewTabURL) && !_isOffTheRecord &&
+    if (tab.lastCommittedURL == GURL(kChromeUINewTabURL) && !_isOffTheRecord &&
         !IsIPadIdiom()) {
       animationParentView = self.view;
       newPage = [self pageFullScreenOpenCloseAnimationView];
@@ -2545,6 +2542,7 @@
   bool isLink = link.is_valid();
   GURL imageUrl = params.src_url;
   bool isImage = imageUrl.is_valid();
+  const GURL& committedURL = [_model currentTab].lastCommittedURL;
 
   if (isLink) {
     if (link.SchemeIs(url::kJavaScriptScheme)) {
@@ -2558,7 +2556,7 @@
     }
 
     if (web::UrlHasWebScheme(link)) {
-      web::Referrer referrer([_model currentTab].url, params.referrer_policy);
+      web::Referrer referrer(committedURL, params.referrer_policy);
 
       // Open in New Tab.
       title = l10n_util::GetNSStringWithFixup(
@@ -2608,7 +2606,7 @@
     [_contextMenuCoordinator addItemWithTitle:title action:action];
   }
   if (isImage) {
-    web::Referrer referrer([_model currentTab].url, params.referrer_policy);
+    web::Referrer referrer(committedURL, params.referrer_policy);
     // Save Image.
     title = l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_SAVEIMAGE);
     action = ^{
@@ -3115,7 +3113,7 @@
   // that native controllers vended here always correspond to the current tab.
   Tab* currentTab = [_model currentTab];
   NSString* nativeControllerKey = currentTab.tabId;
-  if (!currentTab || currentTab.url != url ||
+  if (!currentTab || currentTab.lastCommittedURL != url ||
       [[_nativeControllersForTabIDs objectForKey:nativeControllerKey]
           isKindOfClass:[nativeController class]]) {
     nativeControllerKey = kNativeControllerTemporaryKey;
@@ -4475,7 +4473,8 @@
     std::string base64HTML;
     base::Base64Encode(base::SysNSStringToUTF8(result), &base64HTML);
     GURL URL(std::string("data:text/plain;charset=utf-8;base64,") + base64HTML);
-    web::Referrer referrer([strongTab url], web::ReferrerPolicyDefault);
+    web::Referrer referrer([strongTab lastCommittedURL],
+                           web::ReferrerPolicyDefault);
 
     [[weakSelf tabModel]
         insertTabWithURL:URL
@@ -4522,7 +4521,7 @@
   ToolbarController* relinquishedToolbarController = nil;
   if ([_toolbarController view].hidden) {
     Tab* currentTab = [_model currentTab];
-    if (currentTab && UrlHasChromeScheme(currentTab.url)) {
+    if (currentTab && UrlHasChromeScheme(currentTab.lastCommittedURL)) {
       // Use the native content controller's toolbar when the BVC's is hidden.
       id nativeController = [self nativeControllerForTab:currentTab];
       if ([nativeController conformsToProtocol:@protocol(ToolbarOwner)]) {
@@ -4982,8 +4981,10 @@
 // If an added or removed bookmark is the same as the current url, update the
 // toolbar so the star highlight is kept in sync.
 - (void)bookmarkNodeModified:(const BookmarkNode*)node {
-  if ([_model currentTab] && node->url() == [_model currentTab].url)
+  if ([_model currentTab] &&
+      node->url() == [_model currentTab].lastCommittedURL) {
     [self updateToolbar];
+  }
 }
 
 // If all bookmarks are removed, update the toolbar so the star highlight is
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index 968e2e4..162e3c5 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -82,11 +82,15 @@
 @end
 
 @interface BVCTestTabMock : OCMockComplexTypeHelper {
-  GURL url_;
-  WebStateImpl* webState_;
+  GURL _url;
+  GURL _lastCommittedURL;
+  GURL _visibleURL;
+  WebStateImpl* _webState;
 }
 
 @property(nonatomic, assign) const GURL& url;
+@property(nonatomic, assign) const GURL& lastCommittedURL;
+@property(nonatomic, assign) const GURL& visibleURL;
 @property(nonatomic, assign) WebStateImpl* webState;
 
 - (web::NavigationManager*)navigationManager;
@@ -96,22 +100,34 @@
 
 @implementation BVCTestTabMock
 - (const GURL&)url {
-  return url_;
+  return _url;
 }
 - (void)setUrl:(const GURL&)url {
-  url_ = url;
+  _url = url;
+}
+- (const GURL&)lastCommittedURL {
+  return _lastCommittedURL;
+}
+- (void)setLastCommittedURL:(const GURL&)lastCommittedURL {
+  _lastCommittedURL = lastCommittedURL;
+}
+- (const GURL&)visibleURL {
+  return _visibleURL;
+}
+- (void)setVisibleURL:(const GURL&)visibleURL {
+  _visibleURL = visibleURL;
 }
 - (WebStateImpl*)webState {
-  return webState_;
+  return _webState;
 }
 - (void)setWebState:(WebStateImpl*)webState {
-  webState_ = webState;
+  _webState = webState;
 }
 - (web::NavigationManager*)navigationManager {
-  return &(webState_->GetNavigationManagerImpl());
+  return &(_webState->GetNavigationManagerImpl());
 }
 - (web::NavigationManagerImpl*)navigationManagerImpl {
-  return &(webState_->GetNavigationManagerImpl());
+  return &(_webState->GetNavigationManagerImpl());
 }
 @end
 
@@ -422,7 +438,9 @@
 TEST_F(BrowserViewControllerTest, TestSharePageCommandHandling) {
   GURL expectedUrl("http://www.testurl.net");
   NSString* expectedTitle = @"title";
-  [static_cast<BVCTestTabMock*>(tab_.get()) setUrl:expectedUrl];
+  static_cast<BVCTestTabMock*>(tab_.get()).url = expectedUrl;
+  static_cast<BVCTestTabMock*>(tab_.get()).lastCommittedURL = expectedUrl;
+  static_cast<BVCTestTabMock*>(tab_.get()).visibleURL = expectedUrl;
   OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
   ios::ChromeBrowserState* ptr = chrome_browser_state_.get();
   [[[tabMock stub] andReturnValue:OCMOCK_VALUE(ptr)] browserState];
@@ -470,8 +488,10 @@
   GURL expectedUrl("http://www.testurl.net");
   NSString* expectedTitle = @"title";
   // Sets WebState to nil because [tab close] clears the WebState.
-  [static_cast<BVCTestTabMock*>(tab_.get()) setWebState:nil];
-  [static_cast<BVCTestTabMock*>(tab_.get()) setUrl:expectedUrl];
+  static_cast<BVCTestTabMock*>(tab_.get()).webState = nil;
+  static_cast<BVCTestTabMock*>(tab_.get()).url = expectedUrl;
+  static_cast<BVCTestTabMock*>(tab_.get()).lastCommittedURL = expectedUrl;
+  static_cast<BVCTestTabMock*>(tab_.get()).visibleURL = expectedUrl;
   OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
   [[[tabMock stub] andReturn:expectedTitle] title];
   [[[tabMock stub] andReturn:expectedTitle] originalTitle];
diff --git a/ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome_unittest.mm b/ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome_unittest.mm
index 6338e732..471e6f7 100644
--- a/ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome_unittest.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome_unittest.mm
@@ -52,7 +52,7 @@
                                                      forItem:footerItem];
   };
   EXPECT_NEAR(heightForWidth(300), 50, 5);
-  EXPECT_NEAR(heightForWidth(100), 110, 5);
+  EXPECT_NEAR(heightForWidth(100), 115, 5);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.mm
index e13bbc5..838179c7 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.mm
@@ -7,7 +7,7 @@
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -140,10 +140,9 @@
   _imageView.contentMode = UIViewContentModeCenter;
   _imageView.layer.masksToBounds = YES;
 
-  _textLabel.font = [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+  _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
   _textLabel.textColor = [[MDCPalette greyPalette] tint900];
-  _detailTextLabel.font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+  _detailTextLabel.font = [[MDCTypography fontLoader] regularFontOfSize:14];
   _detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
   _imageView.contentMode = UIViewContentModeScaleAspectFit;
 }
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.mm
index ef0f9e61..1c5d40b6 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.mm
@@ -7,7 +7,7 @@
 #include <algorithm>
 
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -72,8 +72,7 @@
     _textLabel.backgroundColor = [UIColor clearColor];
     [contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
 
     _detailTextLabel = [[UILabel alloc] init];
@@ -81,8 +80,7 @@
     _detailTextLabel.backgroundColor = [UIColor clearColor];
     [contentView addSubview:_detailTextLabel];
 
-    _detailTextLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+    _detailTextLabel.font = [[MDCTypography fontLoader] regularFontOfSize:14];
     _detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
 
     // Set up the width constraints. They are activated here and updated in
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.mm
index 26ed7e8..f5ee5093 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/util/label_link_controller.h"
 #import "ios/chrome/common/string_util.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -90,8 +90,7 @@
     _imageView.translatesAutoresizingMaskIntoConstraints = NO;
     [self.contentView addSubview:_imageView];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.shadowOffset = CGSizeMake(1.f, 0.f);
     _textLabel.shadowColor = [UIColor whiteColor];
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm
index b427959b..5ab31b59 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.mm
@@ -7,7 +7,7 @@
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -67,8 +67,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [self.contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.numberOfLines = 0;
 
diff --git a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm
index f6d4a00..ac6905b 100644
--- a/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm
+++ b/ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.mm
@@ -6,7 +6,7 @@
 
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_cell.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -36,7 +36,7 @@
 
 - (UIFont*)textFont {
   if (!_textFont) {
-    _textFont = [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textFont = [[MDCTypography fontLoader] mediumFontOfSize:14];
   }
   return _textFont;
 }
@@ -50,8 +50,7 @@
 
 - (UIFont*)detailTextFont {
   if (!_detailTextFont) {
-    _detailTextFont =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+    _detailTextFont = [[MDCTypography fontLoader] regularFontOfSize:14];
   }
   return _detailTextFont;
 }
diff --git a/ios/chrome/browser/ui/contextual_search/contextual_search_promo_view.mm b/ios/chrome/browser/ui/contextual_search/contextual_search_promo_view.mm
index d7209692..f156400 100644
--- a/ios/chrome/browser/ui/contextual_search/contextual_search_promo_view.mm
+++ b/ios/chrome/browser/ui/contextual_search/contextual_search_promo_view.mm
@@ -12,7 +12,7 @@
 #include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
@@ -95,7 +95,7 @@
   NSDictionary* attributes = @{
     NSParagraphStyleAttributeName : paragraphStyle,
     NSFontAttributeName :
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:kTextFontSize],
+        [[MDCTypography fontLoader] regularFontOfSize:kTextFontSize],
     NSForegroundColorAttributeName :
         [UIColor colorWithWhite:kTextColorGrayShade alpha:1]
   };
@@ -111,7 +111,7 @@
   text.numberOfLines = 0;
 
   UIFont* buttonFont =
-      [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:kButtonFontSize];
+      [[MDCTypography fontLoader] mediumFontOfSize:kButtonFontSize];
 
   // Create accept and decline buttons with dimensions defined by the
   // minimum height and width constants.
diff --git a/ios/chrome/browser/ui/downloads/download_manager_controller.mm b/ios/chrome/browser/ui/downloads/download_manager_controller.mm
index 4895408..5ce9e54 100644
--- a/ios/chrome/browser/ui/downloads/download_manager_controller.mm
+++ b/ios/chrome/browser/ui/downloads/download_manager_controller.mm
@@ -35,7 +35,6 @@
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/web_thread.h"
@@ -869,7 +868,7 @@
     [_timeLeftLabel setFont:[MDCTypography captionFont]];
     [_fileNameLabel setFont:[MDCTypography body1Font]];
     [_errorOrSizeLabel
-        setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:10]];
+        setFont:[[MDCTypography fontLoader] regularFontOfSize:10]];
   }
 }
 
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
index b010c60b..283f5688 100644
--- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
+++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view.mm
@@ -18,7 +18,7 @@
 #include "ios/chrome/common/string_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
@@ -45,7 +45,7 @@
 // Layout constants.
 const CGFloat kImageTopPadding[SIZE_CLASS_COUNT] = {32.0, 50.0};
 const CGFloat kTOSLabelTopPadding[SIZE_CLASS_COUNT] = {34.0, 40.0};
-const CGFloat kOptInLabelTopPadding[SIZE_CLASS_COUNT] = {10.0, 14.0};
+const CGFloat kOptInLabelPadding[SIZE_CLASS_COUNT] = {10.0, 14.0};
 const CGFloat kCheckBoxPadding[SIZE_CLASS_COUNT] = {10.0, 16.0};
 const CGFloat kOKButtonBottomPadding[SIZE_CLASS_COUNT] = {32.0, 32.0};
 const CGFloat kOKButtonHeight[SIZE_CLASS_COUNT] = {36.0, 54.0};
@@ -326,8 +326,10 @@
   [self layoutTOSLabel];
   [self layoutOptInLabel];
   [self layoutCheckBoxButton];
-  [self layoutContainerView];
+  // The OK Button must be laid out before the container view so that the
+  // container view can take its position into account.
   [self layoutOKButton];
+  [self layoutContainerView];
 }
 
 - (void)layoutTitleLabel {
@@ -398,7 +400,7 @@
 
 - (void)layoutOptInLabel {
   // The opt in label is laid out to the right (or left in RTL) of the check box
-  // button and below |TOSLabel| as specified by kOptInLabelTopPadding.
+  // button and below |TOSLabel| as specified by kOptInLabelPadding.
   CGSize checkBoxSize =
       [self.checkBoxButton imageForState:self.checkBoxButton.state].size;
   CGFloat checkBoxPadding = kCheckBoxPadding[self.cr_widthSizeClass];
@@ -407,7 +409,7 @@
       sizeThatFits:CGSizeMake(CGRectGetWidth(self.containerView.bounds) -
                                   optInLabelSidePadding,
                               CGFLOAT_MAX)];
-  CGFloat optInLabelTopPadding = kOptInLabelTopPadding[self.cr_heightSizeClass];
+  CGFloat optInLabelTopPadding = kOptInLabelPadding[self.cr_heightSizeClass];
   CGFloat optInLabelOriginX =
       base::i18n::IsRTL() ? 0.0f : optInLabelSidePadding;
   self.optInLabel.frame = AlignRectOriginAndSizeToPixels(
@@ -447,12 +449,18 @@
 - (void)layoutContainerView {
   // The container view is resized according to the final layout of
   // |checkBoxButton|, which is its lowest subview.  The resized view is then
-  // centered horizontally and vertically.
+  // centered horizontally and vertically. If necessary, it is shifted up to
+  // allow |kOptInLabelPadding| between |optInLabel| and |OKButton|.
   CGSize containerViewSize = self.containerView.bounds.size;
   containerViewSize.height = CGRectGetMaxY(self.checkBoxButton.frame);
-  self.containerView.frame = AlignRectOriginAndSizeToPixels(CGRectMake(
-      (CGRectGetWidth(self.bounds) - containerViewSize.width) / 2.0,
+
+  CGFloat padding = kOptInLabelPadding[self.cr_heightSizeClass];
+  CGFloat originY = fmin(
       (CGRectGetHeight(self.bounds) - containerViewSize.height) / 2.0,
+      CGRectGetMinY(self.OKButton.frame) - padding - containerViewSize.height);
+
+  self.containerView.frame = AlignRectOriginAndSizeToPixels(CGRectMake(
+      (CGRectGetWidth(self.bounds) - containerViewSize.width) / 2.0, originY,
       containerViewSize.width, CGRectGetMaxY(self.checkBoxButton.frame)));
 }
 
@@ -485,7 +493,7 @@
 }
 
 - (void)configureTitleLabel {
-  self.titleLabel.font = [[MDFRobotoFontLoader sharedInstance]
+  self.titleLabel.font = [[MDCTypography fontLoader]
       regularFontOfSize:kTitleLabelFontSize[self.cr_widthSizeClass]];
 }
 
@@ -502,13 +510,13 @@
 }
 
 - (void)configureTOSLabel {
-  self.TOSLabel.font = [[MDFRobotoFontLoader sharedInstance]
+  self.TOSLabel.font = [[MDCTypography fontLoader]
       regularFontOfSize:kTOSLabelFontSize[self.cr_widthSizeClass]];
   self.TOSLabel.cr_lineHeight = kTOSLabelLineHeight[self.cr_widthSizeClass];
 }
 
 - (void)configureOptInLabel {
-  self.optInLabel.font = [[MDFRobotoFontLoader sharedInstance]
+  self.optInLabel.font = [[MDCTypography fontLoader]
       regularFontOfSize:kOptInLabelFontSize[self.cr_widthSizeClass]];
   self.optInLabel.cr_lineHeight = kOptInLabelLineHeight[self.cr_widthSizeClass];
 }
@@ -523,7 +531,7 @@
 }
 
 - (void)configureOKButton {
-  self.OKButton.titleLabel.font = [[MDFRobotoFontLoader sharedInstance]
+  self.OKButton.titleLabel.font = [[MDCTypography fontLoader]
       mediumFontOfSize:kOKButtonTitleLabelFontSize[self.cr_widthSizeClass]];
   CGSize size = [self.OKButton
       sizeThatFits:CGSizeMake(CGFLOAT_MAX,
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider.mm b/ios/chrome/browser/ui/history/favicon_view_provider.mm
index 2b65dbd6..d2b0c7bd 100644
--- a/ios/chrome/browser/ui/history/favicon_view_provider.mm
+++ b/ios/chrome/browser/ui/history/favicon_view_provider.mm
@@ -16,7 +16,7 @@
 #include "components/favicon_base/fallback_icon_style.h"
 #include "components/favicon_base/favicon_types.h"
 #import "ios/chrome/browser/ui/history/favicon_view.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "skia/ext/skia_utils_ios.h"
 #include "url/gurl.h"
@@ -147,7 +147,7 @@
 
     CGFloat fontSize = floorf(_faviconSize / 2);
     _faviconView.faviconFallbackLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:fontSize];
+        [[MDCTypography fontLoader] regularFontOfSize:fontSize];
   }
   return _faviconView;
 }
diff --git a/ios/chrome/browser/ui/history/history_entry_item.mm b/ios/chrome/browser/ui/history/history_entry_item.mm
index e4806c6c..08bb6d12 100644
--- a/ios/chrome/browser/ui/history/history_entry_item.mm
+++ b/ios/chrome/browser/ui/history/history_entry_item.mm
@@ -19,7 +19,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -240,18 +240,16 @@
     _faviconViewContainer = [[UIView alloc] initWithFrame:CGRectZero];
 
     _textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    [_textLabel
-        setFont:[[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:16]];
+    [_textLabel setFont:[[MDCTypography fontLoader] mediumFontOfSize:16]];
     [_textLabel setTextColor:[[MDCPalette greyPalette] tint900]];
 
     _detailTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
     [_detailTextLabel
-        setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14]];
+        setFont:[[MDCTypography fontLoader] regularFontOfSize:14]];
     [_detailTextLabel setTextColor:[[MDCPalette greyPalette] tint600]];
 
     _timeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    [_timeLabel
-        setFont:[[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14]];
+    [_timeLabel setFont:[[MDCTypography fontLoader] mediumFontOfSize:14]];
     [_timeLabel setTextColor:[[MDCPalette greyPalette] tint600]];
     _timeLabel.textAlignment =
         UseRTLLayout() ? NSTextAlignmentLeft : NSTextAlignmentRight;
diff --git a/ios/chrome/browser/ui/history/tab_history_cell.mm b/ios/chrome/browser/ui/history/tab_history_cell.mm
index b2d708a..a0a0efc 100644
--- a/ios/chrome/browser/ui/history/tab_history_cell.mm
+++ b/ios/chrome/browser/ui/history/tab_history_cell.mm
@@ -7,7 +7,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/navigation_item.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -65,8 +65,7 @@
 - (void)commonInitialization {
   _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
   [_titleLabel setTextColor:UIColorFromRGB(kTitleTextRGB)];
-  [_titleLabel
-      setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+  [_titleLabel setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
   [[self contentView] addSubview:_titleLabel];
 }
 
diff --git a/ios/chrome/browser/ui/history/tab_history_popup_controller.mm b/ios/chrome/browser/ui/history/tab_history_popup_controller.mm
index 5c6c124..fc2ede7 100644
--- a/ios/chrome/browser/ui/history/tab_history_popup_controller.mm
+++ b/ios/chrome/browser/ui/history/tab_history_popup_controller.mm
@@ -14,7 +14,7 @@
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/common/material_timing.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/navigation_item.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 #include "ui/gfx/ios/uikit_util.h"
@@ -145,7 +145,7 @@
   }
   // Increase the width to fit the text to display but don't exceed maxWidth.
   CGFloat cellWidth = kTabHistoryMinWidth;
-  UIFont* font = [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16];
+  UIFont* font = [[MDCTypography fontLoader] regularFontOfSize:16];
   for (web::NavigationItem* item : items) {
     // TODO(rohitrao): Can this be replaced with GetTitleForDisplay()?
     NSString* cellText = item->GetTitle().empty()
diff --git a/ios/chrome/browser/ui/material_components/BUILD.gn b/ios/chrome/browser/ui/material_components/BUILD.gn
index 63e674f..905795b 100644
--- a/ios/chrome/browser/ui/material_components/BUILD.gn
+++ b/ios/chrome/browser/ui/material_components/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 source_set("material_components") {
+  configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "activity_indicator.h",
     "activity_indicator.mm",
diff --git a/ios/chrome/browser/ui/material_components/activity_indicator.mm b/ios/chrome/browser/ui/material_components/activity_indicator.mm
index fc648746..e5361fd 100644
--- a/ios/chrome/browser/ui/material_components/activity_indicator.mm
+++ b/ios/chrome/browser/ui/material_components/activity_indicator.mm
@@ -7,6 +7,10 @@
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 NSArray* ActivityIndicatorBrandedCycleColors() {
 #if defined(GOOGLE_CHROME_BUILD)
   return @[
diff --git a/ios/chrome/browser/ui/material_components/app_bar_presenting.h b/ios/chrome/browser/ui/material_components/app_bar_presenting.h
index d6c6ecd..a304a60 100644
--- a/ios/chrome/browser/ui/material_components/app_bar_presenting.h
+++ b/ios/chrome/browser/ui/material_components/app_bar_presenting.h
@@ -15,7 +15,7 @@
 @protocol AppBarPresenting<NSObject>
 
 // The installed app bar, if any.
-@property(nonatomic, readonly) MDCAppBar* appBar;
+@property(nonatomic, readonly, strong) MDCAppBar* appBar;
 
 @end
 
diff --git a/ios/chrome/browser/ui/material_components/utils.mm b/ios/chrome/browser/ui/material_components/utils.mm
index 6bb5b81..7d64d0c 100644
--- a/ios/chrome/browser/ui/material_components/utils.mm
+++ b/ios/chrome/browser/ui/material_components/utils.mm
@@ -11,6 +11,10 @@
 #import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 void ConfigureAppBarWithCardStyle(MDCAppBar* appBar) {
   appBar.headerViewController.headerView.canOverExtend = NO;
   appBar.headerViewController.headerView.shiftBehavior =
diff --git a/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm b/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
index cd938591..4c1a7e5 100644
--- a/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
+++ b/ios/chrome/browser/ui/ntp/incognito_panel_controller.mm
@@ -17,7 +17,7 @@
 #import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/referrer.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -86,8 +86,7 @@
     [_containerView addSubview:incognitoImage];
 
     // Title.
-    UIFont* titleFont =
-        [[MDFRobotoFontLoader sharedInstance] lightFontOfSize:24];
+    UIFont* titleFont = [[MDCTypography fontLoader] lightFontOfSize:24];
     base::scoped_nsobject<UILabel> incognitoTabHeading(
         [[self labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_HEADING)
                           font:titleFont
@@ -95,8 +94,7 @@
     [_containerView addSubview:incognitoTabHeading];
 
     // Description paragraph.
-    UIFont* regularFont =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+    UIFont* regularFont = [[MDCTypography fontLoader] regularFontOfSize:14];
     base::scoped_nsobject<UILabel> incognitoTabDescription([[self
         labelWithString:l10n_util::GetNSString(IDS_NEW_TAB_OTR_DESCRIPTION)
                    font:regularFont
@@ -120,8 +118,7 @@
                forState:UIControlStateNormal];
     [learnMore setTitleColor:UIColorFromRGB(kLinkColor)
                     forState:UIControlStateNormal];
-    UIFont* buttonFont =
-        [[MDFRobotoFontLoader sharedInstance] boldFontOfSize:14];
+    UIFont* buttonFont = [[MDCTypography fontLoader] boldFontOfSize:14];
     [[learnMore titleLabel] setFont:buttonFont];
     [learnMore addTarget:self
                   action:@selector(learnMoreButtonPressed)
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm
index 511b962..2e2d99a8 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm
@@ -12,7 +12,7 @@
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/l10n/time_format.h"
 
@@ -49,8 +49,7 @@
     [_icon setTranslatesAutoresizingMaskIntoConstraints:NO];
     _label = [[UILabel alloc] initWithFrame:CGRectZero];
     [_label setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_label
-        setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+    [_label setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
     [_label setTextAlignment:NSTextAlignmentNatural];
     [_label setBackgroundColor:[UIColor whiteColor]];
 
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.mm
index 633129b..5d45150 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.mm
@@ -10,7 +10,6 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -44,8 +43,7 @@
     // Create and add the bar's title.
     UILabel* title = [[UILabel alloc] initWithFrame:CGRectZero];
     [title setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [title setFont:[[MDFRobotoFontLoader sharedInstance]
-                       mediumFontOfSize:kFontSize]];
+    [title setFont:[[MDCTypography fontLoader] mediumFontOfSize:kFontSize]];
     [title setTextColor:recent_tabs::GetTextColorGray()];
     [title setTextAlignment:NSTextAlignmentNatural];
     [title setText:l10n_util::GetNSString(IDS_IOS_NEW_TAB_RECENT_TABS)];
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm
index eeea4f0..0151986b 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/l10n/time_format.h"
 
@@ -57,8 +56,7 @@
     [_nameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
     [_nameLabel setHighlightedTextColor:[_nameLabel textColor]];
     [_nameLabel setTextAlignment:NSTextAlignmentNatural];
-    [_nameLabel
-        setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+    [_nameLabel setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
     [_nameLabel setBackgroundColor:[UIColor whiteColor]];
     [_nameLabel
         setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
index 8aee9c9..fc4c6f7 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
@@ -14,7 +14,7 @@
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -45,8 +45,7 @@
     _label = [[UILabel alloc] initWithFrame:CGRectZero];
     [_label setLineBreakMode:NSLineBreakByTruncatingTail];
     [_label setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_label
-        setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+    [_label setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
     [_label setTextAlignment:NSTextAlignmentNatural];
     [_label setTextColor:recent_tabs::GetTextColorGray()];
     [_label setHighlightedTextColor:[_label textColor]];
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.mm
index c0c25734..c09b36ba2 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.mm
@@ -8,7 +8,7 @@
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/views_utils.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #import "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -33,7 +33,7 @@
 
     UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
     [label setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [label setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+    [label setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
     [label setTextAlignment:NSTextAlignmentNatural];
     [label setTextColor:recent_tabs::GetTextColorGray()];
     [label setText:l10n_util::GetNSString(IDS_HISTORY_SHOWFULLHISTORY_LINK)];
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.mm
index 9202445..0e167e6 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.mm
@@ -9,7 +9,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -40,7 +40,7 @@
 
     label = [[UILabel alloc] initWithFrame:CGRectZero];
     [label setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [label setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+    [label setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
     [label setText:l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES)];
     [label setBackgroundColor:[UIColor whiteColor]];
 
diff --git a/ios/chrome/browser/ui/ntp/whats_new_header_view.mm b/ios/chrome/browser/ui/ntp/whats_new_header_view.mm
index 96301ef4..c4a7aef6 100644
--- a/ios/chrome/browser/ui/ntp/whats_new_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/whats_new_header_view.mm
@@ -10,7 +10,7 @@
 #include "ios/chrome/common/string_util.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/images/branded_image_provider.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 namespace {
 
@@ -183,8 +183,8 @@
 + (UILabel*)promoLabel {
   base::scoped_nsobject<UILabel> promoLabel(
       [[UILabel alloc] initWithFrame:CGRectZero]);
-  [promoLabel setFont:[[MDFRobotoFontLoader sharedInstance]
-                          regularFontOfSize:kLabelFontSize]];
+  [promoLabel
+      setFont:[[MDCTypography fontLoader] regularFontOfSize:kLabelFontSize]];
   [promoLabel setTextColor:UIColorFromRGB(kTextColorRgb, 1.0)];
   [promoLabel setNumberOfLines:0];
   [promoLabel setTextAlignment:NSTextAlignmentNatural];
diff --git a/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm b/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm
index f203b2f3..e0450c2 100644
--- a/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm
+++ b/ios/chrome/browser/ui/omnibox/location_bar_controller_impl.mm
@@ -27,7 +27,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #include "ios/shared/chrome/browser/ui/omnibox/location_bar_delegate.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/navigation_manager.h"
 #include "ios/web/public/ssl_status.h"
@@ -282,8 +282,7 @@
   // Set chip text options.
   [button setTitleColor:[UIColor colorWithWhite:0.631 alpha:1]
                forState:UIControlStateNormal];
-  [button titleLabel].font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12];
+  [button titleLabel].font = [[MDCTypography fontLoader] regularFontOfSize:12];
   [field_ setLeftView:button];
 
   // The placeholder image is only shown when in edit mode on iPhone, and always
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
index 3503348..1493aa7 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
@@ -25,7 +25,6 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "net/base/escape.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -472,14 +471,14 @@
   switch (type) {
     case SuggestionAnswer::TOP_ALIGNED:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12],
+        font : [[MDCTypography fontLoader] regularFontOfSize:12],
         baselineOffset : @10.0f,
         foregroundColor : [UIColor grayColor],
       };
       break;
     case SuggestionAnswer::DESCRIPTION_POSITIVE:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16],
+        font : [[MDCTypography fontLoader] regularFontOfSize:16],
         foregroundColor : [UIColor colorWithRed:11 / 255.0
                                           green:128 / 255.0
                                            blue:67 / 255.0
@@ -488,7 +487,7 @@
       break;
     case SuggestionAnswer::DESCRIPTION_NEGATIVE:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16],
+        font : [[MDCTypography fontLoader] regularFontOfSize:16],
         foregroundColor : [UIColor colorWithRed:197 / 255.0
                                           green:57 / 255.0
                                            blue:41 / 255.0
@@ -497,30 +496,30 @@
       break;
     case SuggestionAnswer::PERSONALIZED_SUGGESTION:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16],
+        font : [[MDCTypography fontLoader] regularFontOfSize:16],
       };
       break;
     case SuggestionAnswer::ANSWER_TEXT_MEDIUM:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:20],
+        font : [[MDCTypography fontLoader] regularFontOfSize:20],
         foregroundColor : [UIColor grayColor],
       };
       break;
     case SuggestionAnswer::ANSWER_TEXT_LARGE:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:24],
+        font : [[MDCTypography fontLoader] regularFontOfSize:24],
         foregroundColor : [UIColor grayColor],
       };
       break;
     case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_SMALL:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12],
+        font : [[MDCTypography fontLoader] regularFontOfSize:12],
         foregroundColor : [UIColor grayColor],
       };
       break;
     case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_MEDIUM:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14],
+        font : [[MDCTypography fontLoader] regularFontOfSize:14],
         foregroundColor : [UIColor grayColor],
       };
       break;
@@ -528,7 +527,7 @@
     // Fall through.
     default:
       attributes = @{
-        font : [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16],
+        font : [[MDCTypography fontLoader] regularFontOfSize:16],
       };
   }
 
@@ -697,8 +696,8 @@
   [as addAttributes:dict range:NSMakeRange(0, [text length])];
 
   if (classifications != NULL) {
-    UIFont* boldFontRef = [[MDFRobotoFontLoader sharedInstance]
-        mediumFontOfSize:fontRef.pointSize];
+    UIFont* boldFontRef =
+        [[MDCTypography fontLoader] mediumFontOfSize:fontRef.pointSize];
 
     for (ACMatchClassifications::const_iterator i = classifications->begin();
          i != classifications->end(); ++i) {
diff --git a/ios/chrome/browser/ui/omnibox/page_info_view_controller.mm b/ios/chrome/browser/ui/omnibox/page_info_view_controller.mm
index 5d3d3aa..baf87c3 100644
--- a/ios/chrome/browser/ui/omnibox/page_info_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/page_info_view_controller.mm
@@ -25,7 +25,6 @@
 #import "ios/chrome/common/material_timing.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
@@ -81,7 +80,7 @@
 }
 
 inline UIFont* PageInfoHeadlineFont() {
-  return [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:16];
+  return [[MDCTypography fontLoader] mediumFontOfSize:16];
 }
 
 inline CATransform3D PageInfoAnimationScale() {
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 f73f183..98db8d2 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item.mm
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/payments/cells/page_info_item.h"
 
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -72,8 +72,7 @@
 
     // Page title
     _pageTitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    _pageTitleLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:12];
+    _pageTitleLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:12];
     _pageTitleLabel.textColor = [[MDCPalette greyPalette] tint900];
     _pageTitleLabel.backgroundColor = [UIColor clearColor];
     _pageTitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -81,8 +80,7 @@
 
     // Page host
     _pageHostLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    _pageHostLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12];
+    _pageHostLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
     _pageHostLabel.textColor = [[MDCPalette greyPalette] tint600];
     // Allow the label to break to multiple lines. This should be very rare but
     // will prevent malicious domains from suppling very long host names and
diff --git a/ios/chrome/browser/ui/payments/payment_request_view_controller.mm b/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
index 7826e26..0844d86 100644
--- a/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_view_controller.mm
@@ -37,7 +37,6 @@
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ios/web/public/payments/payment_request.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
diff --git a/ios/chrome/browser/ui/reading_list/number_badge_view.mm b/ios/chrome/browser/ui/reading_list/number_badge_view.mm
index 3fd1bcea..97e86af4 100644
--- a/ios/chrome/browser/ui/reading_list/number_badge_view.mm
+++ b/ios/chrome/browser/ui/reading_list/number_badge_view.mm
@@ -8,7 +8,7 @@
 
 #include "base/format_macros.h"
 #import "ios/chrome/common/material_timing.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -46,7 +46,7 @@
 
     UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
     _label = label;
-    [label setFont:[[MDFRobotoFontLoader sharedInstance] boldFontOfSize:10]];
+    [label setFont:[[MDCTypography fontLoader] boldFontOfSize:10]];
     [label setTranslatesAutoresizingMaskIntoConstraints:NO];
     [label setTextColor:[UIColor whiteColor]];
     [self addSubview:label];
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm
index 270387c..efbe38d 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_item.mm
@@ -12,7 +12,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/time_format.h"
 #import "url/gurl.h"
@@ -249,7 +249,7 @@
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
-    MDFRobotoFontLoader* fontLoader = [MDFRobotoFontLoader sharedInstance];
+    id<MDCTypographyFontLoading> fontLoader = [MDCTypography fontLoader];
     CGFloat faviconSize = kFaviconPreferredSize;
     _titleLabel = [[UILabel alloc] init];
     _titleLabel.font = [fontLoader mediumFontOfSize:16];
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_empty_collection_background.mm b/ios/chrome/browser/ui/reading_list/reading_list_empty_collection_background.mm
index 7b7e141..c22e4f3 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_empty_collection_background.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_empty_collection_background.mm
@@ -9,7 +9,7 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -76,7 +76,7 @@
         stringByAppendingString:l10n_util::GetNSString(
                                     IDS_IOS_SHARE_MENU_READING_LIST_ACTION)];
 
-    MDFRobotoFontLoader* fontLoader = [MDFRobotoFontLoader sharedInstance];
+    id<MDCTypographyFontLoading> fontLoader = [MDCTypography fontLoader];
 
     UIColor* textColor = [[MDCPalette greyPalette] tint700];
     UIFont* textFont = [fontLoader regularFontOfSize:kFontSize];
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
index 2320cfd..793be20 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
@@ -17,7 +17,7 @@
 #import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/chrome/browser/ui/util/label_link_controller.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ios/web/public/navigation_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
@@ -313,7 +313,7 @@
              }];
 
   _footerLabelLinkController.linkFont =
-      [MDFRobotoFontLoader.sharedInstance boldFontOfSize:kFooterLabelFontSize];
+      [[MDCTypography fontLoader] boldFontOfSize:kFooterLabelFontSize];
   _footerLabelLinkController.linkUnderlineStyle = NSUnderlineStyleSingle;
   NSRange linkRange = [label.text rangeOfString:linkText];
   DCHECK(linkRange.location != NSNotFound);
@@ -351,7 +351,7 @@
     [_titleLabel
         setTextColor:[UIColor colorWithWhite:kTitleLabelTextColorBrightness
                                        alpha:1.0]];
-    [_titleLabel setFont:[[MDFRobotoFontLoader sharedInstance]
+    [_titleLabel setFont:[[MDCTypography fontLoader]
                              regularFontOfSize:kTitleLabelFontSize]];
   }
   return _titleLabel;
@@ -366,7 +366,7 @@
     [_messageTextView
         setTextColor:[UIColor colorWithWhite:kGeneralTextColorBrightness
                                        alpha:1.0]];
-    [_messageTextView setFont:[[MDFRobotoFontLoader sharedInstance]
+    [_messageTextView setFont:[[MDCTypography fontLoader]
                                   regularFontOfSize:kMessageTextViewFontSize]];
   }
   return _messageTextView;
@@ -377,7 +377,7 @@
     _footerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
     [_footerLabel setBackgroundColor:self.backgroundColor];
     [_footerLabel setNumberOfLines:0];
-    [_footerLabel setFont:[[MDFRobotoFontLoader sharedInstance]
+    [_footerLabel setFont:[[MDCTypography fontLoader]
                               regularFontOfSize:kFooterLabelFontSize]];
     [_footerLabel
         setTextColor:[UIColor colorWithWhite:kGeneralTextColorBrightness
diff --git a/ios/chrome/browser/ui/settings/cells/account_signin_item.mm b/ios/chrome/browser/ui/settings/cells/account_signin_item.mm
index 911fb4d..bf83bde4 100644
--- a/ios/chrome/browser/ui/settings/cells/account_signin_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/account_signin_item.mm
@@ -7,7 +7,7 @@
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -91,10 +91,9 @@
   _imageView.contentMode = UIViewContentModeCenter;
   _imageView.layer.masksToBounds = YES;
   _imageView.contentMode = UIViewContentModeScaleAspectFit;
-  _textLabel.font = [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+  _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
   _textLabel.textColor = [[MDCPalette greyPalette] tint900];
-  _detailTextLabel.font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+  _detailTextLabel.font = [[MDCTypography fontLoader] regularFontOfSize:14];
   _detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
 }
 
diff --git a/ios/chrome/browser/ui/settings/cells/autofill_data_item.mm b/ios/chrome/browser/ui/settings/cells/autofill_data_item.mm
index 31b72340..5b886570 100644
--- a/ios/chrome/browser/ui/settings/cells/autofill_data_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/autofill_data_item.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/settings/cells/autofill_data_item.h"
 
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -85,19 +85,19 @@
 
 // Sets default font and text colors for labels.
 - (void)setDefaultViewStyling {
-  _textLabel.font = [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+  _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
   _textLabel.textColor = [[MDCPalette greyPalette] tint900];
   _textLabel.numberOfLines = 0;
   _textLabel.lineBreakMode = NSLineBreakByWordWrapping;
 
   _leadingDetailTextLabel.font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+      [[MDCTypography fontLoader] regularFontOfSize:14];
   _leadingDetailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
   _leadingDetailTextLabel.numberOfLines = 0;
   _leadingDetailTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
 
   _trailingDetailTextLabel.font =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:12];
+      [[MDCTypography fontLoader] regularFontOfSize:12];
   _trailingDetailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
 }
 
diff --git a/ios/chrome/browser/ui/settings/cells/card_multiline_item.mm b/ios/chrome/browser/ui/settings/cells/card_multiline_item.mm
index 2fcdb5b..4e47ea0 100644
--- a/ios/chrome/browser/ui/settings/cells/card_multiline_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/card_multiline_item.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/settings/cells/card_multiline_item.h"
 
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -53,8 +53,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] regularFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.numberOfLines = 0;
 
diff --git a/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.mm b/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.mm
index ad4011f2..2157ed5 100644
--- a/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/copied_to_chrome_item.mm
@@ -9,7 +9,7 @@
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -54,8 +54,7 @@
     _button.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_button];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.text =
         l10n_util::GetNSString(IDS_IOS_AUTOFILL_DESCRIBE_LOCAL_COPY);
diff --git a/ios/chrome/browser/ui/settings/cells/encryption_item.mm b/ios/chrome/browser/ui/settings/cells/encryption_item.mm
index d22d8ba..13b76b0 100644
--- a/ios/chrome/browser/ui/settings/cells/encryption_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/encryption_item.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/settings/cells/encryption_item.h"
 
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -70,8 +70,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [self.contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.numberOfLines = 0;
 
     // Set up the constraints.
diff --git a/ios/chrome/browser/ui/settings/cells/import_data_multiline_detail_cell.mm b/ios/chrome/browser/ui/settings/cells/import_data_multiline_detail_cell.mm
index 060c7ce..5c97d5e 100644
--- a/ios/chrome/browser/ui/settings/cells/import_data_multiline_detail_cell.mm
+++ b/ios/chrome/browser/ui/settings/cells/import_data_multiline_detail_cell.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/settings/cells/import_data_multiline_detail_cell.h"
 
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -34,16 +34,14 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
 
     _detailTextLabel = [[UILabel alloc] init];
     _detailTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_detailTextLabel];
 
-    _detailTextLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:14];
+    _detailTextLabel.font = [[MDCTypography fontLoader] regularFontOfSize:14];
     _detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
     _detailTextLabel.numberOfLines = 0;
 
diff --git a/ios/chrome/browser/ui/settings/cells/native_app_item.mm b/ios/chrome/browser/ui/settings/cells/native_app_item.mm
index aad554b..c0c0d3f 100644
--- a/ios/chrome/browser/ui/settings/cells/native_app_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/native_app_item.mm
@@ -10,7 +10,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -88,8 +88,7 @@
     _nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_nameLabel];
 
-    _nameLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _nameLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _nameLabel.textColor = [[MDCPalette greyPalette] tint900];
 
     _switchControl = [[UISwitch alloc] init];
diff --git a/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm b/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm
index ab4e158..dd7c80f0 100644
--- a/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/passphrase_error_item.mm
@@ -8,7 +8,7 @@
 
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -54,8 +54,7 @@
 
     _textLabel = [[UILabel alloc] init];
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette cr_redPalette] tint500];
     [contentView addSubview:_textLabel];
 
diff --git a/ios/chrome/browser/ui/settings/cells/password_details_item.mm b/ios/chrome/browser/ui/settings/cells/password_details_item.mm
index 9a59dcde1..3752974 100644
--- a/ios/chrome/browser/ui/settings/cells/password_details_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/password_details_item.mm
@@ -9,7 +9,7 @@
 
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -67,8 +67,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.numberOfLines = 0;
 
diff --git a/ios/chrome/browser/ui/settings/cells/sync_switch_item.mm b/ios/chrome/browser/ui/settings/cells/sync_switch_item.mm
index d8191ee5..0c411d7b 100644
--- a/ios/chrome/browser/ui/settings/cells/sync_switch_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/sync_switch_item.mm
@@ -7,7 +7,7 @@
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -80,8 +80,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [self.contentView addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.numberOfLines = 0;
 
@@ -89,8 +88,7 @@
     _detailTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
     [self.contentView addSubview:_detailTextLabel];
 
-    _detailTextLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _detailTextLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _detailTextLabel.textColor = [[MDCPalette greyPalette] tint500];
     _detailTextLabel.numberOfLines = 0;
 
diff --git a/ios/chrome/browser/ui/settings/cells/text_and_error_item.mm b/ios/chrome/browser/ui/settings/cells/text_and_error_item.mm
index 4adf9d6..7281b08 100644
--- a/ios/chrome/browser/ui/settings/cells/text_and_error_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/text_and_error_item.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/foundation_util.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -89,8 +89,7 @@
     self.contentView.clipsToBounds = YES;
     _textLabel = [[UILabel alloc] init];
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
     _textLabel.numberOfLines = 0;
     [self.contentView addSubview:_textLabel];
diff --git a/ios/chrome/browser/ui/settings/cells/version_item.mm b/ios/chrome/browser/ui/settings/cells/version_item.mm
index cb8b3cf..239e7ff 100644
--- a/ios/chrome/browser/ui/settings/cells/version_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/version_item.mm
@@ -6,7 +6,7 @@
 
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -54,8 +54,7 @@
     _textLabel.shadowColor = [UIColor whiteColor];
     [self addSubview:_textLabel];
 
-    _textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
     _textLabel.textColor = [[MDCPalette greyPalette] tint900];
 
     // Set up the constraints.
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
index 71b7c41..5c1f13d5 100644
--- a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
@@ -39,7 +39,6 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "url/gurl.h"
@@ -320,7 +319,7 @@
     CardMultilineCell* messageCell =
         base::mac::ObjCCastStrict<CardMultilineCell>(cell);
     messageCell.textLabel.font =
-        [[MDFRobotoFontLoader sharedInstance] mediumFontOfSize:14];
+        [[MDCTypography fontLoader] mediumFontOfSize:14];
   }
   return cell;
 }
diff --git a/ios/chrome/browser/ui/static_content/BUILD.gn b/ios/chrome/browser/ui/static_content/BUILD.gn
index b0be5865..61ec53e 100644
--- a/ios/chrome/browser/ui/static_content/BUILD.gn
+++ b/ios/chrome/browser/ui/static_content/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 source_set("static_content") {
+  configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "static_html_native_content.h",
     "static_html_native_content.mm",
diff --git a/ios/chrome/browser/ui/static_content/static_html_native_content.h b/ios/chrome/browser/ui/static_content/static_html_native_content.h
index 3c4f6594..f4c4f75 100644
--- a/ios/chrome/browser/ui/static_content/static_html_native_content.h
+++ b/ios/chrome/browser/ui/static_content/static_html_native_content.h
@@ -55,7 +55,7 @@
 // The overscroll actions controller of the native content.
 // Setting this value to non-nil will enable Overscroll Actions.
 // Invalidated when |close| is called on this object.
-@property(nonatomic, assign)
+@property(nonatomic, strong)
     OverscrollActionsController* overscrollActionsController;
 
 @end
diff --git a/ios/chrome/browser/ui/static_content/static_html_native_content.mm b/ios/chrome/browser/ui/static_content/static_html_native_content.mm
index 5c151b9..c7255d4 100644
--- a/ios/chrome/browser/ui/static_content/static_html_native_content.mm
+++ b/ios/chrome/browser/ui/static_content/static_html_native_content.mm
@@ -5,12 +5,15 @@
 #import "ios/chrome/browser/ui/static_content/static_html_native_content.h"
 
 #include "base/logging.h"
-#import "base/mac/scoped_nsobject.h"
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
 #include "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
 #import "ios/chrome/browser/ui/url_loader.h"
 #include "ios/web/public/referrer.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 @interface StaticHtmlNativeContent ()
 // Designated initializer.
 - (instancetype)initWithLoader:(id<UrlLoader>)loader
@@ -25,12 +28,11 @@
   BOOL _webUsageEnabled;
   // The static HTML view controller that is used to display the content in
   // a web view.
-  base::scoped_nsobject<StaticHtmlViewController> _staticHTMLViewController;
+  StaticHtmlViewController* _staticHTMLViewController;
   // Responsible for loading a particular URL.
   id<UrlLoader> _loader;  // weak
   // The controller handling the overscroll actions.
-  base::scoped_nsobject<OverscrollActionsController>
-      _overscrollActionsController;
+  OverscrollActionsController* _overscrollActionsController;
 }
 
 #pragma mark -
@@ -47,7 +49,7 @@
     [HTMLViewController setLoader:loader referrer:referrer];
     _URL = URL;
     _loader = loader;
-    _staticHTMLViewController.reset([HTMLViewController retain]);
+    _staticHTMLViewController = HTMLViewController;
   }
   return self;
 }
@@ -60,9 +62,9 @@
   DCHECK(browserState);
   DCHECK(URL.is_valid());
   DCHECK(resourcePath);
-  base::scoped_nsobject<StaticHtmlViewController> HTMLViewController(
+  StaticHtmlViewController* HTMLViewController =
       [[StaticHtmlViewController alloc] initWithResource:resourcePath
-                                            browserState:browserState]);
+                                            browserState:browserState];
   return [self initWithLoader:loader
       staticHTMLViewController:HTMLViewController
                            URL:URL];
@@ -70,7 +72,6 @@
 
 - (void)dealloc {
   [[self scrollView] setDelegate:nil];
-  [super dealloc];
 }
 
 - (void)loadURL:(const GURL&)URL
@@ -84,12 +85,12 @@
 }
 
 - (OverscrollActionsController*)overscrollActionsController {
-  return _overscrollActionsController.get();
+  return _overscrollActionsController;
 }
 
 - (void)setOverscrollActionsController:
     (OverscrollActionsController*)controller {
-  _overscrollActionsController.reset([controller retain]);
+  _overscrollActionsController = controller;
   [[self scrollView] setDelegate:controller];
 }
 
@@ -155,7 +156,7 @@
   }
   _webUsageEnabled = webUsageEnabled;
   if (!_webUsageEnabled) {
-    _staticHTMLViewController.reset();
+    _staticHTMLViewController = nil;
   }
 }
 
diff --git a/ios/chrome/browser/ui/static_content/static_html_view_controller.h b/ios/chrome/browser/ui/static_content/static_html_view_controller.h
index 070e246e..639b5e1 100644
--- a/ios/chrome/browser/ui/static_content/static_html_view_controller.h
+++ b/ios/chrome/browser/ui/static_content/static_html_view_controller.h
@@ -50,7 +50,7 @@
 @interface StaticHtmlViewController : NSObject
 
 // The web view that is displaying the content. It is lazily created.
-@property(nonatomic, readonly) WKWebView* webView;
+@property(nonatomic, readonly, weak) WKWebView* webView;
 
 // Returns the web controller scrollview.
 - (UIScrollView*)scrollView;
diff --git a/ios/chrome/browser/ui/static_content/static_html_view_controller.mm b/ios/chrome/browser/ui/static_content/static_html_view_controller.mm
index 1b3b069..2cb8d194 100644
--- a/ios/chrome/browser/ui/static_content/static_html_view_controller.mm
+++ b/ios/chrome/browser/ui/static_content/static_html_view_controller.mm
@@ -8,11 +8,9 @@
 
 #include <stdlib.h>
 
-#import "base/ios/weak_nsobject.h"
 #include "base/logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
 #include "ios/web/public/referrer.h"
 #import "ios/web/public/web_state/ui/crw_context_menu_delegate.h"
 #import "ios/web/public/web_state/ui/crw_native_content.h"
@@ -21,6 +19,10 @@
 #include "ui/base/page_transition_types.h"
 #include "ui/base/resource/resource_bundle.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 @implementation IdrHtmlGenerator
 - (id)initWithResourceId:(int)resourceId encoding:(NSStringEncoding)encoding {
   if ((self = [super init])) {
@@ -37,10 +39,9 @@
 - (void)generateHtml:(HtmlCallback)callback {
   base::StringPiece html(
       ResourceBundle::GetSharedInstance().GetRawDataResource(resourceId_));
-  base::scoped_nsobject<NSString> result([[NSString alloc]
-      initWithBytes:html.data()
-             length:html.size()
-           encoding:encoding_]);
+  NSString* result = [[NSString alloc] initWithBytes:html.data()
+                                              length:html.size()
+                                            encoding:encoding_];
   callback(result);
 }
 @end
@@ -55,32 +56,32 @@
   // If the page is displaying a local HTML file, it contains the file URL to
   // the file.
   // If the page is a generated HTML, it contains a random resource URL.
-  base::scoped_nsobject<NSURL> resourceUrl_;
+  NSURL* resourceUrl_;
 
   // If the view is displaying a local file, contains the URL of the root
   // directory containing all resources needed by the page.
   // The web view will get access to this page.
-  base::scoped_nsobject<NSURL> resourcesRootDirectory_;
+  NSURL* resourcesRootDirectory_;
 
   // If the view is displaying a resources, contains the name of the resource.
-  base::scoped_nsobject<NSString> resource_;
+  NSString* resource_;
 
   // If the view displayes a generated HTML, contains the |HtmlGenerator| to
   // generate it.
-  base::scoped_nsprotocol<id<HtmlGenerator>> generator_;
+  id<HtmlGenerator> generator_;
 
   // Browser state associated with the view controller, used to create the
   // WKWebView.
   web::BrowserState* browserState_;  // Weak.
 
   // The web view that is used to display the content.
-  base::scoped_nsobject<WKWebView> webView_;
+  WKWebView* webView_;
 
   // The delegate of the native content.
-  base::WeakNSProtocol<id<CRWNativeContentDelegate>> delegate_;  // weak
+  __weak id<CRWNativeContentDelegate> delegate_;
 
   // The loader to navigate from the page.
-  base::WeakNSProtocol<id<UrlLoader>> loader_;  // weak
+  __weak id<UrlLoader> loader_;
 }
 
 // Returns the URL of the static page to display.
@@ -100,7 +101,7 @@
   DCHECK(resource);
   DCHECK(browserState);
   if ((self = [super init])) {
-    resource_.reset([resource copy]);
+    resource_ = [resource copy];
     browserState_ = browserState;
   }
   return self;
@@ -111,7 +112,7 @@
   DCHECK(generator);
   DCHECK(browserState);
   if ((self = [super init])) {
-    generator_.reset([generator retain]);
+    generator_ = generator;
     browserState_ = browserState;
   }
   return self;
@@ -124,8 +125,8 @@
   DCHECK(URL.SchemeIsFile());
   DCHECK(browserState);
   if ((self = [super init])) {
-    resourceUrl_.reset([net::NSURLWithGURL(URL) retain]);
-    resourcesRootDirectory_.reset([net::NSURLWithGURL(resourcesRoot) retain]);
+    resourceUrl_ = net::NSURLWithGURL(URL);
+    resourcesRootDirectory_ = net::NSURLWithGURL(resourcesRoot);
     browserState_ = browserState;
   }
   return self;
@@ -133,7 +134,6 @@
 
 - (void)dealloc {
   [self removeWebViewObservers];
-  [super dealloc];
 }
 
 - (void)removeWebViewObservers {
@@ -142,7 +142,7 @@
 
 - (void)setLoader:(id<UrlLoader>)loader
          referrer:(const web::Referrer&)referrer {
-  loader_.reset(loader);
+  loader_ = loader;
   referrer_ = referrer;
 }
 
@@ -162,11 +162,11 @@
 
 - (void)handleLowMemory {
   [self removeWebViewObservers];
-  webView_.reset();
+  webView_ = nil;
 }
 
 - (BOOL)isViewAlive {
-  return webView_.get() != nil;
+  return webView_ != nil;
 }
 
 - (NSString*)title {
@@ -190,7 +190,7 @@
 }
 
 - (void)setDelegate:(id<CRWNativeContentDelegate>)delegate {
-  delegate_.reset(delegate);
+  delegate_ = delegate;
 }
 
 - (void)setScrollEnabled:(BOOL)enabled {
@@ -263,14 +263,14 @@
 
 - (NSURL*)resourceURL {
   if (resourceUrl_)
-    return resourceUrl_.get();
+    return resourceUrl_;
 
   DCHECK(resource_ || generator_);
   NSString* path = nil;
   if (resource_) {
     NSBundle* bundle = base::mac::FrameworkBundle();
     NSString* bundlePath = [bundle bundlePath];
-    path = [bundlePath stringByAppendingPathComponent:resource_.get()];
+    path = [bundlePath stringByAppendingPathComponent:resource_];
   } else {
     // Generate a random resource URL to whitelist the load in
     // |webView:shouldStartLoadWithRequest:navigationType:| method.
@@ -281,13 +281,12 @@
   // Necessary because the |fileURLWithPath:| method adds a localhost in the
   // URL, and this prevents the URL from being comparable with the ones that
   // UIWebView uses when calling the delegate.
-  base::scoped_nsobject<NSURLComponents> components(
-      [[NSURLComponents alloc] init]);
+  NSURLComponents* components = [[NSURLComponents alloc] init];
   [components setScheme:@"file"];
   [components setHost:@""];
   [components setPath:path];
-  resourceUrl_.reset([[components URL] retain]);
-  resourcesRootDirectory_.reset([resourceUrl_ copy]);
+  resourceUrl_ = [components URL];
+  resourcesRootDirectory_ = [resourceUrl_ copy];
   return resourceUrl_;
 }
 
@@ -300,7 +299,7 @@
                                  UIViewAutoresizingFlexibleHeight];
     [self loadWebViewContents:webView];
     [webView setNavigationDelegate:self];
-    webView_.reset([webView retain]);
+    webView_ = webView;
   }
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
index ec849a6..dac8116 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
@@ -14,7 +14,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #import "ios/third_party/material_text_accessibility_ios/src/src/MDFTextAccessibility.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
@@ -167,8 +167,8 @@
     // Title label.
     _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
     [_titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_titleLabel setFont:[[MDFRobotoFontLoader sharedInstance]
-                             regularFontOfSize:kFontSize]];
+    [_titleLabel
+        setFont:[[MDCTypography fontLoader] regularFontOfSize:kFontSize]];
     [_topBar addSubview:_titleLabel];
 
     // Favicon.
@@ -354,8 +354,8 @@
     [_titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
     [_titleLabel setNumberOfLines:5];
     [_titleLabel setTextAlignment:NSTextAlignmentCenter];
-    [_titleLabel setFont:[[MDFRobotoFontLoader sharedInstance]
-                             regularFontOfSize:kFontSize]];
+    [_titleLabel
+        setFont:[[MDCTypography fontLoader] regularFontOfSize:kFontSize]];
     [_verticallyCenteredView addSubview:_titleLabel];
 
     // Create and add new tab icon to |_verticallyCenteredContent|.
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
index b21d580..9ceeae4 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -33,7 +33,7 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/shared/chrome/browser/ui/tools_menu/tools_menu_configuration.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -403,7 +403,7 @@
 }
 
 - (UIFont*)fontForSize:(NSInteger)size {
-  return [[MDFRobotoFontLoader sharedInstance] boldFontOfSize:size];
+  return [[MDCTypography fontLoader] boldFontOfSize:size];
 }
 
 - (void)dealloc {
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
index 9db0a61..0392cd8 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_item.mm
@@ -6,7 +6,7 @@
 
 #include "base/i18n/rtl.h"
 #include "base/mac/objc_property_releaser.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
@@ -99,7 +99,7 @@
 - (void)initializeTitleView {
   _title = [[UILabel alloc] initWithFrame:self.bounds];
   [_title setTranslatesAutoresizingMaskIntoConstraints:NO];
-  [_title setFont:[[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]];
+  [_title setFont:[[MDCTypography fontLoader] regularFontOfSize:16]];
   [_title setBackgroundColor:[self backgroundColor]];
   [_title setTextAlignment:(base::i18n::IsRTL() ? NSTextAlignmentRight
                                                 : NSTextAlignmentLeft)];
diff --git a/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm b/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm
index 0693e45..2b4e0e2 100644
--- a/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm
+++ b/ios/chrome/browser/ui/util/manual_text_framer_unittest.mm
@@ -8,7 +8,7 @@
 #include "base/time/time.h"
 #import "ios/chrome/browser/ui/util/core_text_util.h"
 #import "ios/chrome/browser/ui/util/text_frame.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -19,12 +19,8 @@
 #endif
 
 namespace {
-// Copy of ManualTextFramer's alignment function.
-enum class AlignmentFunction : short { CEIL = 0, FLOOR };
-CGFloat AlignValueToPixel(CGFloat value, AlignmentFunction function) {
-  static CGFloat scale = [[UIScreen mainScreen] scale];
-  return function == AlignmentFunction::CEIL ? ceil(value * scale) / scale
-                                             : floor(value * scale) / scale;
+void ExpectNearPoint(CGFloat value1, CGFloat value2) {
+  EXPECT_NEAR(value1, value2, 1);
 }
 
 class ManualTextFramerTest : public PlatformTest {
@@ -51,8 +47,8 @@
     text_frame_ = frame;
   }
 
-  UIFont* RobotoFontWithSize(CGFloat size) {
-    return [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:size];
+  UIFont* TypographyFontWithSize(CGFloat size) {
+    return [[MDCTypography fontLoader] regularFontOfSize:size];
   }
 
   NSParagraphStyle* CreateParagraphStyle(CGFloat line_height,
@@ -88,7 +84,7 @@
 // multiple lines.
 TEST_F(ManualTextFramerTest, NewlineTest) {
   SetText(@"line one\nline two\nline three");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -103,7 +99,7 @@
   // whirlpool of Llantysilio of the red cave."
   SetText(
       @"Llanfair­pwllgwyngyll­gogery­chwyrn­drobwll­llan­tysilio­gogo­goch");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(16.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -128,7 +124,7 @@
 // corresponds with the actual range of the text.
 TEST_F(ManualTextFramerTest, LigatureTest) {
   SetText(@"fffi");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -140,7 +136,7 @@
 // Tests that ManualTextFramer correctly frames Å
 TEST_F(ManualTextFramerTest, DiacriticTest) {
   SetText(@"A\u030A");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -158,7 +154,7 @@
   NSString* const kTOSText =
       @"By using this application, you agree to Chrome’s Terms of Service.";
   SetText(kTOSText);
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentCenter, NSLineBreakByTruncatingTail);
   attributes()[NSForegroundColorAttributeName] = [UIColor blackColor];
@@ -172,7 +168,7 @@
 // Tests that the origin of a left-aligned single line is correct.
 TEST_F(ManualTextFramerTest, SimpleOriginTest) {
   SetText(@"test");
-  UIFont* font = RobotoFontWithSize(14.0);
+  UIFont* font = TypographyFontWithSize(14.0);
   attributes()[NSFontAttributeName] = font;
   CGFloat line_height = 20.0;
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
@@ -183,10 +179,8 @@
   CheckForLineCountAndFramedRange(1, text_range());
   FramedLine* line = [text_frame().lines firstObject];
   EXPECT_EQ(0, line.origin.x);
-  EXPECT_EQ(
-      AlignValueToPixel(CGRectGetHeight(bounds) - line_height - font.descender,
-                        AlignmentFunction::FLOOR),
-      line.origin.y);
+  ExpectNearPoint(CGRectGetHeight(bounds) - line_height - font.descender,
+                  line.origin.y);
 }
 
 // Tests that lines that are laid out in RTL are right aligned.
@@ -200,7 +194,7 @@
           @"\u064e\u0649\u0020\u0627\u0644\u0648\u064e\u0642\u0652\u062a\u0650"
           @"\u0020\u002e\u0020\u0641\u064e\u0627\u0644\u062d\u064e\u064a\u064e"
           @"\u0627\u0629\u064f");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -208,10 +202,9 @@
   FrameTextInBounds(bounds);
   CheckForLineCountAndFramedRange(3, text_range());
   for (FramedLine* line in text_frame().lines) {
-    CGFloat line_width =
-        AlignValueToPixel(core_text_util::GetTrimmedLineWidth(line.line),
-                          AlignmentFunction::CEIL);
-    EXPECT_EQ(CGRectGetMaxX(bounds), line.origin.x + line_width);
+    ExpectNearPoint(
+        CGRectGetMaxX(bounds),
+        line.origin.x + core_text_util::GetTrimmedLineWidth(line.line));
   }
 }
 
@@ -222,7 +215,7 @@
   SetText(@"“触摸搜索”会将所选字词和当前页面(作为上下文)一起发送给 Google 搜索。"
           @"您可以在设置中停用此功能。");
   // clang-format on
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(16.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       16 * 1.15, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -231,11 +224,9 @@
   CheckForLineCountAndFramedRange(3, NSMakeRange(0, 53));
 
   // Example without any space-ish characters:
-  // clang-format off
   SetText(@"会将所选字词和当前页面(作为上下文)一起发送给Google搜索。"
           @"您可以在设置中停用此功能。");
-  // clang-format on
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(16.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(16.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       16 * 1.15, NSTextAlignmentNatural, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -246,7 +237,7 @@
 // Tests that paragraphs with NSTextAlignmentCenter are actually centered.
 TEST_F(ManualTextFramerTest, CenterAlignedTest) {
   SetText(@"xxxx\nyyy\nwww");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
@@ -254,12 +245,9 @@
   FrameTextInBounds(bounds);
   CheckForLineCountAndFramedRange(3, text_range());
   for (FramedLine* line in text_frame().lines) {
-    CGFloat line_width =
-        AlignValueToPixel(core_text_util::GetTrimmedLineWidth(line.line),
-                          AlignmentFunction::CEIL);
-    EXPECT_EQ(AlignValueToPixel(CGRectGetMidX(bounds) - 0.5 * line_width,
-                                AlignmentFunction::FLOOR),
-              line.origin.x);
+    ExpectNearPoint(CGRectGetMidX(bounds) -
+                        0.5 * core_text_util::GetTrimmedLineWidth(line.line),
+                    line.origin.x);
   }
 }
 
@@ -267,7 +255,7 @@
 // fit in the bounding height.
 TEST_F(ManualTextFramerTest, LargeLineHeightTest) {
   SetText(@"the last word is very LARGE");
-  attributes()[NSFontAttributeName] = RobotoFontWithSize(14.0);
+  attributes()[NSFontAttributeName] = TypographyFontWithSize(14.0);
   attributes()[NSParagraphStyleAttributeName] = CreateParagraphStyle(
       20.0, NSTextAlignmentCenter, NSLineBreakByWordWrapping);
   ApplyAttributesForRange(text_range());
diff --git a/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm b/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm
index 319450a..770b3415 100644
--- a/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm
+++ b/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm
@@ -6,7 +6,7 @@
 
 #include "base/mac/foundation_util.h"
 #include "ios/chrome/browser/ui/util/text_region_mapper.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -120,7 +120,7 @@
   NSMutableDictionary* attributes = [NSMutableDictionary
       dictionaryWithDictionary:AttributesForTextAlignment(NSTextAlignmentLeft)];
   attributes[NSFontAttributeName] =
-      [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16];
+      [[MDCTypography fontLoader] regularFontOfSize:16];
   NSAttributedString* string =
       [[NSAttributedString alloc] initWithString:CJKString
                                       attributes:attributes];
diff --git a/ios/clean/chrome/app/BUILD.gn b/ios/clean/chrome/app/BUILD.gn
index 2966dd8..21655ec 100644
--- a/ios/clean/chrome/app/BUILD.gn
+++ b/ios/clean/chrome/app/BUILD.gn
@@ -53,12 +53,14 @@
 
   extra_substitutions = [
     "CHROMIUM_BUNDLE_ID=$output_name",
+    "CHROMIUM_HANDOFF_ID=$chromium_handoff_id",
     "CHROMIUM_SHORT_NAME=$output_name",
     "CHROMIUM_URL_SCHEME_1=$url_unsecure_scheme",
     "CHROMIUM_URL_SCHEME_2=$url_secure_scheme",
     "CHROMIUM_URL_SCHEME_3=$url_x_callback_scheme",
     "CHROMIUM_URL_SCHEME_4=$url_channel_scheme",
     "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix",
+    "SSOAUTH_URL_SCHEME=$url_ssoauth_scheme",
   ]
 
   if (ios_encryption_export_compliance_code != "") {
diff --git a/ios/showcase/core/app_delegate.mm b/ios/showcase/core/app_delegate.mm
index 5fdc493..12f1a43 100644
--- a/ios/showcase/core/app_delegate.mm
+++ b/ios/showcase/core/app_delegate.mm
@@ -9,8 +9,6 @@
 #import "ios/showcase/core/showcase_model.h"
 #import "ios/showcase/core/showcase_view_controller.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MDCTypographyAdditions/MDFRobotoFontLoader+MDCTypographyAdditions.h"
-#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -25,7 +23,6 @@
   base::MakeUnique<IOSChromeMain>();
   ResourceBundle::InitSharedInstanceWithLocale(
       std::string(), nullptr, ResourceBundle::LOAD_COMMON_RESOURCES);
-  [MDCTypography setFontLoader:[MDFRobotoFontLoader sharedInstance]];
   self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   ShowcaseViewController* viewController =
       [[ShowcaseViewController alloc] initWithRows:[self rowsToDisplay]];
diff --git a/media/base/android/media_codec_loop.cc b/media/base/android/media_codec_loop.cc
index c6c13cf7..a3c1eda 100644
--- a/media/base/android/media_codec_loop.cc
+++ b/media/base/android/media_codec_loop.cc
@@ -39,15 +39,15 @@
     int sdk_int,
     Client* client,
     std::unique_ptr<MediaCodecBridge> media_codec,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner)
     : state_(STATE_READY),
       client_(client),
       media_codec_(std::move(media_codec)),
       pending_input_buf_index_(kInvalidBufferIndex),
       sdk_int_(sdk_int),
       weak_factory_(this) {
-  if (task_runner)
-    io_timer_.SetTaskRunner(task_runner);
+  if (timer_task_runner)
+    io_timer_.SetTaskRunner(timer_task_runner);
   // TODO(liberato): should this DCHECK?
   if (media_codec_ == nullptr)
     SetState(STATE_ERROR);
diff --git a/media/base/android/media_codec_loop.h b/media/base/android/media_codec_loop.h
index 2ee738c..15110fe 100644
--- a/media/base/android/media_codec_loop.h
+++ b/media/base/android/media_codec_loop.h
@@ -11,7 +11,9 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -101,10 +103,6 @@
 //    |             |
 // [Ready]       [Error]
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace media {
 
 class MEDIA_EXPORT MediaCodecLoop {
@@ -197,15 +195,15 @@
     virtual ~Client() {}
   };
 
-  // We will take ownership of |media_codec|.  We will not destroy it until
-  // we are destructed.  |media_codec| may not be null.
-  // |sdk_level| is temporary.  It is used only to decouple MediaCodecLoop from
-  // BuildInfo, until we get BuildInfo into a mockable state.
+  // We will take ownership of |media_codec|.  We will not destroy it until we
+  // are destructed.  |media_codec| may not be null. |sdk_level| is temporary.
+  // It is used only to decouple MediaCodecLoop from BuildInfo, until we get
+  // BuildInfo into a mockable state. If |timer_task_runner| is non-null,
+  // timers are redirected to it.
   MediaCodecLoop(int sdk_level,
                  Client* client,
                  std::unique_ptr<MediaCodecBridge> media_codec,
-                 scoped_refptr<base::SingleThreadTaskRunner> =
-                     scoped_refptr<base::SingleThreadTaskRunner>());
+                 scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner);
   ~MediaCodecLoop();
 
   // Optionally set the tick clock used for testing.  It is our caller's
diff --git a/media/base/android/media_codec_loop_unittest.cc b/media/base/android/media_codec_loop_unittest.cc
index 8396e3b..5c034e48 100644
--- a/media/base/android/media_codec_loop_unittest.cc
+++ b/media/base/android/media_codec_loop_unittest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "media/base/android/media_codec_loop.h"
+
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "media/base/android/media_codec_bridge.h"
-#include "media/base/android/media_codec_loop.h"
 #include "media/base/android/mock_media_codec_bridge.h"
-#include "media/base/fake_single_thread_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,8 +48,8 @@
 class MediaCodecLoopTest : public testing::Test {
  public:
   MediaCodecLoopTest()
-      : client_(new StrictMock<MockMediaCodecLoopClient>()),
-        task_runner_(new FakeSingleThreadTaskRunner(&clock_)) {}
+      : task_runner_handle_(mock_task_runner_),
+        client_(new StrictMock<MockMediaCodecLoopClient>()) {}
 
   ~MediaCodecLoopTest() override {}
 
@@ -84,7 +86,7 @@
 
     // TODO(liberato): assume that MCL doesn't retry for 30 seconds.  Note
     // that this doesn't actually wall-clock wait.
-    task_runner_->Sleep(base::TimeDelta::FromSeconds(30));
+    mock_task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(30));
   }
 
   void ConstructCodecLoop(int sdk_int = kLollipop) {
@@ -92,8 +94,8 @@
     // Since we're providing a codec, we do not expect an error.
     EXPECT_CALL(*client_, OnCodecLoopError()).Times(0);
     codec_loop_.reset(new MediaCodecLoop(sdk_int, client_.get(),
-                                         std::move(codec), task_runner_));
-    codec_loop_->SetTestTickClock(&clock_);
+                                         std::move(codec), mock_task_runner_));
+    codec_loop_->SetTestTickClock(clock_.get());
     Mock::VerifyAndClearExpectations(client_.get());
   }
 
@@ -182,12 +184,18 @@
   }
 
  public:
+  // Mocks the current thread's task runner which will also be used as the
+  // MediaCodecLoop's task runner.
+  scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_ =
+      new base::TestMockTimeTaskRunner;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
+
+  // A reference to |mock_task_runner_|'s TickClock handed to |codec_loop_|.
+  std::unique_ptr<base::TickClock> clock_ =
+      mock_task_runner_->GetMockTickClock();
+
   std::unique_ptr<MediaCodecLoop> codec_loop_;
   std::unique_ptr<MockMediaCodecLoopClient> client_;
-  // TODO: how is the lifecycle of |clock_| handled?  |task_runner_| can outlive
-  // us, since it's a refptr.
-  base::SimpleTestTickClock clock_;
-  scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest);
 };
@@ -197,7 +205,8 @@
   EXPECT_CALL(*client_, OnCodecLoopError()).Times(1);
   const int sdk_int = kLollipop;
   codec_loop_.reset(
-      new MediaCodecLoop(sdk_int, client_.get(), std::move(codec)));
+      new MediaCodecLoop(sdk_int, client_.get(), std::move(codec),
+                         scoped_refptr<base::SingleThreadTaskRunner>()));
   // Do not WaitUntilIdle() here, since that assumes that we have a codec.
 
   ASSERT_FALSE(codec_loop_->GetCodec());
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
index 357b903..4442331 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
@@ -216,7 +216,12 @@
         // with at least one element, but when the camera is in bad state, they
         // can return null pointers; in that case we use a 0 entry, so we can
         // retrieve as much information as possible.
-        List<Integer> pixelFormats = parameters.getSupportedPreviewFormats();
+        List<Integer> pixelFormats = null;
+        try {
+            pixelFormats = parameters.getSupportedPreviewFormats();
+        } catch (NullPointerException ex) {
+            Log.e(TAG, "Camera.Parameters.getSupportedPreviewFormats: ", ex);
+        }
         if (pixelFormats == null) {
             pixelFormats = new ArrayList<Integer>();
         }
@@ -231,7 +236,12 @@
                 continue;
             }
 
-            List<int[]> listFpsRange = parameters.getSupportedPreviewFpsRange();
+            List<int[]> listFpsRange = null;
+            try {
+                listFpsRange = parameters.getSupportedPreviewFpsRange();
+            } catch (StringIndexOutOfBoundsException ex) {
+                Log.e(TAG, "Camera.Parameters.getSupportedPreviewFpsRange: ", ex);
+            }
             if (listFpsRange == null) {
                 listFpsRange = new ArrayList<int[]>();
             }
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index 81e392d..1a25383 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -291,7 +291,7 @@
 
     private Range<Integer> mAeFpsRange;
     private CameraState mCameraState = CameraState.STOPPED;
-    private final float mMaxZoom;
+    private float mMaxZoom = 1.0f;
     private Rect mCropRect = new Rect();
     private int mPhotoWidth;
     private int mPhotoHeight;
@@ -314,7 +314,7 @@
                         Context.CAMERA_SERVICE);
         try {
             return manager.getCameraCharacteristics(Integer.toString(id));
-        } catch (CameraAccessException ex) {
+        } catch (CameraAccessException | IllegalArgumentException ex) {
             Log.e(TAG, "getCameraCharacteristics: ", ex);
         }
         return null;
@@ -571,12 +571,18 @@
     }
 
     static int getNumberOfCameras() {
-        final CameraManager manager =
-                (CameraManager) ContextUtils.getApplicationContext().getSystemService(
-                        Context.CAMERA_SERVICE);
+        CameraManager manager = null;
+        try {
+            manager = (CameraManager) ContextUtils.getApplicationContext().getSystemService(
+                    Context.CAMERA_SERVICE);
+        } catch (IllegalArgumentException ex) {
+            Log.e(TAG, "getSystemService(Context.CAMERA_SERVICE): ", ex);
+            return 0;
+        }
+        if (manager == null) return 0;
         try {
             return manager.getCameraIdList().length;
-        } catch (CameraAccessException | SecurityException ex) {
+        } catch (CameraAccessException | SecurityException | AssertionError ex) {
             // SecurityException is undocumented but seen in the wild: https://crbug/605424.
             Log.e(TAG, "getNumberOfCameras: getCameraIdList(): ", ex);
             return 0;
@@ -656,8 +662,10 @@
     VideoCaptureCamera2(int id, long nativeVideoCaptureDeviceAndroid) {
         super(id, nativeVideoCaptureDeviceAndroid);
         final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(id);
-        mMaxZoom =
-                cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
+        if (cameraCharacteristics != null) {
+            mMaxZoom = cameraCharacteristics.get(
+                    CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
+        }
     }
 
     @Override
diff --git a/media/filters/android/media_codec_audio_decoder.cc b/media/filters/android/media_codec_audio_decoder.cc
index 0fe3b81..8a7d48fc4 100644
--- a/media/filters/android/media_codec_audio_decoder.cc
+++ b/media/filters/android/media_codec_audio_decoder.cc
@@ -140,7 +140,8 @@
 
   codec_loop_.reset(
       new MediaCodecLoop(base::android::BuildInfo::GetInstance()->sdk_int(),
-                         this, std::move(audio_codec_bridge)));
+                         this, std::move(audio_codec_bridge),
+                         scoped_refptr<base::SingleThreadTaskRunner>()));
 
   return true;
 }
diff --git a/net/disk_cache/disk_cache_perftest.cc b/net/disk_cache/disk_cache_perftest.cc
index 5151d34..7f473d18a 100644
--- a/net/disk_cache/disk_cache_perftest.cc
+++ b/net/disk_cache/disk_cache_perftest.cc
@@ -221,9 +221,9 @@
        file_path = enumerator.Next()) {
     ASSERT_TRUE(base::EvictFileFromSystemCache(file_path));
   }
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_ANDROID)
   // And, cache directories, on platforms where the eviction utility supports
-  // this (currently Linux only).
+  // this (currently Linux and Android only).
   if (simple_cache_mode_) {
     ASSERT_TRUE(
         base::EvictFileFromSystemCache(cache_path_.AppendASCII("index-dir")));
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index e838cbe..68e3d36 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -1625,25 +1625,6 @@
   return true;
 }
 
-bool TransportSecurityState::IsGooglePinnedHost(const std::string& host) const {
-  DCHECK(CalledOnValidThread());
-
-  if (!IsBuildTimely())
-    return false;
-
-  PreloadResult result;
-  if (!DecodeHSTSPreload(host, &result))
-    return false;
-
-  if (!result.has_pins)
-    return false;
-
-  if (result.pinset_id >= arraysize(kPinsets))
-    return false;
-
-  return kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts;
-}
-
 bool TransportSecurityState::GetDynamicSTSState(const std::string& host,
                                                 STSState* result) {
   DCHECK(CalledOnValidThread());
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h
index 19ba839..614762ee 100644
--- a/net/http/transport_security_state.h
+++ b/net/http/transport_security_state.h
@@ -484,12 +484,6 @@
                             STSState* sts_result,
                             PKPState* pkp_result) const;
 
-  // Returns true iff there is static (built-in) state for |host| that
-  // references the Google pins.
-  // TODO(rch): Remove this temporary gross layering violation once QUIC 32 is
-  // deployed.
-  bool IsGooglePinnedHost(const std::string& host) const;
-
   // Returns true and updates |*result| iff |host| has HSTS/HPKP/Expect-CT
   // (respectively) state. If multiple entries match |host|, the most specific
   // match determines the return value.
diff --git a/sandbox/mac/sandbox_mac_compiler_unittest.mm b/sandbox/mac/sandbox_mac_compiler_unittest.mm
index c04d89f..eea5959 100644
--- a/sandbox/mac/sandbox_mac_compiler_unittest.mm
+++ b/sandbox/mac/sandbox_mac_compiler_unittest.mm
@@ -11,6 +11,7 @@
 #include "base/test/multiprocess_test.h"
 #include "base/test/test_timeouts.h"
 #include "sandbox/mac/sandbox_compiler.h"
+#include "sandbox/mac/seatbelt.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/multiprocess_func_list.h"
 
@@ -162,4 +163,27 @@
   EXPECT_EQ(exit_code, 0);
 }
 
+MULTIPROCESS_TEST_MAIN(SandboxCheckTestProcess) {
+  CHECK(!Seatbelt::IsSandboxed());
+  std::string profile =
+      "(version 1)"
+      "(deny default (with no-log))";
+
+  SandboxCompiler compiler(profile);
+  std::string error;
+  CHECK(compiler.CompileAndApplyProfile(&error));
+  CHECK(Seatbelt::IsSandboxed());
+
+  return 0;
+}
+
+TEST_F(SandboxMacCompilerTest, SandboxCheckTest) {
+  base::SpawnChildResult spawn_child = SpawnChild("SandboxCheckTestProcess");
+  ASSERT_TRUE(spawn_child.process.IsValid());
+  int exit_code = 42;
+  EXPECT_TRUE(spawn_child.process.WaitForExitWithTimeout(
+      TestTimeouts::action_max_timeout(), &exit_code));
+  EXPECT_EQ(exit_code, 0);
+}
+
 }  // namespace sandbox
diff --git a/sandbox/mac/seatbelt.cc b/sandbox/mac/seatbelt.cc
index 0987fae..dfba0bd 100644
--- a/sandbox/mac/seatbelt.cc
+++ b/sandbox/mac/seatbelt.cc
@@ -4,6 +4,8 @@
 
 #include "sandbox/mac/seatbelt.h"
 
+#include <unistd.h>
+
 extern "C" {
 #include <sandbox.h>
 
@@ -11,6 +13,12 @@
                                  uint64_t flags,
                                  const char* const parameters[],
                                  char** errorbuf);
+
+// Not deprecated. The canonical usage to test if sandboxed is
+// sandbox_check(getpid(), NULL, SANDBOX_FILTER_NONE), which returns
+// 1 if sandboxed. Note `type` is actually a sandbox_filter_type enum value, but
+// it is unused currently.
+int sandbox_check(pid_t pid, const char* operation, int type, ...);
 };
 
 namespace sandbox {
@@ -54,4 +62,9 @@
 #pragma clang diagnostic pop
 }
 
+// static
+bool Seatbelt::IsSandboxed() {
+  return ::sandbox_check(getpid(), NULL, 0);
+}
+
 }  // namespace sandbox
diff --git a/sandbox/mac/seatbelt.h b/sandbox/mac/seatbelt.h
index 2a5db08..f1971590 100644
--- a/sandbox/mac/seatbelt.h
+++ b/sandbox/mac/seatbelt.h
@@ -17,15 +17,28 @@
 // This class wraps the functions in deprecation warning supressions.
 class SEATBELT_EXPORT Seatbelt {
  public:
+  // Initializes the specified sandbox profile. Returns 0 on success, else -1
+  // and |errorbuf| is populated. |errorbuf| is allocated by the API and must be
+  // freed with FreeError().
   static int Init(const char* profile, uint64_t flags, char** errorbuf);
 
+  // Initializes the specified sandbox profile and passes the parameters to the
+  // |profile|. |parameters| is a null terminated list containing key,value
+  // pairs in sequence. [key1,val1,key2,val2,nullptr]. |errorbuf| is allocated
+  // by the API and is set to a string description of the error. |errorbuf| must
+  // be freed with FreeError(). This function eturns 0 on success, else -1 and
+  // |errorbuf| is populated.
   static int InitWithParams(const char* profile,
                             uint64_t flags,
                             const char* const parameters[],
                             char** errorbuf);
 
+  // Frees the |errorbuf| allocated and set by InitWithParams.
   static void FreeError(char* errorbuf);
 
+  // Returns whether or not the process is currently sandboxed.
+  static bool IsSandboxed();
+
   static const char* kProfileNoInternet;
 
   static const char* kProfileNoNetwork;
diff --git a/testing/buildbot/filters/mojo.fyi.browser_tests.filter b/testing/buildbot/filters/mojo.fyi.browser_tests.filter
index 7b564c9..ba0b591 100644
--- a/testing/buildbot/filters/mojo.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.browser_tests.filter
@@ -11,7 +11,6 @@
 -BrowserTest.Title
 
 # Trying to whitelist
-BootstrapTest.CleanUpFailedUser
 BrowserDialogTest.Invoke
 CastSessionBrowserTest.CreateAndDestroy
 ChromeContentRendererClientSearchBoxTest.RewriteThumbnailURL
@@ -21,7 +20,6 @@
 ChromeRenderViewTest.ImagesBlockedByDefault
 ChromeRenderViewTest.JSBlockSentAfterPageLoad
 ChromeRenderViewTest.PluginsTemporarilyAllowed
-ContentVerifierPolicyTest.PolicyCorruptedOnStartup
 CreateNewFolder/FileManagerBrowserTest.Test/0
 CreateNewFolder/FileManagerBrowserTest.Test/1
 CreateNewFolder/FileManagerBrowserTest.Test/2
@@ -89,7 +87,6 @@
 FormClassifierTest.kChangeFormWithTreePasswordFieldsHTML
 InstantProcessNavigationTest.ForkForNavigationsFromInstantProcess
 InstantProcessNavigationTest.ForkForNavigationsToSearchURLs
-MultiProfileFileManagerBrowserTest.BasicDownloads
 PageClickTrackerTest.PageClickTrackerClickDisabledInputDoesNotResetClickCounter
 PageClickTrackerTest.PageClickTrackerDisabledInputClickedNoEvent
 PageClickTrackerTest.PageClickTrackerInputClicked
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index ce871ca1..3f8a6f08 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -146,10 +146,6 @@
     "type": "raw",
     "args": [],
   },
-  "aura_builder": {
-    "label": "//:aura_builder",
-    "type": "additional_compile_target",
-  },
   "aura_unittests": {
     "label": "//ui/aura:aura_unittests",
     "type": "windowed_test_launcher",
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py
index b407493..e733af78 100755
--- a/testing/buildbot/manage.py
+++ b/testing/buildbot/manage.py
@@ -139,7 +139,6 @@
 
   # These targets are listed only in build-side recipes.
   'All_syzygy',
-  'aura_builder',
   'blink_tests',
   'cast_shell',
   'cast_shell_apk',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index a97de45..04889da5 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3184,12 +3184,25 @@
             ],
             "experiments": [
                 {
+                    "name": "Query",
+                    "params": {
+                        "translate-ranker-model-url": "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/translate/2017/03/translate_ranker_model_20170329.pb.bin"
+                    },
+                    "enable_features": [
+                        "TranslateRankerQuery"
+                    ],
+                    "disable_features": [
+                        "TranslateRankerEnforcement"
+                    ]
+                },
+                {
                     "name": "Enforcement",
                     "params": {
                         "translate-ranker-model-url": "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/translate/2017/03/translate_ranker_model_20170329.pb.bin"
                     },
                     "enable_features": [
-                        "TranslateRankerEnforcement"
+                        "TranslateRankerEnforcement",
+                        "TranslateRankerQuery"
                     ]
                 }
             ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 791d316..2729ef4 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -25,10 +25,6 @@
 Bug(718942) virtual/mojo-loading/http/tests/security/contentSecurityPolicy/1.1/form-action-src-redirect-blocked.html [ Failure ]
 Bug(718942) virtual/off-main-thread-fetch/http/tests/misc/onload-detach-during-csp-frame-src-none.html [ Failure ]
 
-# PlzNavigate: A few line are missing in InspectorTest.dumpServiceWorkersView()
-Bug(725818) http/tests/inspector/service-workers/service-workers-redundant.html [ Failure ]
-Bug(725818) virtual/off-main-thread-fetch/http/tests/inspector/service-workers/service-workers-redundant.html [ Failure ]
-
 # PlzNavigate: Navigation requests upgraded via upgrade-insecure-requests will not get reported	
 # See https://crbug.com/713388
 Bug(713388) external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
index ad43abf1..edc37dca3 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -2745,7 +2745,6 @@
 Bug(none) http/tests/serviceworker/ServiceWorkerGlobalScope/registration-attribute.html [ Failure ]
 Bug(none) http/tests/serviceworker/ServiceWorkerGlobalScope/unregister.html [ Failure ]
 Bug(none) http/tests/serviceworker/ServiceWorkerGlobalScope/update.html [ Failure ]
-Bug(none) http/tests/serviceworker/sync-xhr-doesnt-deadlock.html [ Failure ]
 Bug(none) http/tests/serviceworker/waiting.html [ Failure ]
 Bug(none) http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Failure ]
 Bug(none) http/tests/serviceworker/websocket/websocket-in-service-worker.html [ Failure ]
@@ -3557,12 +3556,12 @@
 Bug(none) presentation/presentation-start.html [ Timeout ]
 Bug(none) presentation/presentationconnectionavailableevent-ctor-mock.html [ Timeout ]
 Bug(none) printing/subframes-percentage-height.html [ Failure ]
-Bug(none) sensor/absolute-orientation-sensor.html [ Timeout ]
 Bug(none) sensor/accelerometer.html [ Timeout ]
 Bug(none) sensor/ambient-light-sensor.html [ Timeout ]
 Bug(none) sensor/gyroscope.html [ Timeout ]
 Bug(none) sensor/magnetometer.html [ Timeout ]
 Bug(none) sensor/mock-sensor.html [ Timeout ]
+Bug(none) sensor/orientation-sensor.html [ Timeout ]
 Bug(none) shapedetection/detection-HTMLCanvasElement.html [ Timeout ]
 Bug(none) shapedetection/detection-HTMLImageElement.html [ Timeout ]
 Bug(none) shapedetection/detection-HTMLVideoElement.html [ Timeout ]
@@ -4601,7 +4600,6 @@
 Bug(none) virtual/mojo-loading/http/tests/serviceworker/ServiceWorkerGlobalScope/registration-attribute.html [ Failure ]
 Bug(none) virtual/mojo-loading/http/tests/serviceworker/ServiceWorkerGlobalScope/unregister.html [ Failure ]
 Bug(none) virtual/mojo-loading/http/tests/serviceworker/ServiceWorkerGlobalScope/update.html [ Failure ]
-Bug(none) virtual/mojo-loading/http/tests/serviceworker/sync-xhr-doesnt-deadlock.html [ Failure ]
 Bug(none) virtual/mojo-loading/http/tests/serviceworker/waiting.html [ Failure ]
 Bug(none) virtual/mojo-loading/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Failure ]
 Bug(none) virtual/mojo-loading/http/tests/serviceworker/websocket/websocket-in-service-worker.html [ Failure ]
@@ -5172,7 +5170,6 @@
 Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/ServiceWorkerGlobalScope/registration-attribute.html [ Failure ]
 Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/ServiceWorkerGlobalScope/unregister.html [ Failure ]
 Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/ServiceWorkerGlobalScope/update.html [ Failure ]
-Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/sync-xhr-doesnt-deadlock.html [ Failure ]
 Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/waiting.html [ Failure ]
 Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ Failure ]
 Bug(none) virtual/off-main-thread-fetch/http/tests/serviceworker/websocket/websocket-in-service-worker.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index b9ba46a..78b70c5a 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -502,7 +502,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-in-inline-percents-001.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-non-replaced-height-005.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-non-replaced-width-007.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-replaced-width-002.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-replaced-width-006.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/blocks-013.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/blocks-017.xht [ Failure ]
@@ -553,13 +552,7 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-non-replaced-height-002.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-replaced-height-008.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-valign-002.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-non-replaced-height-002.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-non-replaced-height-003.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-height-008.xht [ Skip ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-001.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-002.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-003.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-006.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-012.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-013.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-015.xht [ Failure ]
@@ -596,6 +589,7 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-081.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-082.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-090.xht [ Failure ]
+crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-replaced-width-006.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-092.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-093.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/max-height-101.xht [ Failure ]
@@ -737,8 +731,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/positioning-float-002.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/relpos-calcs-004.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/relpos-calcs-005.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-007.xht [ Crash ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-008.xht [ Crash ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-019.xht [ Crash Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-020.xht [ Crash Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-031.xht [ Crash Failure ]
@@ -758,7 +750,7 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-113.xht [ Crash Failure ]
 
 ### virtual/layout_ng/fast/block/basic
-crbug.com/635619 virtual/layout_ng/fast/block/basic/003.html [ Failure ]
+crbug.com/635619 virtual/layout_ng/fast/block/basic/001.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/basic/006.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/basic/011.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/basic/013.html [ Failure ]
@@ -825,7 +817,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/canvas-with-floats-marked-for-layout.html [ Crash ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/centered-float-avoidance-complexity.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/checkbox-and-radio-avoid-floats.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/clamped-right-float.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-element-too-wide-for-containing-block.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-intruding-floats-when-moving-to-inline-parent-3.html [ Crash Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/clear-to-fit.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 2effa99f..40c11b0e 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -4137,6 +4137,18 @@
      {}
     ]
    ],
+   "assumptions/ahem.html": [
+    [
+     "/assumptions/ahem.html",
+     [
+      [
+       "/assumptions/ahem-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "assumptions/canvas-background.html": [
     [
      "/assumptions/canvas-background.html",
@@ -63719,6 +63731,11 @@
      {}
     ]
    ],
+   "assumptions/ahem-ref.html": [
+    [
+     {}
+    ]
+   ],
    "assumptions/canvas-background-ref.html": [
     [
      {}
@@ -63759,16 +63776,6 @@
      {}
     ]
    ],
-   "battery-status/battery-iframe.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "battery-status/battery-insecure-context-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "battery-status/support-iframe.html": [
     [
      {}
@@ -80284,11 +80291,6 @@
      {}
     ]
    ],
-   "custom-elements/reactions/DOMTokenList-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "custom-elements/reactions/HTMLElement-expected.txt": [
     [
      {}
@@ -80729,11 +80731,6 @@
      {}
     ]
    ],
-   "dom/nodes/Element-classlist-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "dom/nodes/Element-closest-expected.txt": [
     [
      {}
@@ -82384,6 +82381,11 @@
      {}
     ]
    ],
+   "fullscreen/api/document-exit-fullscreen-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "fullscreen/api/document-exit-fullscreen-timing-manual-expected.txt": [
     [
      {}
@@ -82409,6 +82411,11 @@
      {}
     ]
    ],
+   "fullscreen/api/element-request-fullscreen-and-exit-iframe-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "fullscreen/api/element-request-fullscreen-and-move-manual-expected.txt": [
     [
      {}
@@ -82429,6 +82436,16 @@
      {}
     ]
    ],
+   "fullscreen/api/element-request-fullscreen-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "fullscreen/api/element-request-fullscreen-not-allowed-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "fullscreen/api/element-request-fullscreen-timing-manual-expected.txt": [
     [
      {}
@@ -82454,6 +82471,31 @@
      {}
     ]
    ],
+   "fullscreen/model/move-to-iframe-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "fullscreen/model/remove-first-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "fullscreen/model/remove-last-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "fullscreen/model/remove-parent-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "fullscreen/model/remove-single-manual-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "fullscreen/trusted-click.js": [
     [
      {}
@@ -91939,6 +91981,11 @@
      {}
     ]
    ],
+   "html/semantics/interactive-elements/the-menu-element/menuitem-label-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/interactive-elements/the-summary-element/.gitkeep": [
     [
      {}
@@ -144017,6 +144064,12 @@
      {}
     ]
    ],
+   "payment-request/payment-request-abort-method.https.html": [
+    [
+     "/payment-request/payment-request-abort-method.https.html",
+     {}
+    ]
+   ],
    "payment-request/payment-request-constructor.https.html": [
     [
      "/payment-request/payment-request-constructor.https.html",
@@ -162661,7 +162714,7 @@
    "support"
   ],
   "./update-built-tests.sh": [
-   "75ea35a5ce9d8e3e32e8d0c336dc12e04691d16a",
+   "99b5beb84b30521fa4c4a8a061acc309ee3d0d4a",
    "support"
   ],
   "./wptrun": [
@@ -170720,6 +170773,14 @@
    "b9ba0287c92e5dbda1dc207ab45e9c90e8618878",
    "reftest"
   ],
+  "assumptions/ahem-ref.html": [
+   "f38cdd07d07558540e19c2b2ec063dbc54f8be7f",
+   "support"
+  ],
+  "assumptions/ahem.html": [
+   "e097b6e6eb9ecf107cea94b3984661cc62c7ac67",
+   "reftest"
+  ],
   "assumptions/canvas-background-ref.html": [
    "0868a5443b1aacb8fd95327bc7c71d071158b0f1",
    "support"
@@ -170796,18 +170857,10 @@
    "0fb90d807a27ce9e78dab040926effc1be7f71be",
    "manual"
   ],
-  "battery-status/battery-iframe.https-expected.txt": [
-   "eb6453b6d1c328ffc20afdbb96fe5d7602a7c1d1",
-   "support"
-  ],
   "battery-status/battery-iframe.https.html": [
    "b4df9429c1ff9ace253fb40296b20c06f8eb5eb3",
    "testharness"
   ],
-  "battery-status/battery-insecure-context-expected.txt": [
-   "6be1447d61155d2656c958a00674ea311031b8eb",
-   "support"
-  ],
   "battery-status/battery-insecure-context.html": [
    "39639373d161846186cbcb7eb33466493bcc77ad",
    "testharness"
@@ -207164,10 +207217,6 @@
    "ad0b3fd9ec6ac895c2abd6685e23bc92b60f0733",
    "testharness"
   ],
-  "custom-elements/reactions/DOMTokenList-expected.txt": [
-   "f4b61b6ed54590d0e65611c03fe9061a2fedbe8d",
-   "support"
-  ],
   "custom-elements/reactions/DOMTokenList.html": [
    "7482fa56e7f4d95cfe8b8f337a9b5e63a83a6e9d",
    "testharness"
@@ -207189,7 +207238,7 @@
    "testharness"
   ],
   "custom-elements/reactions/HTMLElement-expected.txt": [
-   "f30c19c462c4b322553f38401106b2f70442e1c7",
+   "fd027b233d354d933eb260def242be36ea6bccf8",
    "support"
   ],
   "custom-elements/reactions/HTMLElement.html": [
@@ -207537,7 +207586,7 @@
    "testharness"
   ],
   "dom/interfaces-expected.txt": [
-   "ee2b93473877f87d12dd9649452df2ed89706fab",
+   "133f60942eae89418f507d7cea7cee10d3f0e4b0",
    "support"
   ],
   "dom/interfaces.html": [
@@ -208132,10 +208181,6 @@
    "e3fe31ea198922fe64fbf985ae99d1cd4512567a",
    "testharness"
   ],
-  "dom/nodes/Element-classlist-expected.txt": [
-   "3e610f97449595d17e58504e9dc2f9733562aa90",
-   "support"
-  ],
   "dom/nodes/Element-classlist.html": [
    "c197df35960b77a7794eed10a1a927867a6658f4",
    "testharness"
@@ -211612,6 +211657,10 @@
    "b4010cb68f5fa7f97e8d405e67977335e6a00795",
    "testharness"
   ],
+  "fullscreen/api/document-exit-fullscreen-manual-expected.txt": [
+   "c167856f71136c06d7733118f4def0c248989394",
+   "support"
+  ],
   "fullscreen/api/document-exit-fullscreen-manual.html": [
    "398a52fc8728e07771249c017baf0c1867c4ea44",
    "manual"
@@ -211700,6 +211749,10 @@
    "f8c6c1a63b5738a442bcf01c09535d4bb48512a7",
    "testharness"
   ],
+  "fullscreen/api/element-request-fullscreen-and-exit-iframe-manual-expected.txt": [
+   "a473d95d2e72c45121680fc47ced9dcba2d73145",
+   "support"
+  ],
   "fullscreen/api/element-request-fullscreen-and-exit-iframe-manual.html": [
    "870575cb59c5a7f76097e19da8b3854120d6cb86",
    "manual"
@@ -211736,6 +211789,10 @@
    "86c1ac20aa86e860cfa8f05a9873f3a3cddbdcd9",
    "manual"
   ],
+  "fullscreen/api/element-request-fullscreen-manual-expected.txt": [
+   "b14caf034cd09dc2d84c76042c6ce66c3b85d8e2",
+   "support"
+  ],
   "fullscreen/api/element-request-fullscreen-manual.html": [
    "ed7683b3c4a7134b640e07a7329a21361b122402",
    "manual"
@@ -211744,6 +211801,10 @@
    "c346255bb659b952d8d27b2ab136e7815c1161d9",
    "manual"
   ],
+  "fullscreen/api/element-request-fullscreen-not-allowed-expected.txt": [
+   "c0be9280569576bb9e14a1e339bb90e335892c2b",
+   "support"
+  ],
   "fullscreen/api/element-request-fullscreen-not-allowed.html": [
    "8991e8df530fa7c24a9e084f2ab17fa9c70fb120",
    "testharness"
@@ -211801,13 +211862,17 @@
    "testharness"
   ],
   "fullscreen/interfaces-expected.txt": [
-   "ad9dbeb1ee339c858138e3bab0827eca418de781",
+   "d22cb0ab5f83fd919fcce3e334ca6916405c9945",
    "support"
   ],
   "fullscreen/interfaces.html": [
    "f6f0dbc8a505896a0e7ec7aca2746bbd5c1eb7d9",
    "testharness"
   ],
+  "fullscreen/model/move-to-iframe-manual-expected.txt": [
+   "e7019c27330910de32ea2a7f0283377e6dd1cb75",
+   "support"
+  ],
   "fullscreen/model/move-to-iframe-manual.html": [
    "818cb1b5db729db4959591dc75d4bb1ae3c7542d",
    "manual"
@@ -211816,18 +211881,34 @@
    "b1142930c6c972057213bd477cf116fcc9e7fc2a",
    "manual"
   ],
+  "fullscreen/model/remove-first-manual-expected.txt": [
+   "ef976589b9898457661d8304518a5013776b8681",
+   "support"
+  ],
   "fullscreen/model/remove-first-manual.html": [
    "3de98ae96822370fa80c1b8d61df254910a63ff9",
    "manual"
   ],
+  "fullscreen/model/remove-last-manual-expected.txt": [
+   "6813bede8236c163823407e7abbba719bed2c177",
+   "support"
+  ],
   "fullscreen/model/remove-last-manual.html": [
    "8caa21a892edeaba9996a7f2bf1c670385e0a91b",
    "manual"
   ],
+  "fullscreen/model/remove-parent-manual-expected.txt": [
+   "0e4526d0b0bd833feed4ddedd2c35ae7d6a904f8",
+   "support"
+  ],
   "fullscreen/model/remove-parent-manual.html": [
    "e5791db04ab5e2b75a00c922457fcc8ba87c7ce7",
    "manual"
   ],
+  "fullscreen/model/remove-single-manual-expected.txt": [
+   "9d0112ef4bf35d3a6a80e2dcb836b4c57ca850e2",
+   "support"
+  ],
   "fullscreen/model/remove-single-manual.html": [
    "c7fc8323d503adb6d7f0c390a8add90c5c9e8082",
    "manual"
@@ -216409,7 +216490,7 @@
    "testharness"
   ],
   "html/dom/reflection-misc-expected.txt": [
-   "f2046b22833fa1c167a8e898ce4c6f814937d0f2",
+   "a2a204d95b1c8dd8691e6572d9cdf6b64739a73f",
    "support"
   ],
   "html/dom/reflection-misc.html": [
@@ -224132,6 +224213,10 @@
    "a79ad27e8f1e2eee47c89fa4530f7babfbb07dd5",
    "support"
   ],
+  "html/semantics/interactive-elements/the-menu-element/menuitem-label-expected.txt": [
+   "237def2c38478a46dbaf16029c5c2b2d5ff04993",
+   "support"
+  ],
   "html/semantics/interactive-elements/the-menu-element/menuitem-label.html": [
    "d11f6d0ef667da33d7981860b47e6d02f8c0ad24",
    "testharness"
@@ -224145,7 +224230,7 @@
    "testharness"
   ],
   "html/semantics/interfaces-expected.txt": [
-   "66b9d2904c0b48ff310813f23947c8f27d45b1ec",
+   "5bde359d32efb77ff7ed13a3bc646eade3a92d8d",
    "support"
   ],
   "html/semantics/interfaces.html": [
@@ -224581,7 +224666,7 @@
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-cycle.js": [
-   "462fe462bf92e1df232228cc1ce338ff522febbd",
+   "e9cad195e5e718080c21f7cf15a58a775a1226de",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-inc-a.js": [
@@ -224601,11 +224686,11 @@
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-self.js": [
-   "26b832413187999e45c0520e171f5fc61a911b20",
+   "a18743fbd553b68e0ceb657a5d65e3424e6f6a52",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports.html": [
-   "997cee37dcd202498196e63e0f66035979121b7f",
+   "15b0b32d86bc6411b29c5d978db71053c00a1d65",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html": [
@@ -236712,8 +236797,12 @@
    "29af302db74de64e2bd1352ad92092a309d28c92",
    "testharness"
   ],
+  "payment-request/payment-request-abort-method.https.html": [
+   "c9ee5af2ccd5ad364090807c8427f1d4624d3747",
+   "testharness"
+  ],
   "payment-request/payment-request-constructor.https.html": [
-   "12cb2d46800b03554830fb145f2d8dca37043f79",
+   "44d2656f2990c51063254326521a02218a7fc500",
    "testharness"
   ],
   "payment-request/payment-request-id.https.html": [
@@ -236733,7 +236822,7 @@
    "support"
   ],
   "payment-request/payment-request-show-method.https.html": [
-   "026e28265a88be54a56e2dadc0fb485303864dfc",
+   "518136ad885f95172e578f6e2c165a559c51896b",
    "testharness"
   ],
   "performance-timeline/case-sensitivity.any.js": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem-ref.html b/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem-ref.html
new file mode 100644
index 0000000..2272bdab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem-ref.html
@@ -0,0 +1,300 @@
+
+<!doctype html>
+<title>Ahem checker</title>
+<style>
+@font-face {
+  font-family: Ahem;
+  src: url("../css/fonts/ahem/ahem.ttf");
+}
+* {
+  padding: 0;
+  margin: 0;
+  border: none;
+}
+
+table {
+  font: 15px/1 Ahem;
+  border-collapse: separate;
+  border-spacing: 1px;
+  table-layout: fixed;
+}
+
+td {
+  width: 34px;
+}
+</style>
+<table>
+    <tr>
+        <td>&#x0020;x <!-- U+0020: SPACE -->
+        <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
+        <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
+        <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
+        <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
+        <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
+        <td>&#x0026;x <!-- U+0026: AMPERSAND -->
+        <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
+        <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
+        <td>&#x002A;x <!-- U+002A: ASTERISK -->
+        <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
+        <td>&#x002C;x <!-- U+002C: COMMA -->
+        <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
+        <td>&#x002E;x <!-- U+002E: FULL STOP -->
+        <td>&#x002F;x <!-- U+002F: SOLIDUS -->
+        <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
+        <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
+    <tr>
+        <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
+        <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
+        <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
+        <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
+        <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
+        <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
+        <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
+        <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
+        <td>&#x003A;x <!-- U+003A: COLON -->
+        <td>&#x003B;x <!-- U+003B: SEMICOLON -->
+        <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
+        <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
+        <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
+        <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
+        <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
+        <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
+        <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
+    <tr>
+        <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
+        <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
+        <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
+        <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
+        <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
+        <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
+        <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
+        <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
+        <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
+        <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
+        <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
+        <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
+        <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
+        <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
+        <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
+        <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
+        <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
+    <tr>
+        <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
+        <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
+        <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
+        <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
+        <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
+        <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
+        <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
+        <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
+        <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
+        <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
+        <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
+        <td>&#x005F;x <!-- U+005F: LOW LINE -->
+        <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
+        <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
+        <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
+        <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
+        <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
+    <tr>
+        <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
+        <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
+        <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
+        <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
+        <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
+        <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
+        <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
+        <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
+        <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
+        <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
+        <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
+        <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
+        <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
+        <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
+        <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
+        <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
+        <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
+    <tr>
+        <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
+        <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
+        <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
+        <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
+        <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
+        <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
+        <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
+        <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
+        <td>&#x007E;x <!-- U+007E: TILDE -->
+        <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
+        <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
+        <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
+        <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
+        <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
+        <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
+        <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
+        <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
+    <tr>
+        <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
+        <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
+        <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
+        <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+        <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
+        <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
+        <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
+        <td>&#x00AF;x <!-- U+00AF: MACRON -->
+        <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
+        <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
+        <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
+        <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
+        <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
+        <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
+        <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
+        <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
+        <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
+    <tr>
+        <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
+        <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
+        <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+        <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
+        <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
+        <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
+        <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
+        <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
+        <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
+        <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+        <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
+        <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
+        <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
+        <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
+        <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
+        <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
+        <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
+    <tr>
+        <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+        <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
+        <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
+        <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
+        <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+        <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
+        <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
+        <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
+        <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
+        <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
+        <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+        <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
+        <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
+        <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
+        <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
+        <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
+        <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
+    <tr>
+        <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+        <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
+        <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
+        <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
+        <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
+        <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
+        <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
+        <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+        <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
+        <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
+        <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
+        <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
+        <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
+        <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
+        <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
+        <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+        <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
+    <tr>
+        <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
+        <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
+        <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+        <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
+        <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
+        <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
+        <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
+        <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
+        <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+        <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
+        <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
+        <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
+        <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
+        <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
+        <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
+        <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+        <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
+    <tr>
+        <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
+        <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
+        <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
+        <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
+        <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
+        <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
+        <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+        <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
+        <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
+        <td>&#x02C7;x <!-- U+02C7: CARON -->
+        <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
+        <td>&#x02D8;x <!-- U+02D8: BREVE -->
+        <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
+        <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
+        <td>&#x02DB;x <!-- U+02DB: OGONEK -->
+        <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
+        <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
+    <tr>
+        <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
+        <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
+        <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
+        <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
+        <td>&#x2002;x <!-- U+2002: EN SPACE -->
+        <td>&#x2003;x <!-- U+2003: EM SPACE -->
+        <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
+        <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
+        <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
+        <td>&#x2009;x <!-- U+2009: THIN SPACE -->
+        <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
+        <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
+        <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
+        <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
+        <td>&#x2010;x <!-- U+2010: HYPHEN -->
+        <td>&#x2013;x <!-- U+2013: EN DASH -->
+        <td>&#x2014;x <!-- U+2014: EM DASH -->
+    <tr>
+        <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
+        <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
+        <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
+        <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
+        <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
+        <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
+        <td>&#x2020;x <!-- U+2020: DAGGER -->
+        <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
+        <td>&#x2022;x <!-- U+2022: BULLET -->
+        <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
+        <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
+        <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+        <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+        <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
+        <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
+        <td>&#x2126;x <!-- U+2126: OHM SIGN -->
+        <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
+    <tr>
+        <td>&#x2206;x <!-- U+2206: INCREMENT -->
+        <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
+        <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
+        <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
+        <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
+        <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
+        <td>&#x221E;x <!-- U+221E: INFINITY -->
+        <td>&#x222B;x <!-- U+222B: INTEGRAL -->
+        <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
+        <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
+        <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
+        <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
+        <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
+        <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
+        <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
+        <td>&#xF000;x <!-- U+F000 -->
+        <td>&#xF001;x <!-- U+F001 -->
+    <tr>
+        <td>&#xF002;x <!-- U+F002 -->
+        <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
+</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem.html b/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem.html
new file mode 100644
index 0000000..dee1b75c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem.html
@@ -0,0 +1,297 @@
+
+<!doctype html>
+<title>Ahem checker</title>
+<link rel="match" href="ahem-ref.html">
+<style>
+* {
+  padding: 0;
+  margin: 0;
+  border: none;
+}
+
+table {
+  font: 15px/1 Ahem;
+  border-collapse: separate;
+  border-spacing: 1px;
+  table-layout: fixed;
+}
+
+td {
+  width: 34px;
+}
+</style>
+<table>
+    <tr>
+        <td>&#x0020;x <!-- U+0020: SPACE -->
+        <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
+        <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
+        <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
+        <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
+        <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
+        <td>&#x0026;x <!-- U+0026: AMPERSAND -->
+        <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
+        <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
+        <td>&#x002A;x <!-- U+002A: ASTERISK -->
+        <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
+        <td>&#x002C;x <!-- U+002C: COMMA -->
+        <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
+        <td>&#x002E;x <!-- U+002E: FULL STOP -->
+        <td>&#x002F;x <!-- U+002F: SOLIDUS -->
+        <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
+        <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
+    <tr>
+        <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
+        <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
+        <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
+        <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
+        <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
+        <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
+        <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
+        <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
+        <td>&#x003A;x <!-- U+003A: COLON -->
+        <td>&#x003B;x <!-- U+003B: SEMICOLON -->
+        <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
+        <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
+        <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
+        <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
+        <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
+        <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
+        <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
+    <tr>
+        <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
+        <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
+        <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
+        <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
+        <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
+        <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
+        <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
+        <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
+        <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
+        <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
+        <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
+        <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
+        <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
+        <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
+        <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
+        <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
+        <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
+    <tr>
+        <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
+        <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
+        <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
+        <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
+        <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
+        <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
+        <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
+        <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
+        <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
+        <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
+        <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
+        <td>&#x005F;x <!-- U+005F: LOW LINE -->
+        <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
+        <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
+        <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
+        <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
+        <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
+    <tr>
+        <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
+        <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
+        <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
+        <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
+        <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
+        <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
+        <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
+        <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
+        <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
+        <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
+        <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
+        <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
+        <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
+        <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
+        <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
+        <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
+        <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
+    <tr>
+        <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
+        <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
+        <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
+        <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
+        <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
+        <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
+        <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
+        <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
+        <td>&#x007E;x <!-- U+007E: TILDE -->
+        <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
+        <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
+        <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
+        <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
+        <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
+        <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
+        <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
+        <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
+    <tr>
+        <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
+        <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
+        <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
+        <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+        <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
+        <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
+        <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
+        <td>&#x00AF;x <!-- U+00AF: MACRON -->
+        <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
+        <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
+        <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
+        <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
+        <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
+        <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
+        <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
+        <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
+        <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
+    <tr>
+        <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
+        <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
+        <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+        <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
+        <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
+        <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
+        <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
+        <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
+        <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
+        <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+        <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
+        <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
+        <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
+        <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
+        <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
+        <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
+        <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
+    <tr>
+        <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+        <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
+        <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
+        <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
+        <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+        <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
+        <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
+        <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
+        <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
+        <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
+        <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+        <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
+        <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
+        <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
+        <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
+        <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
+        <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
+    <tr>
+        <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+        <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
+        <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
+        <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
+        <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
+        <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
+        <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
+        <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+        <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
+        <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
+        <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
+        <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
+        <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
+        <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
+        <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
+        <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+        <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
+    <tr>
+        <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
+        <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
+        <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+        <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
+        <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
+        <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
+        <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
+        <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
+        <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+        <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
+        <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
+        <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
+        <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
+        <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
+        <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
+        <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+        <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
+    <tr>
+        <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
+        <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
+        <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
+        <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
+        <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
+        <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
+        <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+        <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
+        <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
+        <td>&#x02C7;x <!-- U+02C7: CARON -->
+        <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
+        <td>&#x02D8;x <!-- U+02D8: BREVE -->
+        <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
+        <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
+        <td>&#x02DB;x <!-- U+02DB: OGONEK -->
+        <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
+        <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
+    <tr>
+        <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
+        <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
+        <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
+        <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
+        <td>&#x2002;x <!-- U+2002: EN SPACE -->
+        <td>&#x2003;x <!-- U+2003: EM SPACE -->
+        <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
+        <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
+        <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
+        <td>&#x2009;x <!-- U+2009: THIN SPACE -->
+        <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
+        <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
+        <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
+        <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
+        <td>&#x2010;x <!-- U+2010: HYPHEN -->
+        <td>&#x2013;x <!-- U+2013: EN DASH -->
+        <td>&#x2014;x <!-- U+2014: EM DASH -->
+    <tr>
+        <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
+        <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
+        <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
+        <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
+        <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
+        <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
+        <td>&#x2020;x <!-- U+2020: DAGGER -->
+        <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
+        <td>&#x2022;x <!-- U+2022: BULLET -->
+        <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
+        <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
+        <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+        <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+        <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
+        <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
+        <td>&#x2126;x <!-- U+2126: OHM SIGN -->
+        <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
+    <tr>
+        <td>&#x2206;x <!-- U+2206: INCREMENT -->
+        <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
+        <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
+        <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
+        <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
+        <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
+        <td>&#x221E;x <!-- U+221E: INFINITY -->
+        <td>&#x222B;x <!-- U+222B: INTEGRAL -->
+        <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
+        <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
+        <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
+        <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
+        <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
+        <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
+        <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
+        <td>&#xF000;x <!-- U+F000 -->
+        <td>&#xF001;x <!-- U+F001 -->
+    <tr>
+        <td>&#xF002;x <!-- U+F002 -->
+        <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
+</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt
new file mode 100644
index 0000000..4fe4e85c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS Throws if the promise [[state]] is not "interactive" 
+FAIL Calling abort must not change the [[state]] until after "interactive" assert_true: Unexpected promise rejection: Request failed expected true got false
+FAIL calling .abort() causes acceptPromise to reject and closes the request. assert_true: Unexpected promise rejection: Request failed expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
new file mode 100644
index 0000000..f596800
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<!-- Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
+<meta charset="utf-8">
+<title>Test for PaymentRequest.abort() method</title>
+<link rel="help" href="https://w3c.github.io/browser-payment-api/#abort-method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+"use strict";
+setup(() => {}, {
+  // Ignore unhandled rejections resulting from .show()'s acceptPromise
+  // not being explicitly handled.
+  allow_uncaught_exception: true,
+});
+const basicCard = Object.freeze({ supportedMethods: ["basic-card"] });
+const defaultMethods = Object.freeze([basicCard]);
+const defaultDetails = Object.freeze({
+  total: {
+    label: "Total",
+    amount: {
+      currency: "USD",
+      value: "1.00",
+    },
+  },
+});
+
+promise_test(async t => {
+  // request is in "created" state
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  await promise_rejects(t, "InvalidStateError", request.abort());
+}, `Throws if the promise [[state]] is not "interactive"`);
+
+promise_test(async t => {
+  // request is in "created" state.
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  await promise_rejects(t, "InvalidStateError", request.abort());
+  // Call it again, for good measure.
+  await promise_rejects(t, "InvalidStateError", request.abort());
+  // The request's state is "created", so let's show it
+  // which changes the state to "interactive.".
+  request.show();
+  // Let's set request the state to "closed" by calling .abort()
+  try {
+    await request.abort();
+  } catch (err) {
+    assert_true(false, "Unexpected promise rejection: " + err.message);
+  }
+  // The request is now "closed", so...
+  await promise_rejects(t, "InvalidStateError", request.abort());
+}, `Calling abort must not change the [[state]] until after "interactive"`);
+
+promise_test(async t => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  const acceptPromise = request.show();
+  try {
+    await request.abort();
+  } catch (err) {
+    assert_true(false, "Unexpected promise rejection: " + err.message);
+  }
+  await promise_rejects(t, "AbortError", acceptPromise);
+  // As request is now "closed", trying to show it will fail
+  await promise_rejects(t, "InvalidStateError", request.show());
+}, "calling .abort() causes acceptPromise to reject and closes the request.");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
index 35fb974..971622e8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
@@ -41,7 +41,7 @@
 
 test(() => {
   const newDetails = Object.assign({}, defaultDetails, {
-    id: "".padStart(100000000, "\n test 123 \t \n "),
+    id: "".padStart(1024, "a"),
   });
   const request = new PaymentRequest(defaultMethods, newDetails);
   assert_equals(
@@ -305,6 +305,17 @@
   }, `If details.total.amount.value is not a valid decimal monetary value (in this case "${amount}"), then throw a TypeError`);
 }
 
+for (const prop in ["displayItems", "shippingOptions", "modifiers"]) {
+  test(() => {
+    try {
+      const details = Object.assign({}, defaultDetails, { [prop]: [] });
+      new PaymentRequest(defaultMethods, details);
+    } catch (err) {
+      assert_true(false, `${prop} can be zero length`);
+    }
+  }, `PaymentDetailsBase.${prop} can be 0 length`);
+}
+
 test(() => {
   assert_throws(
     {
@@ -375,7 +386,9 @@
       [
         {
           supportedMethods: ["basic-card"],
-          data: ["some-data"],
+          data: {
+            supportedTypes: ["debit"],
+          },
         },
       ],
       {
@@ -410,6 +423,49 @@
   assert_false(itThrows, "shouldn't throw when given a negative value");
 }, "Negative values are allowed for displayItems.amount.value, irrespective of total amount");
 
+test(() => {
+  let itThrows = false;
+  const largeMoney = "1".repeat(510);
+
+  try {
+    new PaymentRequest(
+      [
+        {
+          supportedMethods: ["basic-card"],
+        },
+      ],
+      {
+        total: {
+          label: "",
+          amount: {
+            currency: "USD",
+            value: `${largeMoney}.${largeMoney}`,
+          },
+        },
+        displayItems: [
+          {
+            label: "",
+            amount: {
+              currency: "USD",
+              value: `-${largeMoney}`,
+            },
+          },
+          {
+            label: "",
+            amount: {
+              currency: "AUD",
+              value: `-${largeMoney}.${largeMoney}`,
+            },
+          },
+        ],
+      }
+    );
+  } catch (err) {
+    itThrows = true;
+  }
+  assert_false(itThrows, "shouldn't throw when given absurd monetary values");
+}, "it handles high precision currency values without throwing");
+
 // Process shipping options:
 const defaultAmount = Object.freeze({
   currency: "USD",
@@ -451,7 +507,11 @@
   const shippingOptions = [defaultShippingOption];
   const details = Object.assign({}, defaultDetails, { shippingOptions });
   const request = new PaymentRequest(defaultMethods, details);
-  assert_equals(request.shippingOption, null, "request.shippingOption must be null");
+  assert_equals(
+    request.shippingOption,
+    null,
+    "request.shippingOption must be null"
+  );
 }, "If there is no selected shipping option, then PaymentRequest.shippingOption remains null");
 
 test(() => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index c7173f3f..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. Test bug: need to pass exception to assert_throws()
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
index d170ea0..1bdbba4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
@@ -7,34 +7,34 @@
 <script src="/resources/testharnessreport.js"></script>
 <script>
 'use strict';
+const basicCard = Object.freeze({ supportedMethods: ["basic-card"] });
+const defaultMethods = Object.freeze([basicCard]);
+const defaultDetails = Object.freeze({
+  total: {
+    label: "Total",
+    amount: {
+      currency: "USD",
+      value: "1.00",
+    },
+  },
+});
 
-promise_test(t => {
-  const request1 = new PaymentRequest([{
-    supportedMethods: ['basic-card'],
-  }], {
-    total: {
-      label: 'request1',
-      amount: {
-        currency: 'USD',
-        value: '1.00',
-      },
-    },
-  });
-  const request2 = new PaymentRequest([{
-    supportedMethods: ['basic-card'],
-  }], {
-    total: {
-      label: 'request2',
-      amount: {
-        currency: 'USD',
-        value: '1.00',
-      },
-    },
-  });
-  const result = promise_rejects(t, null, request1.show());
-  promise_rejects(t, 'AbortError', request2.show())
-    .then(t.step_func(() => request1.abort()));
-  return result;
-}, 'If the user agent\'s "payment request is showing" boolean is true, ' +
-   'then return a promise rejected with an "AbortError" DOMException.');
+promise_test(async t => {
+  const request = new PaymentRequest(defaultMethods, defaultDetails);
+  const acceptPromise = request.show(); // Sets state to "interactive"
+  await promise_rejects(t, "InvalidStateError", request.show());
+  await request.abort();
+  await promise_rejects(t, "AbortError", acceptPromise);
+}, `Throws if the promise [[state]] is not "created"`);
+
+promise_test(async t => {
+  const request1 = new PaymentRequest(defaultMethods, defaultDetails);
+  const request2 = new PaymentRequest(defaultMethods, defaultDetails);
+  const acceptPromise1 = request1.show();
+  const acceptPromise2 = request2.show();
+  await promise_rejects(t, "AbortError", acceptPromise2);
+  await request1.abort();
+  await promise_rejects(t, "AbortError", acceptPromise1);
+}, `If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException.`);
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-xhr-sync.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-xhr-sync.https-expected.txt
new file mode 100644
index 0000000..724b7d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-xhr-sync.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Verify SyncXHR is intercepted assert_equals: HTTP response status code for intercepted request expected 200 but got 404
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-xhr-sync.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-xhr-sync.https.html
new file mode 100644
index 0000000..d483d3e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-request-xhr-sync.https.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>Service Worker: Synchronous XHR is intercepted</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+'use strict';
+
+promise_test(function(t) {
+    var url = 'resources/fetch-request-xhr-sync-worker.js';
+    var scope = 'resources/fetch-request-xhr-sync-iframe.html';
+    var non_existent_file = 'non-existent-file.txt';
+
+    return service_worker_unregister_and_register(t, url, scope)
+      .then(function(registration) {
+          t.add_cleanup(function() {
+              registration.unregister();
+            });
+
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(scope); })
+      .then(function(frame) {
+          t.add_cleanup(function() {
+              frame.remove();
+            });
+
+          return new Promise(function(resolve, reject) {
+              setTimeout(function() {
+                  var xhr;
+                  try {
+                    xhr = frame.contentWindow.performSyncXHR(non_existent_file);
+                    resolve(xhr);
+                  } catch (err) {
+                    reject(err);
+                  }
+                }, 0);
+            })
+        })
+      .then(function(xhr) {
+          assert_equals(
+              xhr.status,
+              200,
+              'HTTP response status code for intercepted request'
+            );
+          assert_equals(
+              xhr.responseText,
+              'Response from service worker',
+              'HTTP response text for intercepted request'
+            );
+        });
+  }, 'Verify SyncXHR is intercepted');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-request-xhr-sync-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-request-xhr-sync-iframe.html
new file mode 100644
index 0000000..900762ff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-request-xhr-sync-iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<title>Service Worker: Synchronous XHR is intercepted iframe</title>
+<script>
+'use strict';
+
+function performSyncXHR(url) {
+  var syncXhr = new XMLHttpRequest();
+  syncXhr.open('GET', url, false);
+  syncXhr.send();
+
+  return syncXhr;
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-request-xhr-sync-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-request-xhr-sync-worker.js
new file mode 100644
index 0000000..070e572
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-request-xhr-sync-worker.js
@@ -0,0 +1,7 @@
+'use strict';
+
+self.onfetch = function(event) {
+  if (event.request.url.indexOf('non-existent-file.txt') !== -1) {
+    event.respondWith(new Response('Response from service worker'));
+  }
+};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh b/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh
index 970a930..90da2624 100755
--- a/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh
+++ b/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh
@@ -2,5 +2,6 @@
 set -ex
 
 2dcontext/tools/build.sh
+assumptions/tools/build.sh
 html/tools/build.sh
 offscreen-canvas/tools/build.sh
diff --git a/third_party/WebKit/LayoutTests/fast/events/hit-test-counts-expected.txt b/third_party/WebKit/LayoutTests/fast/events/hit-test-counts-expected.txt
index 43982142..4a003e8 100644
--- a/third_party/WebKit/LayoutTests/fast/events/hit-test-counts-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/hit-test-counts-expected.txt
@@ -21,7 +21,7 @@
 TouchEnd: 0+0
 GestureTapDown: 1+1
 GestureShowPress: 1+1
-GestureTap: 1+3 [with multiTargetTapNotification: 1+4]
+GestureTap: 1+3
 GestureScrollBegin: 0+1
 GestureTapCancel: 0+1
 GestureScrollUpdate: 0+0
@@ -32,7 +32,7 @@
 ---------------------
 Initial: 0+0 0+0 0+0
 MouseMove: 1+0 1+0 1+0
-MouseDown: 1+2 1+1 1+2 [with multiTargetTapNotification: 1+1 1+1 1+2]
+MouseDown: 1+1 1+1 1+2
 MouseUp: 0+1 0+1 0+1
 Wheel: 0+1 0+1 0+1
 TouchStart: 1+0 1+0 0+1
@@ -78,7 +78,7 @@
 TouchEnd: 0+0
 GestureTapDown: 1+1
 GestureShowPress: 1+1
-GestureTap: 1+3 [with multiTargetTapNotification: 2+4]
+GestureTap: 1+3 [with multiTargetTapNotification: 2+3]
 GestureScrollBegin: 0+1
 GestureTapCancel: 0+1
 GestureScrollUpdate: 0+0
diff --git a/third_party/WebKit/LayoutTests/fast/events/hit-test-counts.html b/third_party/WebKit/LayoutTests/fast/events/hit-test-counts.html
index 8268e853..ea2a688 100644
--- a/third_party/WebKit/LayoutTests/fast/events/hit-test-counts.html
+++ b/third_party/WebKit/LayoutTests/fast/events/hit-test-counts.html
@@ -128,6 +128,8 @@
     });
 
     logCounts('GestureTap', documents, multiTapNotification, function() {
+        // We don't want to tap on an existing selection so we clear selections.
+        window.getSelection().empty();
         eventSender.gestureTap(targetX, targetY, 1, 30, 30);
     });
 
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt b/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt
index 73b69170..ae8f5a0 100644
--- a/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt
@@ -75,15 +75,16 @@
 2. targetDiv received mouseenter buttons: 0
 3. targetDiv received mousemove buttons: 0
 4. targetDiv received mousedown buttons: 1
-5. targetDiv received mouseup buttons: 0
-6. targetDiv received click buttons: 0
-7. targetDiv received mousemove buttons: 0
-8. targetDiv received mousedown buttons: 1
-9. targetDiv received mouseup buttons: 0
-10. targetDiv received click buttons: 0
-11. targetDiv received dblclick buttons: 0
-12. targetDiv received mouseout buttons: 0
-13. targetDiv received mouseleave buttons: 0
+5. targetDiv received contextmenu buttons: 0
+6. targetDiv received mouseup buttons: 0
+7. targetDiv received click buttons: 0
+8. targetDiv received mousemove buttons: 0
+9. targetDiv received mousedown buttons: 1
+10. targetDiv received mouseup buttons: 0
+11. targetDiv received click buttons: 0
+12. targetDiv received dblclick buttons: 0
+13. targetDiv received mouseout buttons: 0
+14. targetDiv received mouseleave buttons: 0
 
 ===== tapAction with initial state=[] =====
 1. targetDiv received mouseover buttons: 0
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock-iframe.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock-iframe.html
deleted file mode 100644
index 0fa7291..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock-iframe.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: SyncXHR doesn't deadlock iframe</title>
-<script>
-function performSyncXHR() {
-  var url = 'sync-xhr-doesnt-deadlock.data?bustcache=' + Date.now();
-  var syncXhr = new XMLHttpRequest();
-  syncXhr.open("GET", url, false);
-  syncXhr.send();
-  if (syncXhr.responseText != 'hello')
-    throw 'FAIL';
-}
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock.data b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock.data
deleted file mode 100644
index b6fc4c6..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock.data
+++ /dev/null
@@ -1 +0,0 @@
-hello
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock.js
deleted file mode 100644
index 3e9093d..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/sync-xhr-doesnt-deadlock.js
+++ /dev/null
@@ -1,5 +0,0 @@
-self.onfetch = function(event) {
-  if (event.request.url.indexOf('sync-xhr-doesnt-deadlock.data') == -1)
-    return;
-  event.respondWith(fetch('404resource?bustcache=' + Date.now()));
-};
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/sync-xhr-doesnt-deadlock-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/sync-xhr-doesnt-deadlock-expected.txt
deleted file mode 100644
index 322df76..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/sync-xhr-doesnt-deadlock-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 7: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-This is a testharness.js-based test.
-PASS Verify SyncXHR does not deadlock 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/sync-xhr-doesnt-deadlock.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/sync-xhr-doesnt-deadlock.html
deleted file mode 100644
index 6fe82d7..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/sync-xhr-doesnt-deadlock.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: SyncXHR doesn't deadlock</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script>
-
-async_test(function(t) {
-    var url = 'resources/sync-xhr-doesnt-deadlock.js';
-    var scope = 'resources/sync-xhr-doesnt-deadlock-iframe.html';
-
-    service_worker_unregister_and_register(t, url, scope)
-      .then(function(registration) {
-          return wait_for_state(t, registration.installing, 'activated');
-        })
-      .then(function() { return with_iframe(scope); })
-      .then(function(frame) {
-          setTimeout(function() {
-              frame.contentWindow.performSyncXHR();
-              service_worker_unregister_and_done(t, scope);
-          }, 0);
-        })
-      .catch(unreached_rejection(t));
-  }, 'Verify SyncXHR does not deadlock');
-</script>
diff --git a/third_party/WebKit/LayoutTests/inspector/layers/layer-replay-scale.html b/third_party/WebKit/LayoutTests/inspector/layers/layer-replay-scale.html
index 18fe0da..3d21515 100644
--- a/third_party/WebKit/LayoutTests/inspector/layers/layer-replay-scale.html
+++ b/third_party/WebKit/LayoutTests/inspector/layers/layer-replay-scale.html
@@ -7,24 +7,24 @@
 {
     InspectorTest.requestLayers(onGotLayers);
 
-    function onGotLayers()
+    async function onGotLayers()
     {
         var layer = InspectorTest.findLayerByNodeIdAttribute("a");
-        layer.snapshots()[0].then(snapshotWithRect =>
-            testImageForSnapshot(snapshotWithRect.snapshot, undefined)
-                .then(() => testImageForSnapshot(snapshotWithRect.snapshot, 0.5))
-                .then(() => InspectorTest.completeTest()));
+        var snapshotWithRect = await layer.snapshots()[0];
+        await testImageForSnapshot(snapshotWithRect.snapshot, undefined);
+        await testImageForSnapshot(snapshotWithRect.snapshot, 0.5);
+        InspectorTest.completeTest();
     }
 
-    function testImageForSnapshot(snapshot, scale)
+    async function testImageForSnapshot(snapshot, scale)
     {
-        return snapshot.replay(null, null, scale).then(imageURL => new Promise(fulfill => {
-           var image = new Image();
-           image.addEventListener("load", () => fulfill(image), false);
-           image.src = imageURL;
-        })).then(image => {
-           InspectorTest.addResult(`Image dimensions at scale ${scale}: ${image.naturalWidth} x ${image.naturalHeight}`);
+        var imageURL = await snapshot.replay(scale);
+        var image = await new Promise(fulfill => {
+            var image = new Image();
+            image.addEventListener("load", () => fulfill(image), false);
+            image.src = imageURL;
         });
+        InspectorTest.addResult(`Image dimensions at scale ${scale}: ${image.naturalWidth} x ${image.naturalHeight}`);
     }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..d7e70afa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..d7e70afa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..e97e7f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Request failed
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..e97e7f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Request failed
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..e97e7f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Request failed
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..d7e70afa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..e97e7f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Request failed
+FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/sensor/absolute-orientation-sensor.html b/third_party/WebKit/LayoutTests/sensor/absolute-orientation-sensor.html
deleted file mode 100644
index 74555b8..0000000
--- a/third_party/WebKit/LayoutTests/sensor/absolute-orientation-sensor.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/mojo-helpers.js"></script>
-<script src="resources/sensor-helpers.js"></script>
-<script src="resources/generic-sensor-tests.js"></script>
-<script>
-
-'use strict';
-
-if (!window.testRunner)
-    debug('This test cannot be run without the TestRunner');
-
-const kQuaternion = [1, 0, 0, 0]; // 180 degrees around X axis.
-const kRotationMatrix = [1,  0,  0,  0,
-                         0, -1,  0,  0,
-                         0,  0, -1,  0,
-                         0,  0,  0,  1];
-const kRotationDOMMatrix = new DOMMatrix(kRotationMatrix);
-
-function update_sensor_reading(buffer) {
-  buffer[2] = 1;
-  buffer[3] = 0;
-  buffer[4] = 0;
-  buffer[5] = 0;
-}
-
-function verify_sensor_reading(sensor, should_be_null) {
-  if (should_be_null)
-    return sensor.quaternion == null && sensor.timestamp == null;
-
-  if (sensor.timestamp == null ||
-      sensor.quaternion.toString() != kQuaternion.toString())
-    return false;
-
-  return true;
-}
-
-runGenericSensorTests(AbsoluteOrientationSensor, update_sensor_reading, verify_sensor_reading);
-
-sensor_test(sensor => {
-  let sensorObject = new AbsoluteOrientationSensor();
-
-  // Throws with insufficient buffer space.
-  assert_throws({ name: 'TypeError' }, () => sensorObject.populateMatrix(new Float32Array(15)));
-
-  // Throws if no orientation data available.
-  assert_throws({ name: 'NotReadableError' }, () => sensorObject.populateMatrix(new Float32Array(16)));
-
-  if (window.SharedArrayBuffer) {
-    // Throws if passed SharedArrayBuffer view.
-    assert_throws({ name: 'TypeError' }, () => sensorObject.populateMatrix(new Float32Array(new SharedArrayBuffer(16))));
-  }
-
-  sensorObject.start();
-
-  return sensor.mockSensorProvider.getCreatedSensor()
-      .then(mockSensor => {
-        return mockSensor.setUpdateSensorReadingFunction(update_sensor_reading);
-      })
-      .then(mockSensor => {
-        return new Promise((resolve, reject) => {
-          let wrapper = new CallbackWrapper(() => {
-            // Works for all supported types.
-            let rotationMatrix32 = new Float32Array(16);
-            sensorObject.populateMatrix(rotationMatrix32);
-            assert_array_equals(rotationMatrix32, kRotationMatrix);
-
-            let rotationMatrix64 = new Float64Array(16);
-            sensorObject.populateMatrix(rotationMatrix64);
-            assert_array_equals(rotationMatrix64, kRotationMatrix);
-
-            let rotationDOMMatrix = new DOMMatrix();
-            sensorObject.populateMatrix(rotationDOMMatrix);
-            assert_array_equals(rotationDOMMatrix, kRotationDOMMatrix);
-
-            // Sets every matrix element.
-            rotationMatrix64.fill(123);
-            sensorObject.populateMatrix(rotationMatrix64);
-            assert_array_equals(rotationMatrix64, kRotationMatrix);
-
-            sensorObject.stop();
-            resolve(mockSensor);
-          }, reject);
-
-          sensorObject.onchange = wrapper.callback;
-          sensorObject.onerror = reject;
-        });
-      })
-      .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
-}, 'Test AbsoluteOrientationSensor.populateMatrix() method works correctly.');
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html b/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html
new file mode 100644
index 0000000..8355a9c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/sensor-helpers.js"></script>
+<script src="resources/generic-sensor-tests.js"></script>
+<script>
+
+'use strict';
+
+if (!window.testRunner)
+    debug('This test cannot be run without the TestRunner');
+
+const kQuaternion = [1, 0, 0, 0]; // 180 degrees around X axis.
+const kRotationMatrix = [1,  0,  0,  0,
+                         0, -1,  0,  0,
+                         0,  0, -1,  0,
+                         0,  0,  0,  1];
+const kRotationDOMMatrix = new DOMMatrix(kRotationMatrix);
+
+function update_sensor_reading(buffer) {
+  buffer[2] = 1;
+  buffer[3] = 0;
+  buffer[4] = 0;
+  buffer[5] = 0;
+}
+
+function verify_sensor_reading(sensor, should_be_null) {
+  if (should_be_null)
+    return sensor.quaternion == null && sensor.timestamp == null;
+
+  if (sensor.timestamp == null ||
+      sensor.quaternion.toString() != kQuaternion.toString())
+    return false;
+
+  return true;
+}
+
+function checkPopulateMatrix(sensor, sensorType) {
+  let sensorObject = new sensorType();
+
+  // Throws with insufficient buffer space.
+  assert_throws({ name: 'TypeError' }, () => sensorObject.populateMatrix(new Float32Array(15)));
+
+  // Throws if no orientation data available.
+  assert_throws({ name: 'NotReadableError' }, () => sensorObject.populateMatrix(new Float32Array(16)));
+
+  if (window.SharedArrayBuffer) {
+    // Throws if passed SharedArrayBuffer view.
+    assert_throws({ name: 'TypeError' }, () => sensorObject.populateMatrix(new Float32Array(new SharedArrayBuffer(16))));
+  }
+
+  sensorObject.start();
+
+  return sensor.mockSensorProvider.getCreatedSensor()
+    .then(mockSensor => {
+      return mockSensor.setUpdateSensorReadingFunction(update_sensor_reading);
+    })
+    .then(mockSensor => {
+      return new Promise((resolve, reject) => {
+        let wrapper = new CallbackWrapper(() => {
+          // Works for all supported types.
+          let rotationMatrix32 = new Float32Array(16);
+          sensorObject.populateMatrix(rotationMatrix32);
+          assert_array_equals(rotationMatrix32, kRotationMatrix);
+
+          let rotationMatrix64 = new Float64Array(16);
+          sensorObject.populateMatrix(rotationMatrix64);
+          assert_array_equals(rotationMatrix64, kRotationMatrix);
+
+          let rotationDOMMatrix = new DOMMatrix();
+          sensorObject.populateMatrix(rotationDOMMatrix);
+          assert_array_equals(rotationDOMMatrix, kRotationDOMMatrix);
+
+          // Sets every matrix element.
+          rotationMatrix64.fill(123);
+          sensorObject.populateMatrix(rotationMatrix64);
+          assert_array_equals(rotationMatrix64, kRotationMatrix);
+
+          sensorObject.stop();
+          resolve(mockSensor);
+        }, reject);
+
+        sensorObject.onchange = wrapper.callback;
+        sensorObject.onerror = reject;
+      });
+    })
+    .then(mockSensor => mockSensor.removeConfigurationCalled());
+}
+
+
+runGenericSensorTests(AbsoluteOrientationSensor, update_sensor_reading, verify_sensor_reading);
+
+sensor_test(sensor => {
+  return checkPopulateMatrix(sensor, AbsoluteOrientationSensor);
+}, 'Test AbsoluteOrientationSensor.populateMatrix() method works correctly.');
+
+runGenericSensorTests(RelativeOrientationSensor, update_sensor_reading, verify_sensor_reading);
+
+sensor_test(sensor => {
+  return checkPopulateMatrix(sensor, RelativeOrientationSensor);
+}, 'Test RelativeOrientationSensor.populateMatrix() method works correctly.');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
index 69fc7d2..12b1e80 100644
--- a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
+++ b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
@@ -5,6 +5,7 @@
 // is called so that the value read in JavaScript are the values expected (the ones
 // sent by |updateReading|).
 function runGenericSensorTests(sensorType, updateReading, verifyReading) {
+  const prefix = sensorType.name + ': ';
   sensor_test(sensor => {
     sensor.mockSensorProvider.setGetSensorShouldFail(true);
     let sensorObject = new sensorType;
@@ -19,7 +20,7 @@
 
       sensorObject.onerror = wrapper.callback;
     });
-  }, 'Test that "onerror" is send when sensor is not supported.');
+  }, prefix + 'Test that "onerror" is send when sensor is not supported.');
 
   sensor_test(sensor => {
       let sensorObject = new sensorType({frequency: 560});
@@ -42,7 +43,7 @@
           });
         });
       return testPromise;
-  }, 'Test that "onerror" is send when start() call has failed.');
+  }, prefix + 'Test that "onerror" is send when start() call has failed.');
 
   sensor_test(sensor => {
       let sensorObject = new sensorType({frequency: 560});
@@ -65,7 +66,7 @@
           })
           .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
       return testPromise;
-  }, 'Test that frequency is capped to 60.0 Hz.');
+  }, prefix + 'Test that frequency is capped to 60.0 Hz.');
 
   sensor_test(sensor => {
     let sensorObject = new sensorType();
@@ -89,7 +90,7 @@
           return mockSensor;
         })
         .then(mockSensor => mockSensor.removeConfigurationCalled());
-  }, 'Test that configuration is removed for a stopped sensor.');
+  }, prefix + 'Test that configuration is removed for a stopped sensor.');
 
   sensor_test(sensor => {
     let maxSupportedFrequency = 15;
@@ -113,7 +114,7 @@
         })
         .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
     return testPromise;
-  }, 'Test that frequency is capped to the maximum supported from frequency.');
+  }, prefix + 'Test that frequency is capped to the maximum supported from frequency.');
 
   sensor_test(sensor => {
     let minSupportedFrequency = 2;
@@ -137,7 +138,7 @@
         })
         .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
     return testPromise;
-  }, 'Test that frequency is limited to the minimum supported from frequency.');
+  }, prefix + 'Test that frequency is limited to the minimum supported from frequency.');
 
   sensor_test(sensor => {
     let sensorObject = new sensorType({frequency: 60});
@@ -159,7 +160,7 @@
       })
       .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
     return testPromise;
-  }, 'Test that sensor can be successfully created and its states are correct.');
+  }, prefix + 'Test that sensor can be successfully created and its states are correct.');
 
   sensor_test(sensor => {
     let sensorObject = new sensorType();
@@ -180,7 +181,7 @@
         })
         .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
     return testPromise;
-  }, 'Test that sensor can be constructed with default configuration.');
+  }, prefix + 'Test that sensor can be constructed with default configuration.');
 
   sensor_test(sensor => {
     let sensorObject = new sensorType({frequency: 60});
@@ -203,7 +204,7 @@
         .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
 
     return testPromise;
-  }, 'Test that addConfiguration and removeConfiguration is called.');
+  }, prefix + 'Test that addConfiguration and removeConfiguration is called.');
 
   function checkOnChangeIsCalledAndReadingIsValid(sensor) {
     let sensorObject = new sensorType({frequency: 60});
@@ -232,12 +233,12 @@
 
   sensor_test(sensor => {
     return checkOnChangeIsCalledAndReadingIsValid(sensor);
-  }, 'Test that onChange is called and sensor reading is valid (onchange reporting).');
+  }, prefix + 'Test that onChange is called and sensor reading is valid (onchange reporting).');
 
   sensor_test(sensor => {
     sensor.mockSensorProvider.setContinuousReportingMode();
     return checkOnChangeIsCalledAndReadingIsValid(sensor);
-  }, 'Test that onChange is called and sensor reading is valid (continuous reporting).');
+  }, prefix + 'Test that onChange is called and sensor reading is valid (continuous reporting).');
 
   sensor_test(sensor => {
     let sensorObject = new sensorType;
@@ -275,7 +276,7 @@
         .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
 
     return testPromise;
-  }, 'Test that sensor receives suspend / resume notifications when page'
+  }, prefix + 'Test that sensor receives suspend / resume notifications when page'
       + ' visibility changes.');
 
   sensor_test(sensor => {
@@ -315,7 +316,7 @@
         .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
 
     return testPromise;
-  }, 'Test that sensor reading is correct.');
+  }, prefix + 'Test that sensor reading is correct.');
 
   function checkFrequencyHintWorks(sensor) {
     let fastSensor = new sensorType({frequency: 30});
@@ -366,10 +367,10 @@
 
   sensor_test(sensor => {
     return checkFrequencyHintWorks(sensor);
-  }, 'Test that frequency hint works (onchange reporting).');
+  }, prefix + 'Test that frequency hint works (onchange reporting).');
 
   sensor_test(sensor => {
     sensor.mockSensorProvider.setContinuousReportingMode();
     return checkFrequencyHintWorks(sensor);
-  }, 'Test that frequency hint works (continuous reporting).');
+  }, prefix + 'Test that frequency hint works (continuous reporting).');
 }
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
index 60ded4ee..c884929 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing-expected.txt
@@ -5189,6 +5189,9 @@
     method pipeThrough
     method pipeTo
     method tee
+interface RelativeOrientationSensor : OrientationSensor
+    attribute @@toStringTag
+    method constructor
 interface RemotePlayback : EventTarget
     attribute @@toStringTag
     getter onconnect
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index d2dd3d1..f852486 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -5196,6 +5196,9 @@
     method pipeThrough
     method pipeTo
     method tee
+interface RelativeOrientationSensor : OrientationSensor
+    attribute @@toStringTag
+    method constructor
 interface RemotePlayback : EventTarget
     attribute @@toStringTag
     getter onconnect
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp
index 89534c7..75b38fe 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp
@@ -420,8 +420,8 @@
       // understanding of the data encoding.
       constexpr size_t kMaximumLengthOfBOM = 4;
       char maybe_bom[kMaximumLengthOfBOM] = {};
-      if (!resource->ResourceBuffer()->GetPartAsBytes(
-              maybe_bom, static_cast<size_t>(0), kMaximumLengthOfBOM)) {
+      if (!resource->ResourceBuffer()->GetBytes(maybe_bom,
+                                                kMaximumLengthOfBOM)) {
         NOTREACHED();
         return;
       }
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index ab71a5b0..2c1d365 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -62,6 +62,7 @@
 #include "core/html/HTMLFrameElementBase.h"
 #include "core/html/HTMLInputElement.h"
 #include "core/html/HTMLSelectElement.h"
+#include "core/input/ContextMenuAllowedScope.h"
 #include "core/input/EventHandler.h"
 #include "core/layout/HitTestRequest.h"
 #include "core/layout/HitTestResult.h"
@@ -728,6 +729,11 @@
   SelectFrameElementInParentIfFullySelected();
   // TODO(editing-dev): Should we pass in user_triggered?
   NotifyTextControlOfSelectionChange(kUserTriggered);
+  if (IsHandleVisible()) {
+    ContextMenuAllowedScope scope;
+    frame_->GetEventHandler().ShowNonLocatedContextMenu(nullptr,
+                                                        kMenuSourceTouch);
+  }
 }
 
 void FrameSelection::NotifyAccessibilityForSelectionChange() {
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index 5c0399a..85273a90 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -41,12 +41,14 @@
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/Settings.h"
+#include "core/input/EventHandler.h"
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LayoutViewItem.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/wtf/AutoReset.h"
+#include "public/web/WebMenuSourceType.h"
 
 namespace blink {
 SelectionController* SelectionController::Create(LocalFrame& frame) {
@@ -191,9 +193,14 @@
         return false;
 
       if (!this->Selection().IsHandleVisible()) {
-        UpdateSelectionForMouseDownDispatchingSelectStart(
-            inner_node, selection, kCharacterGranularity,
-            HandleVisibility::kVisible);
+        const bool did_select =
+            UpdateSelectionForMouseDownDispatchingSelectStart(
+                inner_node, selection, kCharacterGranularity,
+                HandleVisibility::kVisible);
+        if (did_select) {
+          frame_->GetEventHandler().ShowNonLocatedContextMenu(nullptr,
+                                                              kMenuSourceTouch);
+        }
         return false;
       }
     }
@@ -551,10 +558,10 @@
       kWordGranularity, HandleVisibility::kNotVisible);
 }
 
-void SelectionController::SelectClosestWordFromMouseEvent(
+bool SelectionController::SelectClosestWordFromMouseEvent(
     const MouseEventWithHitTestResults& result) {
   if (!mouse_down_may_start_select_)
-    return;
+    return false;
 
   AppendTrailingWhitespace append_trailing_whitespace =
       (result.Event().click_count == 2 &&
@@ -564,7 +571,7 @@
 
   DCHECK(!frame_->GetDocument()->NeedsLayoutTreeUpdate());
 
-  SelectClosestWordFromHitTestResult(
+  return SelectClosestWordFromHitTestResult(
       result.GetHitTestResult(), append_trailing_whitespace,
       result.Event().FromTouch() ? SelectInputEventType::kTouch
                                  : SelectInputEventType::kMouse);
@@ -585,8 +592,10 @@
 
 void SelectionController::SelectClosestWordOrLinkFromMouseEvent(
     const MouseEventWithHitTestResults& result) {
-  if (!result.GetHitTestResult().IsLiveLink())
-    return SelectClosestWordFromMouseEvent(result);
+  if (!result.GetHitTestResult().IsLiveLink()) {
+    SelectClosestWordFromMouseEvent(result);
+    return;
+  }
 
   Node* inner_node = result.InnerNode();
 
@@ -771,7 +780,11 @@
     // from setting caret selection.
     selection_state_ = SelectionState::kExtendedSelection;
   } else {
-    SelectClosestWordFromMouseEvent(event);
+    const bool did_select = SelectClosestWordFromMouseEvent(event);
+    if (did_select && Selection().IsHandleVisible()) {
+      frame_->GetEventHandler().ShowNonLocatedContextMenu(nullptr,
+                                                          kMenuSourceTouch);
+    }
   }
   return true;
 }
@@ -811,12 +824,20 @@
   const bool is_handle_visible =
       event.Event().FromTouch() && new_selection.IsRange();
 
-  return UpdateSelectionForMouseDownDispatchingSelectStart(
+  const bool did_select = UpdateSelectionForMouseDownDispatchingSelectStart(
       inner_node,
       ExpandSelectionToRespectUserSelectAll(inner_node, new_selection),
       kParagraphGranularity,
       is_handle_visible ? HandleVisibility::kVisible
                         : HandleVisibility::kNotVisible);
+  if (!did_select)
+    return false;
+
+  if (Selection().IsHandleVisible()) {
+    frame_->GetEventHandler().ShowNonLocatedContextMenu(nullptr,
+                                                        kMenuSourceTouch);
+  }
+  return true;
 }
 
 bool SelectionController::HandleMousePressEvent(
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.h b/third_party/WebKit/Source/core/editing/SelectionController.h
index ba17143..a7bf3e05 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.h
+++ b/third_party/WebKit/Source/core/editing/SelectionController.h
@@ -102,7 +102,8 @@
                                           SelectInputEventType);
   void SelectClosestMisspellingFromHitTestResult(const HitTestResult&,
                                                  AppendTrailingWhitespace);
-  void SelectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&);
+  // Returns |true| if a word was selected.
+  bool SelectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&);
   void SelectClosestMisspellingFromMouseEvent(
       const MouseEventWithHitTestResults&);
   void SelectClosestWordOrLinkFromMouseEvent(
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
index 7f81c73..8bd538ef 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -188,9 +188,6 @@
   Node* const end_container = end.ComputeContainerNode();
   const int end_offset = end.ComputeOffsetInContainerNode();
 
-  text_node_handler_.Initialize(start_container, start_offset, end_container,
-                                end_offset);
-
   // Remember the range - this does not change.
   start_container_ = start_container;
   start_offset_ = start_offset;
@@ -484,8 +481,23 @@
 
   DCHECK_NE(last_text_node_, node_)
       << "We should never call HandleTextNode on the same node twice";
-  last_text_node_ = ToText(node_);
-  text_node_handler_.HandleTextNode(ToText(node_));
+  Text* text = ToText(node_);
+  last_text_node_ = text;
+
+  // TODO(editing-dev): Introduce a |DOMOffsetRange| class so that we can pass
+  // an offset range with unbounded endpoint(s) in an easy but still clear way.
+  if (node_ != start_container_) {
+    if (node_ != end_container_)
+      text_node_handler_.HandleTextNodeWhole(text);
+    else
+      text_node_handler_.HandleTextNodeEndAt(text, end_offset_);
+    return;
+  }
+  if (node_ != end_container_) {
+    text_node_handler_.HandleTextNodeStartFrom(text, start_offset_);
+    return;
+  }
+  text_node_handler_.HandleTextNodeInRange(text, start_offset_, end_offset_);
 }
 
 template <typename Strategy>
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
index 395e6b2a..be88802 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
@@ -18,22 +18,6 @@
     TextIteratorTextState* text_state)
     : behavior_(behavior), text_state_(*text_state) {}
 
-void TextIteratorTextNodeHandler::Initialize(Node* start_container,
-                                             int start_offset,
-                                             Node* end_container,
-                                             int end_offset) {
-  // This function should be called only once.
-  DCHECK(!start_container_);
-  DCHECK_EQ(start_offset_, 0);
-  DCHECK(!end_container_);
-  DCHECK_EQ(end_offset_, 0);
-
-  start_container_ = start_container;
-  start_offset_ = start_offset;
-  end_container_ = end_container;
-  end_offset_ = end_offset;
-}
-
 bool TextIteratorTextNodeHandler::HandleRemainingTextRuns() {
   if (ShouldProceedToRemainingText())
     ProceedToRemainingText();
@@ -100,7 +84,6 @@
       const String first_letter = first_letter_text_->GetText();
       const unsigned run_start = offset_;
       const bool stops_in_first_letter =
-          text_node_ == end_container_ &&
           end_offset_ <= static_cast<int>(first_letter.length());
       const unsigned run_end =
           stops_in_first_letter ? end_offset_ : first_letter.length();
@@ -123,9 +106,7 @@
   DCHECK_GE(static_cast<unsigned>(offset_), layout_object->TextStartOffset());
   const unsigned run_start = offset_ - layout_object->TextStartOffset();
   const unsigned str_length = str.length();
-  const unsigned end = (text_node_ == end_container_)
-                           ? end_offset_ - layout_object->TextStartOffset()
-                           : str_length;
+  const unsigned end = end_offset_ - layout_object->TextStartOffset();
   const unsigned run_end = std::min(str_length, end);
 
   if (run_start >= run_end)
@@ -134,9 +115,25 @@
   EmitText(text_node_, text_node_->GetLayoutObject(), run_start, run_end);
 }
 
-void TextIteratorTextNodeHandler::HandleTextNode(Text* node) {
+void TextIteratorTextNodeHandler::HandleTextNodeInRange(Text* node,
+                                                        int start_offset,
+                                                        int end_offset) {
+  DCHECK(node);
+  DCHECK_GE(start_offset, 0);
+
+  // TODO(editing-dev): Add the following DCHECK once we stop assuming equal
+  // number of code units in DOM string and LayoutText::GetText(). Currently
+  // violated by
+  // - external/wpt/innerText/getter.html
+  // - fast/css/case-transform.html
+  // DCHECK_LE(end_offset, static_cast<int>(node->data().length()));
+
+  // TODO(editing-dev): Stop passing in |start_offset == end_offset|.
+  DCHECK_LE(start_offset, end_offset);
+
   text_node_ = node;
-  offset_ = text_node_ == start_container_ ? start_offset_ : 0;
+  offset_ = start_offset;
+  end_offset_ = end_offset;
   handled_first_letter_ = false;
   first_letter_text_ = nullptr;
 
@@ -186,6 +183,22 @@
   HandleTextBox();
 }
 
+void TextIteratorTextNodeHandler::HandleTextNodeStartFrom(Text* node,
+                                                          int start_offset) {
+  HandleTextNodeInRange(node, start_offset,
+                        node->GetLayoutObject()->TextStartOffset() +
+                            node->GetLayoutObject()->GetText().length());
+}
+
+void TextIteratorTextNodeHandler::HandleTextNodeEndAt(Text* node,
+                                                      int end_offset) {
+  HandleTextNodeInRange(node, 0, end_offset);
+}
+
+void TextIteratorTextNodeHandler::HandleTextNodeWhole(Text* node) {
+  HandleTextNodeStartFrom(node, 0);
+}
+
 // Restore the collapsed space for copy & paste. See http://crbug.com/318925
 size_t TextIteratorTextNodeHandler::RestoreCollapsedTrailingSpace(
     InlineTextBox* next_text_box,
@@ -228,10 +241,7 @@
     // Start and end offsets in |str|, i.e., str[start..end - 1] should be
     // emitted (after handling whitespace collapsing).
     const unsigned start = offset_ - layout_object->TextStartOffset();
-    const unsigned end =
-        (text_node_ == end_container_)
-            ? static_cast<unsigned>(end_offset_) - text_start_offset
-            : INT_MAX;
+    const unsigned end = static_cast<unsigned>(end_offset_) - text_start_offset;
     while (text_box_) {
       const unsigned text_box_start = text_box_->Start();
       const unsigned run_start = std::max(text_box_start, start);
@@ -357,8 +367,6 @@
 bool TextIteratorTextNodeHandler::ShouldProceedToRemainingText() const {
   if (text_box_ || !remaining_text_box_)
     return false;
-  if (text_node_ != end_container_)
-    return true;
   return offset_ < end_offset_;
 }
 
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
index adcd9ec..9d89fe31 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.h
@@ -26,15 +26,6 @@
   TextIteratorTextNodeHandler(const TextIteratorBehavior&,
                               TextIteratorTextState*);
 
-  // Initializes the full iteration range of the TextIterator. This function
-  // should be called only once from TextIterator::Initialize.
-  // TODO(xiaochengh): TextNodeHandler doesn't need to know the full iteration
-  // range; The offset range in the current node suffices. Remove this function.
-  void Initialize(Node* start_container,
-                  int start_offset,
-                  Node* end_container,
-                  int end_offset);
-
   Text* GetNode() const { return text_node_; }
 
   // Returns true if more text is emitted without traversing to the next node.
@@ -45,7 +36,13 @@
 
   void ResetCollapsedWhiteSpaceFixup();
 
-  void HandleTextNode(Text*);
+  // Emit plain text from the given text node.
+  void HandleTextNodeWhole(Text*);
+
+  // Variants that emit plain text within the given DOM offset range.
+  void HandleTextNodeStartFrom(Text*, int start_offset);
+  void HandleTextNodeEndAt(Text*, int end_offset);
+  void HandleTextNodeInRange(Text*, int start_offset, int end_offset);
 
  private:
   void HandlePreFormattedTextNode();
@@ -72,15 +69,10 @@
                 int text_start_offset,
                 int text_end_offset);
 
-  // The range.
-  Member<Node> start_container_;
-  int start_offset_ = 0;
-  Member<Node> end_container_;
-  int end_offset_ = 0;
-
-  // The current text node and offset, from which text is being emitted.
+  // The current text node and offset range, from which text should be emitted.
   Member<Text> text_node_;
   int offset_ = 0;
+  int end_offset_ = 0;
 
   InlineTextBox* text_box_ = nullptr;
 
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp
index ba13847..8a6f1b3 100644
--- a/third_party/WebKit/Source/core/html/ImageData.cpp
+++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -365,6 +365,48 @@
   return new ImageData(size, buffer_view, color_settings);
 }
 
+// Crops ImageData to the intersect of its size and the given rectangle. If the
+// intersection is empty or it cannot create the cropped ImageData it returns
+// nullptr. This function leaves the source ImageData intact. When crop_rect
+// covers all the ImageData, a copy of the ImageData is returned.
+ImageData* ImageData::CropRect(const IntRect& crop_rect, bool flip_y) {
+  IntRect src_rect(IntPoint(), size_);
+  const IntRect dst_rect = Intersection(src_rect, crop_rect);
+  if (dst_rect.IsEmpty())
+    return nullptr;
+
+  unsigned data_size = 4 * dst_rect.Width() * dst_rect.Height();
+  DOMArrayBufferView* buffer_view = AllocateAndValidateDataArray(
+      data_size,
+      ImageData::GetImageDataStorageFormat(color_settings_.storageFormat()));
+  if (!buffer_view)
+    return nullptr;
+
+  if (src_rect == dst_rect && !flip_y) {
+    std::memcpy(buffer_view->BufferBase()->Data(), BufferBase()->Data(),
+                data_size * buffer_view->TypeSize());
+  } else {
+    unsigned data_type_size =
+        ImageData::StorageFormatDataSize(color_settings_.storageFormat());
+    int src_index = (dst_rect.X() * src_rect.Width() + dst_rect.Y()) * 4;
+    int dst_index = 0;
+    if (flip_y)
+      dst_index = (dst_rect.Height() - 1) * dst_rect.Width() * 4;
+    int src_row_stride = src_rect.Width() * 4;
+    int dst_row_stride = flip_y ? -dst_rect.Width() * 4 : dst_rect.Width() * 4;
+    for (int i = 0; i < dst_rect.Height(); i++) {
+      std::memcpy(
+          static_cast<char*>(buffer_view->BufferBase()->Data()) +
+              dst_index * data_type_size,
+          static_cast<char*>(BufferBase()->Data()) + src_index * data_type_size,
+          dst_rect.Width() * 4 * data_type_size);
+      src_index += src_row_stride;
+      dst_index += dst_row_stride;
+    }
+  }
+  return new ImageData(dst_rect.Size(), buffer_view, &color_settings_);
+}
+
 ScriptPromise ImageData::CreateImageBitmap(ScriptState* script_state,
                                            EventTarget& event_target,
                                            Optional<IntRect> crop_rect,
@@ -600,38 +642,6 @@
   return SkColorSpace::MakeSRGB();
 }
 
-// This function returns the proper SkColorSpace to color correct the pixels
-// stored in ImageData before copying to the canvas. For now, it assumes that
-// both ImageData and canvas use a linear gamma curve.
-sk_sp<SkColorSpace> ImageData::GetSkColorSpace(
-    const CanvasColorSpace& color_space,
-    const CanvasPixelFormat& pixel_format) {
-  switch (color_space) {
-    case kLegacyCanvasColorSpace:
-      return (gfx::ColorSpace::CreateSRGB()).ToSkColorSpace();
-    case kSRGBCanvasColorSpace:
-      if (pixel_format == kF16CanvasPixelFormat)
-        return (gfx::ColorSpace::CreateSCRGBLinear()).ToSkColorSpace();
-      return (gfx::ColorSpace::CreateSRGB()).ToSkColorSpace();
-    case kRec2020CanvasColorSpace:
-      return (gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
-                              gfx::ColorSpace::TransferID::LINEAR))
-          .ToSkColorSpace();
-    case kP3CanvasColorSpace:
-      return (gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTEST432_1,
-                              gfx::ColorSpace::TransferID::LINEAR))
-          .ToSkColorSpace();
-  }
-  NOTREACHED();
-  return nullptr;
-}
-
-sk_sp<SkColorSpace> ImageData::GetSkColorSpaceForTest(
-    const CanvasColorSpace& color_space,
-    const CanvasPixelFormat& pixel_format) {
-  return GetSkColorSpace(color_space, pixel_format);
-}
-
 bool ImageData::ImageDataInCanvasColorSettings(
     const CanvasColorSpace& canvas_color_space,
     const CanvasPixelFormat& canvas_pixel_format,
@@ -690,16 +700,18 @@
 
   sk_sp<SkColorSpace> src_color_space = nullptr;
   if (data_) {
-    src_color_space = ImageData::GetSkColorSpace(image_data_color_space,
-                                                 kRGBA8CanvasPixelFormat);
+    src_color_space =
+        CanvasColorParams(image_data_color_space, kRGBA8CanvasPixelFormat)
+            .GetSkColorSpaceForSkSurfaces();
   } else {
-    src_color_space = ImageData::GetSkColorSpace(image_data_color_space,
-                                                 kF16CanvasPixelFormat);
+    src_color_space =
+        CanvasColorParams(image_data_color_space, kF16CanvasPixelFormat)
+            .GetSkColorSpaceForSkSurfaces();
   }
 
   sk_sp<SkColorSpace> dst_color_space =
-      ImageData::GetSkColorSpace(canvas_color_space, canvas_pixel_format);
-
+      CanvasColorParams(canvas_color_space, canvas_pixel_format)
+          .GetSkColorSpaceForSkSurfaces();
   SkColorSpaceXform::ColorFormat dst_color_format =
       SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
   if (canvas_pixel_format == kF16CanvasPixelFormat)
diff --git a/third_party/WebKit/Source/core/html/ImageData.h b/third_party/WebKit/Source/core/html/ImageData.h
index 420dda7..8d03a8c 100644
--- a/third_party/WebKit/Source/core/html/ImageData.h
+++ b/third_party/WebKit/Source/core/html/ImageData.h
@@ -39,6 +39,7 @@
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/geometry/IntSize.h"
+#include "platform/graphics/CanvasColorParams.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/CheckedNumeric.h"
 #include "platform/wtf/Compiler.h"
@@ -108,8 +109,8 @@
   static ImageData* CreateForTest(const IntSize&,
                                   DOMArrayBufferView*,
                                   const ImageDataColorSettings* = nullptr);
-  static sk_sp<SkColorSpace> GetSkColorSpaceForTest(const CanvasColorSpace&,
-                                                    const CanvasPixelFormat&);
+
+  ImageData* CropRect(const IntRect&, bool = false);
 
   static CanvasColorSpace GetCanvasColorSpace(const String&);
   static String CanvasColorSpaceName(const CanvasColorSpace&);
@@ -193,9 +194,6 @@
 
   static DOMFloat32Array* ConvertFloat16ArrayToFloat32Array(const uint16_t*,
                                                             unsigned);
-
-  static sk_sp<SkColorSpace> GetSkColorSpace(const CanvasColorSpace&,
-                                             const CanvasPixelFormat&);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/ImageDataTest.cpp b/third_party/WebKit/Source/core/html/ImageDataTest.cpp
index 1cc60e05..3d8de2b 100644
--- a/third_party/WebKit/Source/core/html/ImageDataTest.cpp
+++ b/third_party/WebKit/Source/core/html/ImageDataTest.cpp
@@ -38,24 +38,15 @@
 
 TEST_F(ImageDataTest, NegativeAndZeroIntSizeTest) {
   ImageData* image_data;
-
-  image_data = ImageData::Create(IntSize(0, 10));
-  EXPECT_EQ(image_data, nullptr);
-
-  image_data = ImageData::Create(IntSize(10, 0));
-  EXPECT_EQ(image_data, nullptr);
-
-  image_data = ImageData::Create(IntSize(0, 0));
-  EXPECT_EQ(image_data, nullptr);
-
-  image_data = ImageData::Create(IntSize(-1, 10));
-  EXPECT_EQ(image_data, nullptr);
-
-  image_data = ImageData::Create(IntSize(10, -1));
-  EXPECT_EQ(image_data, nullptr);
-
-  image_data = ImageData::Create(IntSize(-1, -1));
-  EXPECT_EQ(image_data, nullptr);
+  // Test scenarios
+  const int num_test_cases = 6;
+  const IntSize image_data_sizes[6] = {IntSize(0, 10),  IntSize(10, 0),
+                                       IntSize(0, 0),   IntSize(-1, 10),
+                                       IntSize(10, -1), IntSize(-1, -1)};
+  for (int i = 1; i < num_test_cases; i++) {
+    image_data = ImageData::Create(image_data_sizes[i]);
+    EXPECT_EQ(image_data, nullptr);
+  }
 }
 
 // Under asan_clang_phone, the test crashes after the memory allocation
@@ -250,15 +241,18 @@
 
   sk_sp<SkColorSpace> src_sk_color_space = nullptr;
   if (u8_array) {
-    src_sk_color_space = ImageData::GetSkColorSpaceForTest(
-        src_color_space, kRGBA8CanvasPixelFormat);
+    src_sk_color_space =
+        CanvasColorParams(src_color_space, kRGBA8CanvasPixelFormat)
+            .GetSkColorSpaceForSkSurfaces();
   } else {
-    src_sk_color_space = ImageData::GetSkColorSpaceForTest(
-        src_color_space, kF16CanvasPixelFormat);
+    src_sk_color_space =
+        CanvasColorParams(src_color_space, kF16CanvasPixelFormat)
+            .GetSkColorSpaceForSkSurfaces();
   }
 
   sk_sp<SkColorSpace> dst_sk_color_space =
-      ImageData::GetSkColorSpaceForTest(dst_color_space, dst_pixel_format);
+      CanvasColorParams(dst_color_space, dst_pixel_format)
+          .GetSkColorSpaceForSkSurfaces();
 
   // When the input dataArray is in Uint16, we normally should convert the
   // values from Little Endian to Big Endian before passing the buffer to
@@ -400,5 +394,144 @@
   delete[] f32_pixels;
 }
 
+// This test examines ImageData::CropRect()
+TEST_F(ImageDataTest, TestCropRect) {
+  const int num_image_data_storage_formats = 3;
+  ImageDataStorageFormat image_data_storage_formats[] = {
+      kUint8ClampedArrayStorageFormat, kUint16ArrayStorageFormat,
+      kFloat32ArrayStorageFormat,
+  };
+  String image_data_storage_format_names[] = {
+      kUint8ClampedArrayStorageFormatName, kUint16ArrayStorageFormatName,
+      kFloat32ArrayStorageFormatName,
+  };
+
+  // Source pixels
+  unsigned width = 20;
+  unsigned height = 20;
+  unsigned data_length = width * height * 4;
+  uint8_t* u8_pixels = new uint8_t[data_length];
+  uint16_t* u16_pixels = new uint16_t[data_length];
+  float* f32_pixels = new float[data_length];
+
+  // Test scenarios
+  const int num_test_cases = 12;
+  const IntRect crop_rects[12] = {
+      IntRect(3, 4, 5, 6),     IntRect(3, 4, 5, 6),    IntRect(10, 10, 20, 20),
+      IntRect(10, 10, 20, 20), IntRect(0, 0, 20, 20),  IntRect(0, 0, 20, 20),
+      IntRect(0, 0, 10, 10),   IntRect(0, 0, 10, 10),  IntRect(0, 0, 10, 0),
+      IntRect(0, 0, 0, 10),    IntRect(10, 0, 10, 10), IntRect(0, 10, 10, 10),
+  };
+  const bool crop_flips[12] = {true, false, true,  false, true,  false,
+                               true, false, false, false, false, false};
+
+  // Fill the pixels with numbers related to their positions
+  unsigned set_value = 0;
+  unsigned expected_value = 0;
+  float fexpected_value = 0;
+  unsigned index = 0, row_index = 0;
+  for (unsigned i = 0; i < height; i++)
+    for (unsigned j = 0; j < width; j++)
+      for (unsigned k = 0; k < 4; k++) {
+        index = i * width * 4 + j * 4 + k;
+        set_value = (i + 1) * (j + 1) * (k + 1);
+        u8_pixels[index] = set_value % 255;
+        u16_pixels[index] = (set_value * 257) % 65535;
+        f32_pixels[index] = (set_value % 255) / 255.0f;
+      }
+
+  // Create ImageData objects
+  DOMArrayBufferView* data_array = nullptr;
+
+  DOMUint8ClampedArray* data_u8 =
+      DOMUint8ClampedArray::Create(u8_pixels, data_length);
+  DCHECK(data_u8);
+  EXPECT_EQ(data_length, data_u8->length());
+  DOMUint16Array* data_u16 = DOMUint16Array::Create(u16_pixels, data_length);
+  DCHECK(data_u16);
+  EXPECT_EQ(data_length, data_u16->length());
+  DOMFloat32Array* data_f32 = DOMFloat32Array::Create(f32_pixels, data_length);
+  DCHECK(data_f32);
+  EXPECT_EQ(data_length, data_f32->length());
+
+  ImageData* image_data = nullptr;
+  ImageData* cropped_image_data = nullptr;
+
+  bool test_passed = true;
+  for (int i = 0; i < num_image_data_storage_formats; i++) {
+    if (image_data_storage_formats[i] == kUint8ClampedArrayStorageFormat)
+      data_array = static_cast<DOMArrayBufferView*>(data_u8);
+    else if (image_data_storage_formats[i] == kUint16ArrayStorageFormat)
+      data_array = static_cast<DOMArrayBufferView*>(data_u16);
+    else
+      data_array = static_cast<DOMArrayBufferView*>(data_f32);
+
+    ImageDataColorSettings color_settings;
+    color_settings.setStorageFormat(image_data_storage_format_names[i]);
+    image_data = ImageData::CreateForTest(IntSize(width, height), data_array,
+                                          &color_settings);
+    for (int j = 0; j < num_test_cases; j++) {
+      // Test the size of the cropped image data
+      IntRect src_rect(IntPoint(), image_data->Size());
+      IntRect crop_rect = Intersection(src_rect, crop_rects[j]);
+
+      cropped_image_data = image_data->CropRect(crop_rects[j], crop_flips[j]);
+      if (crop_rect.IsEmpty()) {
+        EXPECT_FALSE(cropped_image_data);
+        continue;
+      }
+      EXPECT_TRUE(cropped_image_data->Size() == crop_rect.Size());
+
+      // Test the content
+      for (int k = 0; k < crop_rect.Height(); k++)
+        for (int m = 0; m < crop_rect.Width(); m++)
+          for (int n = 0; n < 4; n++) {
+            row_index = crop_flips[j] ? (crop_rect.Height() - k - 1) : k;
+            index =
+                row_index * cropped_image_data->Size().Width() * 4 + m * 4 + n;
+            expected_value =
+                (k + crop_rect.X() + 1) * (m + crop_rect.Y() + 1) * (n + 1);
+            if (image_data_storage_formats[i] ==
+                kUint8ClampedArrayStorageFormat)
+              expected_value %= 255;
+            else if (image_data_storage_formats[i] == kUint16ArrayStorageFormat)
+              expected_value = (expected_value * 257) % 65535;
+            else
+              fexpected_value = (expected_value % 255) / 255.0f;
+
+            if (image_data_storage_formats[i] ==
+                kUint8ClampedArrayStorageFormat) {
+              if (cropped_image_data->data()->Data()[index] != expected_value) {
+                test_passed = false;
+                break;
+              }
+            } else if (image_data_storage_formats[i] ==
+                       kUint16ArrayStorageFormat) {
+              if (cropped_image_data->dataUnion()
+                      .getAsUint16Array()
+                      .View()
+                      ->Data()[index] != expected_value) {
+                test_passed = false;
+                break;
+              }
+            } else {
+              if (cropped_image_data->dataUnion()
+                      .getAsFloat32Array()
+                      .View()
+                      ->Data()[index] != fexpected_value) {
+                test_passed = false;
+                break;
+              }
+            }
+          }
+      EXPECT_TRUE(test_passed);
+    }
+  }
+
+  delete[] u8_pixels;
+  delete[] u16_pixels;
+  delete[] f32_pixels;
+}
+
 }  // namspace
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 0032b57..2160728 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1892,20 +1892,29 @@
   doc->UpdateHoverActiveState(request, result.InnerElement());
 
   // The contextmenu event is a mouse event even when invoked using the
-  // keyboard or other methods.  This is required for web compatibility.
+  // keyboard.  This is required for web compatibility.
   WebInputEvent::Type event_type = WebInputEvent::kMouseDown;
   if (frame_->GetSettings() &&
       frame_->GetSettings()->GetShowContextMenuOnMouseUp())
     event_type = WebInputEvent::kMouseUp;
 
+  WebInputEvent::Modifiers modifiers;
+  switch (source_type) {
+    case kMenuSourceTouch:
+    case kMenuSourceLongPress:
+    case kMenuSourceTouchHandle:
+      modifiers = WebInputEvent::kIsCompatibilityEventForTouch;
+      break;
+    default:
+      modifiers = WebInputEvent::kNoModifiers;
+      break;
+  }
+
   WebMouseEvent mouse_event(
       event_type,
       WebFloatPoint(location_in_root_frame.X(), location_in_root_frame.Y()),
       WebFloatPoint(global_position.X(), global_position.Y()),
-      WebPointerProperties::Button::kNoButton, /* clickCount */ 0,
-      ((source_type == kMenuSourceTouchHandle)
-           ? WebInputEvent::kIsCompatibilityEventForTouch
-           : WebInputEvent::kNoModifiers),
+      WebPointerProperties::Button::kNoButton, /* clickCount */ 0, modifiers,
       TimeTicks::Now().InSeconds());
 
   // TODO(dtapuska): Transition the mouseEvent to be created really in viewport
diff --git a/third_party/WebKit/Source/core/input/GestureManager.cpp b/third_party/WebKit/Source/core/input/GestureManager.cpp
index 5a4675b..a1324f0 100644
--- a/third_party/WebKit/Source/core/input/GestureManager.cpp
+++ b/third_party/WebKit/Source/core/input/GestureManager.cpp
@@ -333,7 +333,6 @@
   if (inner_node && inner_node->GetLayoutObject() &&
       selection_controller_->HandleGestureLongPress(hit_test_result)) {
     mouse_event_manager_->FocusDocumentView();
-    return WebInputEventResult::kHandledSystem;
   }
 
   return SendContextMenuEventForGesture(targeted_event);
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 1a426a9..89db06a 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -55,11 +55,11 @@
   // Only resolve our BFC offset if we know that we are non-empty as we may
   // need to pass through our margin strut.
   if (!inline_node->Items().IsEmpty()) {
-    NGLogicalOffset bfc_offset = ConstraintSpace().BfcOffset();
-    bfc_offset.block_offset += ConstraintSpace().MarginStrut().Sum();
-    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_offset,
+    LayoutUnit bfc_block_offset = ConstraintSpace().BfcOffset().block_offset;
+    bfc_block_offset += ConstraintSpace().MarginStrut().Sum();
+    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset,
                                  &container_builder_);
-    PositionPendingFloats(bfc_offset.block_offset, &container_builder_,
+    PositionPendingFloats(bfc_block_offset, &container_builder_,
                           MutableConstraintSpace());
   }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 261d588..03f6691 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -67,14 +67,31 @@
 
 }  // namespace
 
+// This struct is used for communicating to a child the position of the
+// previous inflow child.
+struct NGPreviousInflowPosition {
+  LayoutUnit bfc_block_offset;
+  LayoutUnit logical_block_offset;
+  NGMarginStrut margin_strut;
+};
+
+// This strut holds information for the current inflow child. The data is not
+// useful outside of handling this single inflow child.
+struct NGInflowChildData {
+  NGLogicalOffset bfc_offset_estimate;
+  NGMarginStrut margin_strut;
+  NGBoxStrut margins;
+};
+
 void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace& space,
-                                  const NGLogicalOffset& offset,
+                                  LayoutUnit bfc_block_offset,
                                   NGFragmentBuilder* builder) {
   DCHECK(builder);
   if (!builder->BfcOffset()) {
-    NGLogicalOffset mutable_offset(offset);
-    AdjustToClearance(space.ClearanceOffset(), &mutable_offset);
-    builder->SetBfcOffset(mutable_offset);
+    NGLogicalOffset bfc_offset = {space.BfcOffset().inline_offset,
+                                  bfc_block_offset};
+    AdjustToClearance(space.ClearanceOffset(), &bfc_offset);
+    builder->SetBfcOffset(bfc_offset);
   }
 }
 
@@ -150,11 +167,13 @@
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
+    const NGBoxStrut& child_margins,
     const WTF::Optional<NGLogicalOffset>& known_fragment_offset) {
   if (known_fragment_offset)
     return known_fragment_offset.value() - ContainerBfcOffset();
   LayoutUnit inline_offset =
-      border_and_padding_.inline_start + curr_child_margins_.inline_start;
+      border_and_padding_.inline_start + child_margins.inline_start;
+  // TODO(ikilpatrick): Using the content_size_ here looks suspicious - check.
   return {inline_offset, content_size_};
 }
 
@@ -199,17 +218,20 @@
   // within a previous fragment.
   content_size_ = BreakToken() ? LayoutUnit() : border_and_padding_.block_start;
 
-  curr_margin_strut_ = ConstraintSpace().MarginStrut();
-  curr_bfc_offset_ = ConstraintSpace().BfcOffset();
+  NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut();
+  LayoutUnit input_bfc_block_offset =
+      ConstraintSpace().BfcOffset().block_offset;
 
   // Margins collapsing:
   //   Do not collapse margins between parent and its child if there is
   //   border/padding between them.
   if (border_and_padding_.block_start) {
-    curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
-    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
+    input_bfc_block_offset += input_margin_strut.Sum();
+    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset,
                                  &container_builder_);
-    curr_margin_strut_ = NGMarginStrut();
+    // We reset the block offset here as it may have been effected by clearance.
+    input_bfc_block_offset = ContainerBfcOffset().block_offset;
+    input_margin_strut = NGMarginStrut();
   }
 
   // If a new formatting context hits the margin collapsing if-branch above
@@ -218,29 +240,34 @@
   // If we are resuming layout from a break token the same rule applies. Margin
   // struts cannot pass through break tokens.
   if (ConstraintSpace().IsNewFormattingContext() || BreakToken()) {
-    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
+    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), input_bfc_block_offset,
                                  &container_builder_);
-    DCHECK_EQ(curr_margin_strut_, NGMarginStrut());
+    DCHECK_EQ(input_margin_strut, NGMarginStrut());
     DCHECK_EQ(container_builder_.BfcOffset().value(), NGLogicalOffset());
-    curr_bfc_offset_ = {};
   }
 
-  curr_bfc_offset_.block_offset += content_size_;
+  input_bfc_block_offset += content_size_;
+
+  NGPreviousInflowPosition previous_inflow_position = {
+      input_bfc_block_offset, content_size_, input_margin_strut};
 
   while (child) {
     if (child->IsOutOfFlowPositioned()) {
       DCHECK(!child_break_token);
-      HandleOutOfFlowPositioned(ToNGBlockNode(child));
+      HandleOutOfFlowPositioned(previous_inflow_position, ToNGBlockNode(child));
     } else if (child->IsFloating()) {
-      HandleFloating(ToNGBlockNode(child),
+      HandleFloating(previous_inflow_position, ToNGBlockNode(child),
                      ToNGBlockBreakToken(child_break_token));
     } else {
-      NGLogicalOffset child_bfc_offset = PrepareChildLayout(child);
+      NGInflowChildData child_data =
+          PrepareChildLayout(previous_inflow_position, child);
       RefPtr<NGConstraintSpace> child_space =
-          CreateConstraintSpaceForChild(child_bfc_offset, *child);
+          CreateConstraintSpaceForChild(*child, child_data);
       RefPtr<NGLayoutResult> layout_result =
           child->Layout(child_space.Get(), child_break_token);
-      FinishChildLayout(*child_space, child, layout_result.Get());
+      previous_inflow_position =
+          FinishChildLayout(*child_space, previous_inflow_position, child_data,
+                            child, layout_result.Get());
     }
 
     entry = child_iterator.NextChild();
@@ -251,6 +278,9 @@
       break;
   }
 
+  NGMarginStrut end_margin_strut = previous_inflow_position.margin_strut;
+  LayoutUnit end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
+
   // Margins collapsing:
   //   Bottom margins of an in-flow block box doesn't collapse with its last
   //   in-flow block-level child's bottom margin if the box has bottom
@@ -258,8 +288,8 @@
   content_size_ += border_and_padding_.block_end;
   if (border_and_padding_.block_end ||
       ConstraintSpace().IsNewFormattingContext()) {
-    content_size_ += curr_margin_strut_.Sum();
-    curr_margin_strut_ = NGMarginStrut();
+    content_size_ += end_margin_strut.Sum();
+    end_margin_strut = NGMarginStrut();
   }
 
   // Recompute the block-axis size now that we know our content size.
@@ -273,10 +303,10 @@
   // Non-empty blocks always know their position in space.
   // TODO(ikilpatrick): This check for a break token seems error prone.
   if (size.block_size || BreakToken()) {
-    curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
-    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
+    end_bfc_block_offset += end_margin_strut.Sum();
+    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), end_bfc_block_offset,
                                  &container_builder_);
-    PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
+    PositionPendingFloats(end_bfc_block_offset, &container_builder_,
                           MutableConstraintSpace());
   }
 
@@ -285,9 +315,9 @@
   //   of its parent if the parent has height != auto()
   if (!Style().LogicalHeight().IsAuto()) {
     // TODO(glebl): handle minLogicalHeight, maxLogicalHeight.
-    curr_margin_strut_ = NGMarginStrut();
+    end_margin_strut = NGMarginStrut();
   }
-  container_builder_.SetEndMarginStrut(curr_margin_strut_);
+  container_builder_.SetEndMarginStrut(end_margin_strut);
 
   container_builder_.SetOverflowSize(
       NGLogicalSize(max_inline_size_, content_size_));
@@ -302,33 +332,32 @@
   return container_builder_.ToBoxFragment();
 }
 
-void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode* child) {
-  NGLogicalOffset offset = {border_and_padding_.inline_start, content_size_};
+void NGBlockLayoutAlgorithm::HandleOutOfFlowPositioned(
+    const NGPreviousInflowPosition& previous_inflow_position,
+    NGBlockNode* child) {
+  NGLogicalOffset offset = {border_and_padding_.inline_start,
+                            previous_inflow_position.logical_block_offset};
 
   // We only include the margin strut in the OOF static-position if we know we
   // aren't going to be a zero-block-size fragment.
   if (container_builder_.BfcOffset())
-    offset.block_offset += curr_margin_strut_.Sum();
+    offset.block_offset += previous_inflow_position.margin_strut.Sum();
 
   container_builder_.AddOutOfFlowChildCandidate(child, offset);
 }
 
-void NGBlockLayoutAlgorithm::HandleFloating(NGBlockNode* child,
-                                            NGBlockBreakToken* token) {
-  // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child.
-  curr_bfc_offset_ = container_builder_.BfcOffset()
-                         ? container_builder_.BfcOffset().value()
-                         : ConstraintSpace().BfcOffset();
-  curr_bfc_offset_.block_offset += content_size_;
-
+void NGBlockLayoutAlgorithm::HandleFloating(
+    const NGPreviousInflowPosition& previous_inflow_position,
+    NGBlockNode* child,
+    NGBlockBreakToken* token) {
   // Calculate margins in the BFC's writing mode.
-  curr_child_margins_ = CalculateMargins(child);
+  NGBoxStrut margins = CalculateMargins(child);
 
   NGLogicalOffset origin_offset = constraint_space_->BfcOffset();
   origin_offset.inline_offset += border_and_padding_.inline_start;
   RefPtr<NGUnpositionedFloat> unpositioned_float = NGUnpositionedFloat::Create(
       child_available_size_, child_percentage_size_, origin_offset,
-      constraint_space_->BfcOffset(), curr_child_margins_, child, token);
+      constraint_space_->BfcOffset(), margins, child, token);
   container_builder_.AddUnpositionedFloat(unpositioned_float);
 
   // If there is a break token for a float we must be resuming layout, we must
@@ -337,29 +366,28 @@
 
   // No need to postpone the positioning if we know the correct offset.
   if (container_builder_.BfcOffset()) {
-    NGLogicalOffset origin_point = curr_bfc_offset_;
     // Adjust origin point to the margins of the last child.
     // Example: <div style="margin-bottom: 20px"><float></div>
     //          <div style="margin-bottom: 30px"></div>
-    origin_point.block_offset += curr_margin_strut_.Sum();
-    PositionPendingFloats(origin_point.block_offset, &container_builder_,
+    LayoutUnit origin_block_offset =
+        previous_inflow_position.bfc_block_offset +
+        previous_inflow_position.margin_strut.Sum();
+    PositionPendingFloats(origin_block_offset, &container_builder_,
                           MutableConstraintSpace());
   }
 }
 
-NGLogicalOffset NGBlockLayoutAlgorithm::PrepareChildLayout(
+NGInflowChildData NGBlockLayoutAlgorithm::PrepareChildLayout(
+    const NGPreviousInflowPosition& previous_inflow_position,
     NGLayoutInputNode* child) {
   DCHECK(child);
   DCHECK(!child->IsFloating());
 
-  // TODO(ikilpatrick): Pass in BFC offset from previous in-flow child.
-  curr_bfc_offset_ = container_builder_.BfcOffset()
-                         ? container_builder_.BfcOffset().value()
-                         : ConstraintSpace().BfcOffset();
-  curr_bfc_offset_.block_offset += content_size_;
+  LayoutUnit bfc_block_offset = previous_inflow_position.bfc_block_offset;
 
   // Calculate margins in parent's writing mode.
-  curr_child_margins_ = CalculateMargins(child);
+  NGBoxStrut margins = CalculateMargins(child);
+  NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
 
   bool should_position_pending_floats =
       !IsNewFormattingContextForBlockLevelChild(Style(), *child) &&
@@ -371,45 +399,50 @@
   // be positioned before layout. This also resolves the fragment's bfc offset.
   if (should_position_pending_floats) {
     LayoutUnit origin_point_block_offset =
-        curr_bfc_offset_.block_offset + curr_margin_strut_.Sum();
-    MaybeUpdateFragmentBfcOffset(
-        ConstraintSpace(),
-        {curr_bfc_offset_.inline_offset, origin_point_block_offset},
-        &container_builder_);
+        bfc_block_offset + margin_strut.Sum();
+    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), origin_point_block_offset,
+                                 &container_builder_);
+    // TODO(ikilpatrick): Check if origin_point_block_offset is correct -
+    // MaybeUpdateFragmentBfcOffset might have changed it due to clearance.
     PositionPendingFloats(origin_point_block_offset, &container_builder_,
                           MutableConstraintSpace());
   }
 
-  NGLogicalOffset child_bfc_offset = curr_bfc_offset_;
-  child_bfc_offset.inline_offset +=
-      {border_and_padding_.inline_start + curr_child_margins_.inline_start};
+  NGLogicalOffset child_bfc_offset = {
+      ConstraintSpace().BfcOffset().inline_offset +
+          border_and_padding_.inline_start + margins.inline_start,
+      bfc_block_offset};
+
+  bool is_new_fc = IsNewFormattingContextForBlockLevelChild(Style(), *child);
 
   // Append the current margin strut with child's block start margin.
   // Non empty border/padding, and new FC use cases are handled inside of the
   // child's layout.
-  if (!IsNewFormattingContextForBlockLevelChild(Style(), *child))
-    curr_margin_strut_.Append(curr_child_margins_.block_start);
+  if (!is_new_fc)
+    margin_strut.Append(margins.block_start);
 
   // TODO(crbug.com/716930): We should also collapse margins below once we
   // remove LayoutInline splitting.
 
   // Should collapse margins if our child is a legacy block.
-  if (IsLegacyBlock(*child)) {
-    curr_bfc_offset_ +=
-        {border_and_padding_.inline_start + curr_child_margins_.inline_start,
-         curr_margin_strut_.Sum()};
-    MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
-                                 &container_builder_);
-    PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
+  // TODO(ikilpatrick): I think this can be removed.
+  if (IsLegacyBlock(*child) && !is_new_fc) {
+    child_bfc_offset.block_offset += margin_strut.Sum();
+    MaybeUpdateFragmentBfcOffset(
+        ConstraintSpace(), child_bfc_offset.block_offset, &container_builder_);
+    // TODO(ikilpatrick): Check if child_bfc_offset.block_offset is correct -
+    // MaybeUpdateFragmentBfcOffset might have changed it due to clearance.
+    PositionPendingFloats(child_bfc_offset.block_offset, &container_builder_,
                           MutableConstraintSpace());
-    curr_margin_strut_ = {};
+    margin_strut = {};
   }
-  child_bfc_offset.block_offset = curr_bfc_offset_.block_offset;
-  return child_bfc_offset;
+  return {child_bfc_offset, margin_strut, margins};
 }
 
-void NGBlockLayoutAlgorithm::FinishChildLayout(
+NGPreviousInflowPosition NGBlockLayoutAlgorithm::FinishChildLayout(
     const NGConstraintSpace& child_space,
+    const NGPreviousInflowPosition& previous_inflow_position,
+    const NGInflowChildData& child_data,
     const NGLayoutInputNode* child,
     NGLayoutResult* layout_result) {
   // Pull out unpositioned floats to the current fragment. This may needed if
@@ -425,97 +458,134 @@
   // Determine the fragment's position in the parent space.
   WTF::Optional<NGLogicalOffset> child_bfc_offset;
   if (child_space.IsNewFormattingContext())
-    child_bfc_offset = PositionNewFc(fragment, child_space);
+    child_bfc_offset = PositionNewFc(*child, previous_inflow_position, fragment,
+                                     child_data, child_space);
   else if (fragment.BfcOffset())
     child_bfc_offset = PositionWithBfcOffset(fragment);
   else if (IsLegacyBlock(*child))
-    child_bfc_offset = PositionLegacy(child_space);
+    child_bfc_offset = PositionLegacy(child_space, child_data);
   else if (container_builder_.BfcOffset())
-    child_bfc_offset = PositionWithParentBfc(child_space, fragment);
+    child_bfc_offset = PositionWithParentBfc(child_space, child_data, fragment);
 
-  NGLogicalOffset logical_offset = CalculateLogicalOffset(child_bfc_offset);
+  NGLogicalOffset logical_offset =
+      CalculateLogicalOffset(child_data.margins, child_bfc_offset);
 
-  // Update margin strut.
-  curr_margin_strut_ = fragment.EndMarginStrut();
-  curr_margin_strut_.Append(curr_child_margins_.block_end);
+  NGMarginStrut margin_strut = fragment.EndMarginStrut();
+  margin_strut.Append(child_data.margins.block_end);
 
-  // Only modify content_size if BlockSize is not empty. It's needed to prevent
-  // the situation when logical_offset is included in content_size for empty
-  // blocks. Example:
+  // Only modify content_size_ if the fragment's BlockSize is not empty. This is
+  // needed to prevent the situation when logical_offset is included in
+  // content_size_ for empty blocks. Example:
   //   <div style="overflow:hidden">
   //     <div style="margin-top: 8px"></div>
   //     <div style="margin-top: 10px"></div>
   //   </div>
   if (fragment.BlockSize())
-    content_size_ = fragment.BlockSize() + logical_offset.block_offset;
-  max_inline_size_ =
-      std::max(max_inline_size_, fragment.InlineSize() +
-                                     curr_child_margins_.InlineSum() +
-                                     border_and_padding_.InlineSum());
+    content_size_ = std::max(
+        content_size_, logical_offset.block_offset + fragment.BlockSize());
+  max_inline_size_ = std::max(
+      max_inline_size_, fragment.InlineSize() + child_data.margins.InlineSum() +
+                            border_and_padding_.InlineSum());
 
   container_builder_.AddChild(layout_result, logical_offset);
+
+  // Determine the child's end BFC block offset for the next child to use.
+  LayoutUnit child_end_bfc_block_offset;
+  if (child_bfc_offset) {
+    // TODO(crbug.com/716930): I think the fragment.BfcOffset() condition here
+    // can be removed once we've removed inline splitting.
+    if (fragment.BlockSize() || fragment.BfcOffset()) {
+      child_end_bfc_block_offset =
+          child_bfc_offset.value().block_offset + fragment.BlockSize();
+    } else {
+      DCHECK_EQ(LayoutUnit(), fragment.BlockSize());
+      child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
+    }
+  } else {
+    child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset;
+  }
+
+  return {child_end_bfc_block_offset,
+          logical_offset.block_offset + fragment.BlockSize(), margin_strut};
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc(
+    const NGLayoutInputNode& child,
+    const NGPreviousInflowPosition& previous_inflow_position,
     const NGBoxFragment& fragment,
+    const NGInflowChildData& child_data,
     const NGConstraintSpace& child_space) {
+  const ComputedStyle& child_style = child.Style();
+
+  LayoutUnit child_bfc_offset_estimate =
+      child_data.bfc_offset_estimate.block_offset;
+
   // 1. Position all pending floats to a temporary space.
   RefPtr<NGConstraintSpace> tmp_space =
       NGConstraintSpaceBuilder(&child_space)
           .SetIsNewFormattingContext(false)
           .ToConstraintSpace(child_space.WritingMode());
-  PositionFloats(curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset,
-                 curr_bfc_offset_.block_offset,
+  PositionFloats(child_bfc_offset_estimate, child_bfc_offset_estimate,
+                 child_bfc_offset_estimate,
                  container_builder_.UnpositionedFloats(), tmp_space.Get());
 
-  NGLogicalOffset origin_offset = curr_bfc_offset_;
-  origin_offset.inline_offset += border_and_padding_.inline_start;
+  NGLogicalOffset origin_offset = {ConstraintSpace().BfcOffset().inline_offset +
+                                       border_and_padding_.inline_start,
+                                   child_bfc_offset_estimate};
+  AdjustToClearance(
+      GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()),
+      &origin_offset);
 
   // 2. Find an estimated layout opportunity for our fragment.
   NGLayoutOpportunity opportunity = FindLayoutOpportunityForFragment(
       tmp_space->Exclusions().get(), child_space.AvailableSize(), origin_offset,
-      curr_child_margins_, fragment.Size());
+      child_data.margins, fragment.Size());
+
+  NGMarginStrut margin_strut = previous_inflow_position.margin_strut;
 
   // 3. If the found opportunity lies on the same line with our estimated
   //    child's BFC offset then merge fragment's margins with the current
   //    MarginStrut.
-  if (opportunity.offset.block_offset == curr_bfc_offset_.block_offset)
-    curr_margin_strut_.Append(curr_child_margins_.block_start);
-  curr_bfc_offset_.block_offset += curr_margin_strut_.Sum();
-  curr_margin_strut_ = {};
+  if (opportunity.offset.block_offset == child_bfc_offset_estimate)
+    margin_strut.Append(child_data.margins.block_start);
+  child_bfc_offset_estimate += margin_strut.Sum();
 
   // 4. The child's BFC block offset is known here.
-  MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
+  MaybeUpdateFragmentBfcOffset(ConstraintSpace(), child_bfc_offset_estimate,
                                &container_builder_);
-  PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
+  PositionPendingFloats(child_bfc_offset_estimate, &container_builder_,
                         MutableConstraintSpace());
 
-  origin_offset = curr_bfc_offset_;
-  origin_offset.inline_offset += border_and_padding_.inline_start;
+  origin_offset = {ConstraintSpace().BfcOffset().inline_offset +
+                       border_and_padding_.inline_start,
+                   child_bfc_offset_estimate};
+  AdjustToClearance(
+      GetClearanceOffset(ConstraintSpace().Exclusions(), child_style.Clear()),
+      &origin_offset);
 
   // 5. Find the final layout opportunity for the fragment after all pending
   // floats are positioned at the correct BFC block's offset.
   opportunity = FindLayoutOpportunityForFragment(
       MutableConstraintSpace()->Exclusions().get(), child_space.AvailableSize(),
-      origin_offset, curr_child_margins_, fragment.Size());
+      origin_offset, child_data.margins, fragment.Size());
 
-  curr_bfc_offset_ = opportunity.offset;
-  return curr_bfc_offset_;
+  return opportunity.offset;
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithBfcOffset(
     const NGBoxFragment& fragment) {
   DCHECK(fragment.BfcOffset());
-  curr_bfc_offset_.block_offset = fragment.BfcOffset().value().block_offset;
-  MaybeUpdateFragmentBfcOffset(ConstraintSpace(), curr_bfc_offset_,
+  LayoutUnit bfc_block_offset = fragment.BfcOffset().value().block_offset;
+  MaybeUpdateFragmentBfcOffset(ConstraintSpace(), bfc_block_offset,
                                &container_builder_);
-  PositionPendingFloats(curr_bfc_offset_.block_offset, &container_builder_,
+  PositionPendingFloats(bfc_block_offset, &container_builder_,
                         MutableConstraintSpace());
   return fragment.BfcOffset().value();
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionWithParentBfc(
     const NGConstraintSpace& space,
+    const NGInflowChildData& child_data,
     const NGBoxFragment& fragment) {
   // The child must be an in-flow zero-block-size fragment, use its end margin
   // strut for positioning.
@@ -523,22 +593,28 @@
   DCHECK_EQ(fragment.BlockSize(), LayoutUnit());
 
   NGMarginStrut margin_strut = fragment.EndMarginStrut();
-  margin_strut.Append(curr_child_margins_.block_end);
+  margin_strut.Append(child_data.margins.block_end);
 
-  curr_bfc_offset_ +=
-      {border_and_padding_.inline_start + curr_child_margins_.inline_start,
-       margin_strut.Sum()};
-  AdjustToClearance(space.ClearanceOffset(), &curr_bfc_offset_);
-  PositionPendingFloatsFromOffset(
-      curr_bfc_offset_.block_offset, curr_bfc_offset_.block_offset,
-      &container_builder_, MutableConstraintSpace());
-  return curr_bfc_offset_;
+  NGLogicalOffset bfc_offset = {
+      ConstraintSpace().BfcOffset().inline_offset +
+          border_and_padding_.inline_start + child_data.margins.inline_start,
+      child_data.bfc_offset_estimate.block_offset + margin_strut.Sum()};
+  AdjustToClearance(space.ClearanceOffset(), &bfc_offset);
+  PositionPendingFloatsFromOffset(bfc_offset.block_offset,
+                                  bfc_offset.block_offset, &container_builder_,
+                                  MutableConstraintSpace());
+  return bfc_offset;
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionLegacy(
-    const NGConstraintSpace& child_space) {
-  AdjustToClearance(child_space.ClearanceOffset(), &curr_bfc_offset_);
-  return curr_bfc_offset_;
+    const NGConstraintSpace& child_space,
+    const NGInflowChildData& child_data) {
+  NGLogicalOffset bfc_offset = {ConstraintSpace().BfcOffset().inline_offset +
+                                    border_and_padding_.inline_start +
+                                    child_data.margins.inline_start,
+                                child_data.bfc_offset_estimate.block_offset};
+  AdjustToClearance(child_space.ClearanceOffset(), &bfc_offset);
+  return bfc_offset;
 }
 
 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
@@ -609,8 +685,8 @@
 }
 
 RefPtr<NGConstraintSpace> NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
-    const NGLogicalOffset& child_bfc_offset,
-    const NGLayoutInputNode& child) {
+    const NGLayoutInputNode& child,
+    const NGInflowChildData& child_data) {
   NGConstraintSpaceBuilder space_builder(MutableConstraintSpace());
   space_builder.SetAvailableSize(child_available_size_)
       .SetPercentageResolutionSize(child_percentage_size_);
@@ -618,8 +694,8 @@
   const ComputedStyle& child_style = child.Style();
   bool is_new_bfc = IsNewFormattingContextForBlockLevelChild(Style(), child);
   space_builder.SetIsNewFormattingContext(is_new_bfc)
-      .SetBfcOffset(child_bfc_offset)
-      .SetMarginStrut(curr_margin_strut_);
+      .SetBfcOffset(child_data.bfc_offset_estimate)
+      .SetMarginStrut(child_data.margin_strut);
 
   if (!is_new_bfc) {
     space_builder.SetUnpositionedFloats(
@@ -646,7 +722,7 @@
     // position in the formatting context, and are able to adjust the
     // fragmentation line.
     if (is_new_bfc) {
-      space_available -= child_bfc_offset.block_offset;
+      space_available -= child_data.bfc_offset_estimate.block_offset;
     }
   }
   space_builder.SetFragmentainerSpaceAvailable(space_available);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index 9ce63c41..6b46510 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -18,10 +18,12 @@
 
 class NGConstraintSpace;
 class NGLayoutResult;
+struct NGInflowChildData;
+struct NGPreviousInflowPosition;
 
 // Updates the fragment's BFC offset if it's not already set.
 void MaybeUpdateFragmentBfcOffset(const NGConstraintSpace&,
-                                  const NGLogicalOffset&,
+                                  LayoutUnit bfc_block_offset,
                                   NGFragmentBuilder* builder);
 
 // Positions pending floats starting from {@origin_block_offset} and relative
@@ -52,15 +54,19 @@
 
   // Creates a new constraint space for the current child.
   RefPtr<NGConstraintSpace> CreateConstraintSpaceForChild(
-      const NGLogicalOffset& child_bfc_offset,
-      const NGLayoutInputNode&);
+      const NGLayoutInputNode& child,
+      const NGInflowChildData& child_data);
 
   // @return Estimated BFC offset for the "to be layout" child.
-  NGLogicalOffset PrepareChildLayout(NGLayoutInputNode*);
+  NGInflowChildData PrepareChildLayout(const NGPreviousInflowPosition&,
+                                       NGLayoutInputNode*);
 
-  void FinishChildLayout(const NGConstraintSpace&,
-                         const NGLayoutInputNode* child,
-                         NGLayoutResult*);
+  NGPreviousInflowPosition FinishChildLayout(
+      const NGConstraintSpace&,
+      const NGPreviousInflowPosition& prev_data,
+      const NGInflowChildData& child_data,
+      const NGLayoutInputNode* child,
+      NGLayoutResult*);
 
   // Positions the fragment that establishes a new formatting context.
   //
@@ -81,7 +87,10 @@
   //    then it will be placed there and we collapse its margin.
   // 2) If #new-fc is too big then we need to clear its position and place it
   //    below #float ignoring its vertical margin.
-  NGLogicalOffset PositionNewFc(const NGBoxFragment&,
+  NGLogicalOffset PositionNewFc(const NGLayoutInputNode& child,
+                                const NGPreviousInflowPosition&,
+                                const NGBoxFragment&,
+                                const NGInflowChildData& child_data,
                                 const NGConstraintSpace& child_space);
 
   // Positions the fragment that knows its BFC offset.
@@ -95,12 +104,16 @@
   //   <div style="padding: 1px">
   //     <div id="empty-div" style="margins: 1px"></div>
   NGLogicalOffset PositionWithParentBfc(const NGConstraintSpace&,
+                                        const NGInflowChildData& child_data,
                                         const NGBoxFragment&);
 
-  NGLogicalOffset PositionLegacy(const NGConstraintSpace& child_space);
+  NGLogicalOffset PositionLegacy(const NGConstraintSpace& child_space,
+                                 const NGInflowChildData& child_data);
 
-  void HandleOutOfFlowPositioned(NGBlockNode*);
-  void HandleFloating(NGBlockNode*, NGBlockBreakToken*);
+  void HandleOutOfFlowPositioned(const NGPreviousInflowPosition&, NGBlockNode*);
+  void HandleFloating(const NGPreviousInflowPosition&,
+                      NGBlockNode*,
+                      NGBlockBreakToken*);
 
   // Final adjustments before fragment creation. We need to prevent the
   // fragment from crossing fragmentainer boundaries, and rather create a break
@@ -112,6 +125,7 @@
   // or {@code known_fragment_offset} if the fragment knows it's offset
   // @return Fragment's offset relative to the fragment's parent.
   NGLogicalOffset CalculateLogicalOffset(
+      const NGBoxStrut& child_margins,
       const WTF::Optional<NGLogicalOffset>& known_fragment_offset);
 
   NGLogicalSize child_available_size_;
@@ -120,10 +134,6 @@
   NGBoxStrut border_and_padding_;
   LayoutUnit content_size_;
   LayoutUnit max_inline_size_;
-  // MarginStrut for the previous child.
-  NGMarginStrut curr_margin_strut_;
-  NGLogicalOffset curr_bfc_offset_;
-  NGBoxStrut curr_child_margins_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
index cab8dce..65c85ef8 100644
--- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
+++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -394,8 +394,9 @@
       DOMArrayBuffer* buffer = DOMArrayBuffer::CreateUninitializedOrNull(
           binary_response_builder_->size(), 1);
       if (buffer) {
-        binary_response_builder_->GetAsBytes(
+        bool result = binary_response_builder_->GetBytes(
             buffer->Data(), static_cast<size_t>(buffer->ByteLength()));
+        DCHECK(result);
         response_array_buffer_ = buffer;
       }
       // https://xhr.spec.whatwg.org/#arraybuffer-response allows clearing
diff --git a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
index df3eda95..672d7fd 100644
--- a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
+++ b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
@@ -1174,11 +1174,11 @@
    * @param {number} scale
    * @return {!Promise}
    */
-  update(glContext, scale) {
+  async update(glContext, scale) {
     this._gl = glContext;
     this.scale = scale;
-    return this.snapshot.replay(null, null, scale).then(imageURL => imageURL && UI.loadImage(imageURL)).then(image => {
-      this.texture = image && LayerViewer.LayerTextureManager._createTextureForImage(glContext, image);
-    });
+    var imageURL = await this.snapshot.replay(scale);
+    var image = imageURL && await UI.loadImage(imageURL);
+    this.texture = image && LayerViewer.LayerTextureManager._createTextureForImage(glContext, image);
   }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js b/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js
index e34c95c..21aba3de 100644
--- a/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js
+++ b/third_party/WebKit/Source/devtools/front_end/layer_viewer/PaintProfilerView.js
@@ -157,7 +157,7 @@
    * @param {!Array.<!SDK.PaintProfilerLogItem>} log
    * @param {?Protocol.DOM.Rect} clipRect
    */
-  setSnapshotAndLog(snapshot, log, clipRect) {
+  async setSnapshotAndLog(snapshot, log, clipRect) {
     this._reset();
     this._snapshot = snapshot;
     if (this._snapshot)
@@ -174,17 +174,13 @@
     this._selectionWindow.setEnabled(true);
     this._progressBanner.classList.remove('hidden');
     this._updateImage();
-    snapshot.profile(clipRect, onProfileDone.bind(this));
-    /**
-     * @param {!Array.<!Protocol.LayerTree.PaintProfile>=} profiles
-     * @this {LayerViewer.PaintProfilerView}
-     */
-    function onProfileDone(profiles) {
-      this._progressBanner.classList.add('hidden');
-      this._profiles = profiles;
-      this._update();
-      this._updatePieChart();
-    }
+
+    var profiles = await snapshot.profile(clipRect);
+
+    this._progressBanner.classList.add('hidden');
+    this._profiles = profiles;
+    this._update();
+    this._updatePieChart();
   }
 
   /**
@@ -323,15 +319,15 @@
 
   _updateImage() {
     delete this._updateImageTimer;
-    var left = null;
-    var right = null;
+    var left;
+    var right;
     var window = this.selectionWindow();
     if (this._profiles && this._profiles.length && window) {
       left = this._log[window.left].commandIndex;
       right = this._log[window.right - 1].commandIndex;
     }
     var scale = this._pendingScale;
-    this._snapshot.replay(left, right, scale).then(image => {
+    this._snapshot.replay(scale, left, right).then(image => {
       if (!image)
         return;
       this._scale = scale;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js b/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
index 058e3e18..5d8afa3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
@@ -41,9 +41,9 @@
    * @param {!Array.<!SDK.PictureFragment>} fragments
    * @return {!Promise<?SDK.PaintProfilerSnapshot>}
    */
-  loadSnapshotFromFragments(fragments) {
-    return this._layerTreeAgent.loadSnapshot(
-        fragments, (error, snapshotId) => error ? null : new SDK.PaintProfilerSnapshot(this, snapshotId));
+  async loadSnapshotFromFragments(fragments) {
+    var snapshotId = await this._layerTreeAgent.loadSnapshot(fragments);
+    return snapshotId && new SDK.PaintProfilerSnapshot(this, snapshotId);
   }
 
   /**
@@ -59,9 +59,9 @@
    * @param {string} layerId
    * @return {!Promise<?SDK.PaintProfilerSnapshot>}
    */
-  makeSnapshot(layerId) {
-    return this._layerTreeAgent.makeSnapshot(
-        layerId, (error, snapshotId) => error ? null : new SDK.PaintProfilerSnapshot(this, snapshotId));
+  async makeSnapshot(layerId) {
+    var snapshotId = await this._layerTreeAgent.makeSnapshot(layerId);
+    return snapshotId && new SDK.PaintProfilerSnapshot(this, snapshotId);
   }
 };
 
@@ -95,43 +95,29 @@
   }
 
   /**
-   * @param {?number} firstStep
-   * @param {?number} lastStep
-   * @param {?number} scale
+   * @param {number=} scale
+   * @param {number=} firstStep
+   * @param {number=} lastStep
    * @return {!Promise<?string>}
    */
-  replay(firstStep, lastStep, scale) {
-    return this._paintProfilerModel._layerTreeAgent.replaySnapshot(
-        this._id, firstStep || undefined, lastStep || undefined, scale || 1.0, (error, str) => error ? null : str);
+  replay(scale, firstStep, lastStep) {
+    return this._paintProfilerModel._layerTreeAgent.replaySnapshot(this._id, firstStep, lastStep, scale || 1.0);
   }
 
   /**
    * @param {?Protocol.DOM.Rect} clipRect
-   * @param {function(!Array.<!Protocol.LayerTree.PaintProfile>=)} callback
+   * @return {!Promise<?Array<!Protocol.LayerTree.PaintProfile>>}
    */
-  profile(clipRect, callback) {
-    var wrappedCallback =
-        Protocol.inspectorBackend.wrapClientCallback(callback, 'Protocol.LayerTree.profileSnapshot(): ');
-    this._paintProfilerModel._layerTreeAgent.profileSnapshot(this._id, 5, 1, clipRect || undefined, wrappedCallback);
+  profile(clipRect) {
+    return this._paintProfilerModel._layerTreeAgent.profileSnapshot(this._id, 5, 1, clipRect || undefined);
   }
 
   /**
    * @return {!Promise<?Array<!SDK.PaintProfilerLogItem>>}
    */
-  commandLog() {
-    return this._paintProfilerModel._layerTreeAgent.snapshotCommandLog(this._id, processLog);
-
-    /**
-     * @param {?string} error
-     * @param {?Array<!Object>} log
-     */
-    function processLog(error, log) {
-      if (error)
-        return null;
-      return log.map(
-          (entry, index) => new SDK.PaintProfilerLogItem(
-              /** @type {!SDK.RawPaintProfilerLogItem} */ (entry), index));
-    }
+  async commandLog() {
+    var log = await this._paintProfilerModel._layerTreeAgent.snapshotCommandLog(this._id);
+    return log && log.map((entry, index) => new SDK.PaintProfilerLogItem(entry, index));
   }
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
index b475dd5..8fe9c58 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -1413,7 +1413,7 @@
     var snapshotWithRect = await new TimelineModel.LayerPaintEvent(event, target).snapshotPromise();
     if (!snapshotWithRect)
       return null;
-    var imageURLPromise = snapshotWithRect.snapshot.replay(null, null, 1);
+    var imageURLPromise = snapshotWithRect.snapshot.replay();
     snapshotWithRect.snapshot.release();
     var imageURL = await imageURLPromise;
     if (!imageURL)
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
index 45713fa..d5817d3 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -52,7 +52,6 @@
     "CSS",
     "DOMDebugger",
     "IndexedDB",
-    "LayerTree",
 ])
 
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
index ef2efa1..c32619d 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -1240,15 +1240,18 @@
 
   sk_sp<SkColorSpace> src_sk_color_space = nullptr;
   if (u8_array) {
-    src_sk_color_space = ImageData::GetSkColorSpaceForTest(
-        src_color_space, kRGBA8CanvasPixelFormat);
+    src_sk_color_space =
+        CanvasColorParams(src_color_space, kRGBA8CanvasPixelFormat)
+            .GetSkColorSpaceForSkSurfaces();
   } else {
-    src_sk_color_space = ImageData::GetSkColorSpaceForTest(
-        src_color_space, kF16CanvasPixelFormat);
+    src_sk_color_space =
+        CanvasColorParams(src_color_space, kF16CanvasPixelFormat)
+            .GetSkColorSpaceForSkSurfaces();
   }
 
   sk_sp<SkColorSpace> dst_sk_color_space =
-      ImageData::GetSkColorSpaceForTest(dst_color_space, dst_pixel_format);
+      CanvasColorParams(dst_color_space, dst_pixel_format)
+          .GetSkColorSpaceForSkSurfaces();
 
   // When the input dataArray is in Uint16, we normally should convert the
   // values from Little Endian to Big Endian before passing the buffer to
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
index 36969a7..b18bbcf 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
@@ -157,10 +157,9 @@
   DCHECK(value);
 
   uint8_t header[3];
-  if (!value->data_ || value->data_->size() < sizeof(header))
+  if (!value->data_ || !value->data_->GetBytes(header, sizeof(header)))
     return false;
 
-  value->data_->GetPartAsBytes(header, static_cast<size_t>(0), sizeof(header));
   return header[0] == kVersionTag &&
          header[1] == kRequiresProcessingSSVPseudoVersion &&
          header[2] == kBlobWrappedValue;
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
index 6db678ea..f3beb0a2 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
@@ -34,8 +34,8 @@
   EXPECT_TRUE(IDBValueUnwrapper::IsWrapped(wrapped_value.Get()));
 
   Vector<char> wrapped_marker_bytes(wrapped_marker_buffer->size());
-  wrapped_marker_buffer->GetAsBytes(wrapped_marker_bytes.data(),
-                                    wrapped_marker_bytes.size());
+  ASSERT_TRUE(wrapped_marker_buffer->GetBytes(wrapped_marker_bytes.data(),
+                                              wrapped_marker_bytes.size()));
 
   // IsWrapped() looks at the first 3 bytes in the value's byte array.
   // Truncating the array to fewer than 3 bytes should cause IsWrapped() to
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 13f3379..86a8aa4 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -237,6 +237,7 @@
                     "sensor/Gyroscope.idl",
                     "sensor/Magnetometer.idl",
                     "sensor/OrientationSensor.idl",
+                    "sensor/RelativeOrientationSensor.idl",
                     "sensor/Sensor.idl",
                     "sensor/SensorErrorEvent.idl",
                     "serviceworkers/Client.idl",
diff --git a/third_party/WebKit/Source/modules/sensor/BUILD.gn b/third_party/WebKit/Source/modules/sensor/BUILD.gn
index 7fd28fa6..5154b933 100644
--- a/third_party/WebKit/Source/modules/sensor/BUILD.gn
+++ b/third_party/WebKit/Source/modules/sensor/BUILD.gn
@@ -18,6 +18,8 @@
     "Magnetometer.h",
     "OrientationSensor.cpp",
     "OrientationSensor.h",
+    "RelativeOrientationSensor.cpp",
+    "RelativeOrientationSensor.h",
     "Sensor.cpp",
     "Sensor.h",
     "SensorErrorEvent.cpp",
diff --git a/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp
new file mode 100644
index 0000000..22e97ea
--- /dev/null
+++ b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.cpp
@@ -0,0 +1,39 @@
+// 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 "modules/sensor/RelativeOrientationSensor.h"
+
+using device::mojom::blink::SensorType;
+
+namespace blink {
+
+RelativeOrientationSensor* RelativeOrientationSensor::Create(
+    ExecutionContext* execution_context,
+    const SensorOptions& options,
+    ExceptionState& exception_state) {
+  return new RelativeOrientationSensor(execution_context, options,
+                                       exception_state);
+}
+
+// static
+RelativeOrientationSensor* RelativeOrientationSensor::Create(
+    ExecutionContext* execution_context,
+    ExceptionState& exception_state) {
+  return Create(execution_context, SensorOptions(), exception_state);
+}
+
+RelativeOrientationSensor::RelativeOrientationSensor(
+    ExecutionContext* execution_context,
+    const SensorOptions& options,
+    ExceptionState& exception_state)
+    : OrientationSensor(execution_context,
+                        options,
+                        exception_state,
+                        SensorType::RELATIVE_ORIENTATION) {}
+
+DEFINE_TRACE(RelativeOrientationSensor) {
+  OrientationSensor::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.h b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.h
new file mode 100644
index 0000000..3b5a9be
--- /dev/null
+++ b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.h
@@ -0,0 +1,31 @@
+// 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 RelativeOrientationSensor_h
+#define RelativeOrientationSensor_h
+
+#include "modules/sensor/OrientationSensor.h"
+
+namespace blink {
+
+class RelativeOrientationSensor final : public OrientationSensor {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static RelativeOrientationSensor* Create(ExecutionContext*,
+                                           const SensorOptions&,
+                                           ExceptionState&);
+  static RelativeOrientationSensor* Create(ExecutionContext*, ExceptionState&);
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  RelativeOrientationSensor(ExecutionContext*,
+                            const SensorOptions&,
+                            ExceptionState&);
+};
+
+}  // namespace blink
+
+#endif  // RelativeOrientationSensor_h
diff --git a/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.idl b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.idl
new file mode 100644
index 0000000..b782ad94
--- /dev/null
+++ b/third_party/WebKit/Source/modules/sensor/RelativeOrientationSensor.idl
@@ -0,0 +1,15 @@
+// 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.
+
+// Specification at:
+// https://w3c.github.io/orientation-sensor/#relativeorientationsensor-interface
+
+[
+    RuntimeEnabled=Sensor,
+    Constructor(optional SensorOptions sensorOptions),
+    ConstructorCallWith=ExecutionContext,
+    RaisesException=Constructor,
+    MeasureAs=RelativeOrientationSensorConstructor
+] interface RelativeOrientationSensor : OrientationSensor {
+};
diff --git a/third_party/WebKit/Source/platform/SharedBuffer.cpp b/third_party/WebKit/Source/platform/SharedBuffer.cpp
index fa32abda..39707b6 100644
--- a/third_party/WebKit/Source/platform/SharedBuffer.cpp
+++ b/third_party/WebKit/Source/platform/SharedBuffer.cpp
@@ -204,13 +204,12 @@
   return 0;
 }
 
-bool SharedBuffer::GetAsBytesInternal(void* dest,
-                                      size_t load_position,
-                                      size_t byte_length) const {
+bool SharedBuffer::GetBytesInternal(void* dest, size_t byte_length) const {
   if (!dest)
     return false;
 
   const char* segment = nullptr;
+  size_t load_position = 0;
   size_t write_position = 0;
   while (byte_length > 0) {
     size_t load_size = GetSomeDataInternal(segment, load_position);
diff --git a/third_party/WebKit/Source/platform/SharedBuffer.h b/third_party/WebKit/Source/platform/SharedBuffer.h
index e0d2d54..0fa3f91 100644
--- a/third_party/WebKit/Source/platform/SharedBuffer.h
+++ b/third_party/WebKit/Source/platform/SharedBuffer.h
@@ -112,26 +112,14 @@
     return GetSomeDataInternal(data, position);
   }
 
-  // Returns the content data into "dest" as a flat buffer. "byteLength" must
-  // exactly match with size(). |dest| must not be null even if |bytesLength|
-  // is 0.
+  // Copies |byteLength| bytes from the beginning of the content data into
+  // |dest| as a flat buffer. Returns true on success, otherwise the content of
+  // |dest| is not guaranteed.
   HAS_STRICTLY_TYPED_ARG
-  void GetAsBytes(void* dest, STRICTLY_TYPED_ARG(byte_length)) const {
+  WARN_UNUSED_RESULT
+  bool GetBytes(void* dest, STRICTLY_TYPED_ARG(byte_length)) const {
     STRICT_ARG_TYPE(size_t);
-    DCHECK_EQ(byte_length, size());
-    auto result = GetAsBytesInternal(dest, 0, byte_length);
-    DCHECK(result);
-  }
-
-  // Copies "byteLength" bytes from "position"-th bytes (0 origin) of the
-  // content data into "dest" as a flat buffer, Returns true on success,
-  // otherwise the content of "dest" is not guaranteed.
-  HAS_STRICTLY_TYPED_ARG
-  bool GetPartAsBytes(void* dest,
-                      STRICTLY_TYPED_ARG(position),
-                      STRICTLY_TYPED_ARG(byte_length)) const {
-    STRICT_ARG_TYPE(size_t);
-    return GetAsBytesInternal(dest, position, byte_length);
+    return GetBytesInternal(dest, byte_length);
   }
 
   // Creates an SkData and copies this SharedBuffer's contents to that
@@ -150,7 +138,7 @@
   void MergeSegmentsIntoBuffer() const;
 
   void AppendInternal(const char* data, size_t);
-  bool GetAsBytesInternal(void* dest, size_t, size_t) const;
+  bool GetBytesInternal(void* dest, size_t) const;
   size_t GetSomeDataInternal(const char*& data, size_t position) const;
 
   size_t size_;
diff --git a/third_party/WebKit/Source/platform/SharedBufferTest.cpp b/third_party/WebKit/Source/platform/SharedBufferTest.cpp
index 8900ca30..269ebf3 100644
--- a/third_party/WebKit/Source/platform/SharedBufferTest.cpp
+++ b/third_party/WebKit/Source/platform/SharedBufferTest.cpp
@@ -52,7 +52,7 @@
 
   const size_t size = shared_buffer->size();
   std::unique_ptr<char[]> data = WrapArrayUnique(new char[size]);
-  shared_buffer->GetAsBytes(data.get(), size);
+  ASSERT_TRUE(shared_buffer->GetBytes(data.get(), size));
 
   char expected_concatenation[] = "HelloWorldGoodbye";
   ASSERT_EQ(strlen(expected_concatenation), size);
@@ -71,16 +71,14 @@
   shared_buffer->Append(test_data2, strlen(test_data2));
 
   struct TestData {
-    size_t position;
     size_t size;
     const char* expected;
   } test_data[] = {
-      {0, 17, "HelloWorldGoodbye"}, {0, 7, "HelloWo"}, {4, 7, "oWorldG"},
+      {17, "HelloWorldGoodbye"}, {7, "HelloWo"}, {3, "Hel"},
   };
   for (TestData& test : test_data) {
     std::unique_ptr<char[]> data = WrapArrayUnique(new char[test.size]);
-    ASSERT_TRUE(
-        shared_buffer->GetPartAsBytes(data.get(), test.position, test.size));
+    ASSERT_TRUE(shared_buffer->GetBytes(data.get(), test.size));
     EXPECT_EQ(0, memcmp(test.expected, data.get(), test.size));
   }
 }
@@ -102,7 +100,7 @@
 
   const size_t size = shared_buffer->size();
   std::unique_ptr<char[]> data = WrapArrayUnique(new char[size]);
-  shared_buffer->GetAsBytes(data.get(), size);
+  ASSERT_TRUE(shared_buffer->GetBytes(data.get(), size));
 
   ASSERT_EQ(0x4000U + 0x4000U + 0x4000U, size);
   int position = 0;
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
index 4c73aaa..eb8fdd5 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
@@ -6,6 +6,7 @@
 
 #include <inttypes.h>
 #include <algorithm>
+#include "platform/bindings/V8PerIsolateData.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
@@ -43,6 +44,11 @@
   }
 }
 
+// static
+RuntimeCallStats* RuntimeCallStats::From(v8::Isolate* isolate) {
+  return V8PerIsolateData::From(isolate)->GetRuntimeCallStats();
+}
+
 void RuntimeCallStats::Reset() {
   for (int i = 0; i < number_of_counters_; i++) {
     counters_[i].Reset();
@@ -55,7 +61,7 @@
   builder.Append("Name                              Count     Time (ms)\n\n");
   for (int i = 0; i < number_of_counters_; i++) {
     const RuntimeCallCounter* counter = &counters_[i];
-    builder.Append(String::Format("%-32s  %8" PRIu64 "%8.3f\n",
+    builder.Append(String::Format("%-32s  %8" PRIu64 "  %9.3f\n",
                                   counter->GetName(), counter->GetCount(),
                                   counter->GetTime().InMillisecondsF()));
   }
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
index dd36d7c..546ddea 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This file contains the Blink version of RuntimeCallStats which is implemented
+// by V8 in //v8/src/counters.h
+
 #ifndef RuntimeCallStats_h
 #define RuntimeCallStats_h
 
@@ -9,6 +12,7 @@
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Time.h"
 #include "platform/wtf/text/WTFString.h"
+#include "v8/include/v8.h"
 
 namespace blink {
 
@@ -90,6 +94,8 @@
 class PLATFORM_EXPORT RuntimeCallStats {
  public:
   RuntimeCallStats();
+  // Get RuntimeCallStats object associated with the given isolate.
+  static RuntimeCallStats* From(v8::Isolate*);
 
 // Counters
 #define FOR_EACH_COUNTER(V) \
diff --git a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h
index dbb2c0e..8af0f25 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h
+++ b/third_party/WebKit/Source/platform/bindings/V8PerIsolateData.h
@@ -31,6 +31,7 @@
 #include "gin/public/isolate_holder.h"
 #include "gin/public/v8_idle_task_runner.h"
 #include "platform/PlatformExport.h"
+#include "platform/bindings/RuntimeCallStats.h"
 #include "platform/bindings/ScopedPersistent.h"
 #include "platform/bindings/ScriptState.h"
 #include "platform/bindings/ScriptWrappableVisitor.h"
@@ -120,6 +121,8 @@
 
   StringCache* GetStringCache() { return string_cache_.get(); }
 
+  RuntimeCallStats* GetRuntimeCallStats() { return &runtime_call_stats_; }
+
   bool IsHandlingRecursionLevelError() const {
     return is_handling_recursion_level_error_;
   }
@@ -267,6 +270,8 @@
 
   Persistent<ActiveScriptWrappableSet> active_script_wrappables_;
   std::unique_ptr<ScriptWrappableVisitor> script_wrappable_visitor_;
+
+  RuntimeCallStats runtime_call_stats_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp
index f89ba935..a7fd314 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp
@@ -23,7 +23,7 @@
     canvas->scale(dest_rect.Width() / src_rect.Width(),
                   dest_rect.Height() / src_rect.Height());
   canvas->translate(-src_rect.X(), -src_rect.Y());
-  SkRect bounds = dest_rect;
+  SkRect bounds = SkRect::MakeWH(src_rect.Width(), src_rect.Height());
   canvas->saveLayer(&bounds, &flags);
   canvas->drawPicture(record_);
 }
diff --git a/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp b/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp
index 9328735..0870821 100644
--- a/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ContextMenuClientImpl.cpp
@@ -197,7 +197,7 @@
          !data.link_url.IsEmpty() ||
          data.media_type == WebContextMenuData::kMediaTypeImage ||
          data.media_type == WebContextMenuData::kMediaTypeVideo ||
-         data.is_editable;
+         data.is_editable || !data.selected_text.IsEmpty();
 }
 
 static HTMLFormElement* AssociatedFormElement(HTMLElement& element) {
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp
index 1f5cc5b..993a156 100644
--- a/third_party/WebKit/Source/web/WebKit.cpp
+++ b/third_party/WebKit/Source/web/WebKit.cpp
@@ -141,4 +141,10 @@
   WorkerBackingThread::SetRAILModeOnWorkerThreadIsolates(rail_mode);
 }
 
+void LogRuntimeCallStats() {
+  LOG(INFO)
+      << "\n"
+      << RuntimeCallStats::From(MainThreadIsolate())->ToString().Utf8().data();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 3dfa0a3..f2d32a8 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -840,9 +840,13 @@
         }
       }
 
-      event_result =
-          MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
-              targeted_event);
+      {
+        ContextMenuAllowedScope scope;
+        event_result =
+            MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
+                targeted_event);
+      }
+
       if (page_popup_ && last_hidden_page_popup_ &&
           page_popup_->HasSamePopupClient(last_hidden_page_popup_.Get())) {
         // The tap triggered a page popup that is the same as the one we just
diff --git a/third_party/WebKit/public/platform/UseCounterFeature.def b/third_party/WebKit/public/platform/UseCounterFeature.def
index 48c769e6..1d7f3d8 100644
--- a/third_party/WebKit/public/platform/UseCounterFeature.def
+++ b/third_party/WebKit/public/platform/UseCounterFeature.def
@@ -1550,6 +1550,7 @@
 
 kClientHintsDeviceRAM = 2017,
 kCSSRegisterProperty = 2018,
+kRelativeOrientationSensorConstructor = 2019,
 // Add new features immediately above this line. Don't change assigned
 // numbers of any item, and don't reuse removed slots.
 // Also, run update_use_counter_feature_enum.py in
diff --git a/third_party/WebKit/public/platform/WebPointerProperties.h b/third_party/WebKit/public/platform/WebPointerProperties.h
index 7af81c14..27453dcc0 100644
--- a/third_party/WebKit/public/platform/WebPointerProperties.h
+++ b/third_party/WebKit/public/platform/WebPointerProperties.h
@@ -29,7 +29,8 @@
     kRight,
     kBack,
     kForward,
-    kEraser
+    kEraser,
+    kLastEntry = kEraser  // Must be the last entry in the list
   };
 
   enum class Buttons : unsigned {
diff --git a/third_party/WebKit/public/web/WebKit.h b/third_party/WebKit/public/web/WebKit.h
index be86b32..95f4d32 100644
--- a/third_party/WebKit/public/web/WebKit.h
+++ b/third_party/WebKit/public/web/WebKit.h
@@ -75,6 +75,9 @@
 // Set the RAIL performance mode on all worker thread isolates.
 BLINK_EXPORT void SetRAILModeOnWorkerThreadIsolates(v8::RAILMode);
 
+// Logs Runtime Call Stats table for Blink.
+BLINK_EXPORT void LogRuntimeCallStats();
+
 }  // namespace blink
 
 #endif
diff --git a/third_party/WebKit/public/web/WebMenuSourceType.h b/third_party/WebKit/public/web/WebMenuSourceType.h
index ce2e78b..5d97c3f9 100644
--- a/third_party/WebKit/public/web/WebMenuSourceType.h
+++ b/third_party/WebKit/public/web/WebMenuSourceType.h
@@ -16,7 +16,8 @@
   kMenuSourceLongPress,
   kMenuSourceLongTap,
   kMenuSourceTouchHandle,
-  kMenuSourceTypeLast = kMenuSourceTouchHandle
+  kMenuSourceStylus,
+  kMenuSourceTypeLast = kMenuSourceStylus
 };
 
 }  // namespace blink
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 0b03d26..e806761 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -172,7 +172,6 @@
   write_buildflag_header_manually(root_gen_dir, 'base/debug/debugging_flags.h',
       {
           'ENABLE_PROFILING': 'false',
-          'ENABLE_MEMORY_TASK_PROFILER': 'false',
           'CAN_UNWIND_WITH_FRAME_POINTERS': 'false'
       })
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index c46ee61..87b3bf4 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -359,6 +359,16 @@
   <int value="3" label="Crashpad database init failed"/>
 </enum>
 
+<enum name="ActivityTrackerCollectOnCrashEvent" type="int">
+  <int value="0" label="Collection attempt"/>
+  <int value="1" label="User data directory not empty"/>
+  <int value="2" label="Path exists"/>
+  <int value="3" label="Report extraction success"/>
+  <int value="4" label="PMA set deleted failed"/>
+  <int value="5" label="Open for delete failed"/>
+  <int value="6" label="Success"/>
+</enum>
+
 <enum name="ActivityTrackerCollectStatus" type="int">
   <int value="0" label="None"/>
   <int value="1" label="Sucess"/>
@@ -370,7 +380,20 @@
   <int value="7" label="Finished writing crash report failed"/>
 </enum>
 
+<enum name="ActivityTrackerRecordEvent" type="int">
+  <int value="0" label="Recording attempt"/>
+  <int value="1" label="Stability directory exists"/>
+  <int value="2" label="Got stability file path"/>
+  <int value="3" label="Got tracker"/>
+  <int value="4" label="Mark deleted"/>
+  <int value="5" label="Mark deleted got file"/>
+  <int value="6" label="Open for delete failed"/>
+</enum>
+
 <enum name="ActivityTrackerRecordInitStatus" type="int">
+  <obsolete>
+    Removed from code May 2017.
+  </obsolete>
   <int value="0" label="Success"/>
   <int value="1" label="Create stability dir failed"/>
   <int value="2" label="Get stability file path failed"/>
@@ -3174,6 +3197,11 @@
   <int value="1" label="Translated"/>
 </enum>
 
+<enum name="BooleanUninstallable" type="int">
+  <int value="0" label="Not uninstallable"/>
+  <int value="1" label="Uninstallable"/>
+</enum>
+
 <enum name="BooleanUnknown" type="int">
   <int value="0" label="Known"/>
   <int value="1" label="Unknown"/>
@@ -15094,6 +15122,7 @@
   <int value="2016" label="TableSectionDirectionDifferentFromTable"/>
   <int value="2017" label="ClientHintsDeviceRAM"/>
   <int value="2018" label="CSSRegisterProperty"/>
+  <int value="2019" label="RelativeOrientationSensorConstructor"/>
 </enum>
 
 <enum name="FeedbackSource" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7a88302..ceeaeb1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -449,8 +449,20 @@
   </summary>
 </histogram>
 
+<histogram name="ActivityTracker.CollectCrash.Event"
+    enum="ActivityTrackerCollectOnCrashEvent">
+  <owner>manzagop@chromium.org</owner>
+  <summary>
+    Events that occur during crash collection of the debug file. Logged each
+    time an event of interest occurs during crash debug file collection.
+  </summary>
+</histogram>
+
 <histogram name="ActivityTracker.CollectCrash.OpenForDeleteSuccess"
     enum="BooleanSuccess">
+  <obsolete>
+    Deprecated 05/2017 in favor of ActivityTracker.CollectCrash.Event.
+  </obsolete>
   <owner>manzagop@chromium.org</owner>
   <summary>
     Success of the attempt to open the debug file for deletion. Logged each time
@@ -468,8 +480,20 @@
   </summary>
 </histogram>
 
+<histogram name="ActivityTracker.Record.Event"
+    enum="ActivityTrackerRecordEvent">
+  <owner>manzagop@chromium.org</owner>
+  <summary>
+    Events pertaining to recording to the debug file. Logged each time an event
+    of interest occurs wrt debug file recording.
+  </summary>
+</histogram>
+
 <histogram name="ActivityTracker.Record.InitStatus"
     enum="ActivityTrackerRecordInitStatus">
+  <obsolete>
+    Deprecated 05/2017 in favor of ActivityTracker.Record.Event.
+  </obsolete>
   <owner>manzagop@chromium.org</owner>
   <summary>
     Status of internal activity tracking initialization. Logged once, during the
@@ -76711,6 +76735,14 @@
   </summary>
 </histogram>
 
+<histogram name="ThirdPartyModules.Uninstallable" enum="BooleanUninstallable">
+  <owner>pmonette@chromium.org</owner>
+  <summary>
+    Records whether or not a loaded third party module could be uninstalled
+    using the Windows Apps &amp; Features page.
+  </summary>
+</histogram>
+
 <histogram name="ThreadWatcher.ResponseTime" units="ms">
   <owner>rch@chromium.org</owner>
   <summary>
diff --git a/ui/aura/client/cursor_client.h b/ui/aura/client/cursor_client.h
index 138e5e44..8a78c1a 100644
--- a/ui/aura/client/cursor_client.h
+++ b/ui/aura/client/cursor_client.h
@@ -61,6 +61,9 @@
   // Sets the display for the cursor.
   virtual void SetDisplay(const display::Display& display) = 0;
 
+  // Returns the display where the cursor is located.
+  virtual const display::Display& GetDisplay() const = 0;
+
   // Locks the cursor change. The cursor type, cursor visibility, and mouse
   // events enable state never change as long as lock is held by anyone.
   virtual void LockCursor() = 0;
diff --git a/ui/aura/client/cursor_client_observer.h b/ui/aura/client/cursor_client_observer.h
index c8408a2..7dc2031 100644
--- a/ui/aura/client/cursor_client_observer.h
+++ b/ui/aura/client/cursor_client_observer.h
@@ -8,6 +8,10 @@
 #include "ui/aura/aura_export.h"
 #include "ui/base/cursor/cursor.h"
 
+namespace display {
+class Display;
+}
+
 namespace aura {
 namespace client {
 
@@ -15,6 +19,7 @@
  public:
   virtual void OnCursorVisibilityChanged(bool is_visible) {}
   virtual void OnCursorSetChanged(ui::CursorSetType cursor_set) {}
+  virtual void OnCursorDisplayChanged(const display::Display& display) {}
 
  protected:
   virtual ~CursorClientObserver() {}
diff --git a/ui/aura/test/test_cursor_client.cc b/ui/aura/test/test_cursor_client.cc
index f54f92d..72f3a056 100644
--- a/ui/aura/test/test_cursor_client.cc
+++ b/ui/aura/test/test_cursor_client.cc
@@ -5,6 +5,7 @@
 #include "ui/aura/test/test_cursor_client.h"
 
 #include "ui/aura/client/cursor_client_observer.h"
+#include "ui/display/display.h"
 
 namespace aura {
 namespace test {
@@ -68,6 +69,11 @@
 
 void TestCursorClient::SetDisplay(const display::Display& display) {}
 
+const display::Display& TestCursorClient::GetDisplay() const {
+  static const display::Display display;
+  return display;
+}
+
 void TestCursorClient::LockCursor() {
   cursor_lock_count_++;
 }
diff --git a/ui/aura/test/test_cursor_client.h b/ui/aura/test/test_cursor_client.h
index 2b6f173..8b4e1d9 100644
--- a/ui/aura/test/test_cursor_client.h
+++ b/ui/aura/test/test_cursor_client.h
@@ -43,6 +43,7 @@
   void DisableMouseEvents() override;
   bool IsMouseEventsEnabled() const override;
   void SetDisplay(const display::Display& display) override;
+  const display::Display& GetDisplay() const override;
   void LockCursor() override;
   void UnlockCursor() override;
   bool IsCursorLocked() const override;
diff --git a/ui/base/ui_base_types.h b/ui/base/ui_base_types.h
index 7eaf0e0b..975a82d 100644
--- a/ui/base/ui_base_types.h
+++ b/ui/base/ui_base_types.h
@@ -49,7 +49,8 @@
   MENU_SOURCE_LONG_PRESS      = 5,
   MENU_SOURCE_LONG_TAP        = 6,
   MENU_SOURCE_TOUCH_HANDLE    = 7,
-  MENU_SOURCE_TYPE_LAST = MENU_SOURCE_TOUCH_HANDLE
+  MENU_SOURCE_STYLUS          = 8,
+  MENU_SOURCE_TYPE_LAST = MENU_SOURCE_STYLUS
 };
 
 UI_BASE_EXPORT MenuSourceType GetMenuSourceTypeForEvent(const ui::Event& event);
diff --git a/ui/login/account_picker/md_screen_account_picker.html b/ui/login/account_picker/md_screen_account_picker.html
index 191410d..b2f95a4 100644
--- a/ui/login/account_picker/md_screen_account_picker.html
+++ b/ui/login/account_picker/md_screen_account_picker.html
@@ -1,8 +1,7 @@
 <div id="account-picker" class="step faded hidden no-logo" hidden>
   <div id="signin-banner-container1">
     <div id="signin-banner-container2">
-      <div id="signin-banner"
-          i18n-content="signinBannerText"></div>
+      <div id="signin-banner">$i18n{signinBannerText}</div>
     </div>
   </div>
   <podrow id="pod-row" class="podrow images-loading"></podrow>
diff --git a/ui/login/account_picker/md_user_pod_template.html b/ui/login/account_picker/md_user_pod_template.html
index 5023323..0b69870 100644
--- a/ui/login/account_picker/md_user_pod_template.html
+++ b/ui/login/account_picker/md_user_pod_template.html
@@ -59,8 +59,8 @@
             <span class="action-box-menu-title-name"></span>
             <span class="action-box-menu-title-email"></span>
           </div>
-          <div class="action-box-menu-remove"
-              i18n-content="removeUserWarningButtonTitle">
+          <div class="action-box-menu-remove">
+            $i18n{removeUserWarningButtonTitle}
           </div>
           <div class="action-box-remove-user-warning" hidden>
             <div class="action-box-remove-user-warning-text"></div>
@@ -68,38 +68,45 @@
                           non-sync has-stats">
               <tbody>
                 <tr>
-                  <td i18n-content="removeUserWarningTextHistory"></td>
+                  <td>$i18n{removeUserWarningTextHistory}</td>
                   <td class="action-box-remove-user-warning-history
-                             action-box-remove-user-warning-table-numbers"
-                      i18n-content="removeUserWarningTextCalculating"></td>
+                             action-box-remove-user-warning-table-numbers">
+                    $i18n{removeUserWarningTextCalculating}
+                  </td>
                 </tr>
                 <tr>
-                  <td i18n-content="removeUserWarningTextPasswords"></td>
+                  <td>$i18n{removeUserWarningTextPasswords}</td>
                   <td class="action-box-remove-user-warning-passwords
-                             action-box-remove-user-warning-table-numbers"
-                      i18n-content="removeUserWarningTextCalculating"></td>
+                             action-box-remove-user-warning-table-numbers">
+                    $i18n{removeUserWarningTextCalculating}
+                  </td>
                 </tr>
                 <tr>
-                  <td i18n-content="removeUserWarningTextBookmarks"></td>
+                  <td>$i18n{removeUserWarningTextBookmarks}</td>
                   <td class="action-box-remove-user-warning-bookmarks
-                             action-box-remove-user-warning-table-numbers"
-                      i18n-content="removeUserWarningTextCalculating"></td>
+                             action-box-remove-user-warning-table-numbers">
+                    $i18n{removeUserWarningTextCalculating}
+                  </td>
                 </tr>
                 <tr>
-                  <td i18n-content="removeUserWarningTextSettings"></td>
+                  <td>$i18n{removeUserWarningTextSettings}</td>
                   <td class="action-box-remove-user-warning-settings
-                             action-box-remove-user-warning-table-numbers"
-                      i18n-content="removeUserWarningTextCalculating"></td>
+                             action-box-remove-user-warning-table-numbers">
+                    $i18n{removeUserWarningTextCalculating}
+                  </td>
                 </tr>
               </tbody>
             </table>
-            <div class="action-box-remove-legacy-supervised-user-warning-text"
-                i18n-content="removeLegacySupervisedUserWarningText"></div>
-            <div class="action-box-remove-non-owner-user-warning-text"
-                i18n-content="removeNonOwnerUserWarningText"></div>
+            <div class="action-box-remove-legacy-supervised-user-warning-text">
+              $i18n{removeLegacySupervisedUserWarningText}
+            </div>
+            <div class="action-box-remove-non-owner-user-warning-text">
+              $i18n{removeNonOwnerUserWarningText}
+            </div>
             <!-- paper-button is imported inside user_manager.html -->
-            <paper-button class="remove-warning-button"
-                i18n-content="removeUserWarningButtonTitle"></paper-button>
+            <paper-button class="remove-warning-button">
+              $i18n{removeUserWarningButtonTitle}
+            </paper-button>
           </div>
         </div>
       </div>
@@ -108,14 +115,14 @@
         <div class="custom-icon-container" hidden></div>
 <if expr="chromeos">
         <div class="fingerprint-icon-container" hidden
-             i18n-values="aria-label:fingerprintIconMessage">
+            aria-label="$i18n{fingerprintIconMessage}">
           <div class="custom-icon fingerprint-icon-image"></div>
         </div>
 </if>
         <div class="password-entry-container">
           <div class="password-container">
             <input type="password" class="password"
-                   i18n-values="placeholder:passwordHint">
+                placeholder="$i18n{passwordHint}">
           </div>
 <if expr="chromeos">
           <div class="capslock-hint-container">
@@ -131,7 +138,7 @@
         <!-- User Click Authentication -->
         <div class="password-label"></div>
         <div class="signin-transition-container">
-          <span class="signing-in-label" i18n-content="signingIn"></span>
+          <span class="signing-in-label">$i18n{signingIn}</span>
           <span class="animated-ellipsis-component0">.</span>
           <span class="animated-ellipsis-component1">.</span>
           <span class="animated-ellipsis-component2">.</span>
@@ -141,8 +148,7 @@
           <span class="reauth-name-hint"></span>
         </div>
         <div class="launch-app-button-container" hidden>
-          <button class="launch-app-button" i18n-content="launchAppButton">
-          </button>
+          <button class="launch-app-button">$i18n{launchAppButton}</button>
         </div>
         <div id="input-line">
           <svg>
@@ -158,16 +164,20 @@
     </div>
     <div class="user-type-bubble">
       <div class="user-type-bubble-header">
-        <span class="mp-policy-title"
-            i18n-content="multiProfilesRestrictedPolicyTitle"></span>
+        <span class="mp-policy-title">
+          $i18n{multiProfilesRestrictedPolicyTitle}
+        </span>
       </div>
       <div class="user-type-bubble-body">
-        <span class="mp-policy-not-allowed-msg"
-            i18n-content="multiProfilesNotAllowedPolicyMsg" hidden></span>
-        <span class="mp-policy-primary-only-msg"
-            i18n-content="multiProfilesPrimaryOnlyPolicyMsg" hidden></span>
-        <span class="mp-owner-primary-only-msg"
-            i18n-content="multiProfilesOwnerPrimaryOnlyMsg" hidden></span>
+        <span class="mp-policy-not-allowed-msg" hidden>
+          $i18n{multiProfilesNotAllowedPolicyMsg}
+        </span>
+        <span class="mp-policy-primary-only-msg" hidden>
+          $i18n{multiProfilesPrimaryOnlyPolicyMsg}
+        </span>
+        <span class="mp-owner-primary-only-msg" hidden>
+          $i18n{multiProfilesOwnerPrimaryOnlyMsg}
+        </span>
       </div>
     </div>
   </div>
@@ -193,24 +203,26 @@
           </div>
           <div class="info"></div>
           <div class="monitoring-container">
-            <span class="monitoring-warning"
-                  i18n-content="publicAccountMonitoringWarning"></span>
-            <a class="monitoring-learn-more" href="#" role="button"
-               i18n-content="publicAccountLearnMore"></a>
+            <span class="monitoring-warning">
+              $i18n{publicAccountMonitoringWarning}
+            </span>
+            <a class="monitoring-learn-more" href="#" role="button">
+              $i18n{publicAccountLearnMore}
+            </a>
           </div>
-          <div class="reminder" i18n-content="publicAccountReminder"></div>
+          <div class="reminder">$i18n{publicAccountReminder}</div>
           <div class="language-and-input-section">
             <div class="select-with-label">
-              <label class="language-select-label"
-                     i18n-content="publicSessionSelectLanguage">
+              <label class="language-select-label">
+                $i18n{publicSessionSelectLanguage}
               </label>
               <div class="select-container">
                 <select class="language-select"></select>
               </div>
             </div>
             <div class="select-with-label">
-              <label class="keyboard-select-label"
-                     i18n-content="publicSessionSelectKeyboard">
+              <label class="keyboard-select-label">
+                $i18n{publicSessionSelectKeyboard}
               </label>
               <div class="select-container">
                 <select class="keyboard-select"></select>
@@ -222,12 +234,13 @@
       <div class="horizontal-line"></div>
       <div class="bottom-container">
         <paper-button raised class="enter-button"
-                i18n-content="publicAccountEnter"
-                i18n-values="aria-label:publicAccountEnterAccessibleName">
+            aria-label="$i18n{publicAccountEnterAccessibleName}">
+          $i18n{publicAccountEnter}
         </paper-button>
         <div class="language-and-input-container">
-          <a class="language-and-input" href="#" role="button"
-             i18n-content="publicSessionLanguageAndInput"></a>
+          <a class="language-and-input" href="#" role="button">
+            $i18n{publicSessionLanguageAndInput}
+          </a>
         </div>
       </div>
     </div>
diff --git a/ui/login/account_picker/screen_account_picker.html b/ui/login/account_picker/screen_account_picker.html
index e8166b4..0d054476 100644
--- a/ui/login/account_picker/screen_account_picker.html
+++ b/ui/login/account_picker/screen_account_picker.html
@@ -1,8 +1,7 @@
 <div id="account-picker" class="step faded hidden no-logo" hidden>
   <div id="signin-banner-container1">
     <div id="signin-banner-container2">
-      <div id="signin-banner"
-          i18n-content="signinBannerText"></div>
+      <div id="signin-banner">$i18n{signinBannerText}</div>
     </div>
   </div>
   <podrow id="pod-row" class="podrow images-loading"></podrow>
diff --git a/ui/login/account_picker/user_pod_template.html b/ui/login/account_picker/user_pod_template.html
index 25948b4..97804ca0 100644
--- a/ui/login/account_picker/user_pod_template.html
+++ b/ui/login/account_picker/user_pod_template.html
@@ -24,7 +24,7 @@
     <div class="user-image-container">
       <img class="user-image" alt>
     </div>
-    <div class="signed-in-indicator" i18n-content="signedIn"></div>
+    <div class="signed-in-indicator">$i18n{signedIn}</div>
     <div class="indicator-container">
       <div class="indicator legacy-supervised-indicator"></div>
       <div class="indicator child-indicator"></div>
@@ -48,14 +48,14 @@
       <div class="custom-icon-container" hidden></div>
 <if expr="chromeos">
       <div class="fingerprint-icon-container" hidden
-           i18n-values="aria-label:fingerprintIconMessage">
+          aria-label="$i18n{fingerprintIconMessage}">
         <div class="custom-icon fingerprint-icon-image"></div>
       </div>
 </if>
       <div class="password-entry-container">
         <div class="password-container">
           <input type="password" class="password"
-                 i18n-values="placeholder:passwordHint">
+              placeholder="$i18n{passwordHint}">
         </div>
 <if expr="chromeos">
         <div class="capslock-hint-container">
@@ -63,15 +63,15 @@
                src="chrome://theme/IDR_LOGIN_PASSWORD_CAPS_LOCK" alt>
         </div>
         <paper-icon-button class="submit-button" disabled
-                           aria-label="$i18n{submitButtonAccessibleName}"
-                           icon="user-pod:arrow-forward" tabindex="-1">
+            aria-label="$i18n{submitButtonAccessibleName}"
+            icon="user-pod:arrow-forward" tabindex="-1">
         </paper-icon-button>
 </if>
       </div>
       <!-- User Click Authentication -->
       <div class="password-label"></div>
       <div class="signin-transition-container">
-        <span class="signing-in-label" i18n-content="signingIn"></span>
+        <span class="signing-in-label">$i18n{signingIn}</span>
         <span class="animated-ellipsis-component0">.</span>
         <span class="animated-ellipsis-component1">.</span>
         <span class="animated-ellipsis-component2">.</span>
@@ -81,8 +81,7 @@
         <span class="reauth-name-hint"></span>
       </div>
       <div class="launch-app-button-container" hidden>
-        <button class="launch-app-button" i18n-content="launchAppButton">
-        </button>
+        <button class="launch-app-button">$i18n{launchAppButton}</button>
       </div>
     </div>
   </div>
@@ -110,52 +109,63 @@
                     non-sync has-stats">
         <tbody>
           <tr>
-            <td i18n-content="removeUserWarningTextHistory"></td>
+            <td>$i18n{removeUserWarningTextHistory}</td>
             <td class="action-box-remove-user-warning-history
-                       action-box-remove-user-warning-table-numbers"
-                i18n-content="removeUserWarningTextCalculating"></td>
+                       action-box-remove-user-warning-table-numbers">
+              $i18n{removeUserWarningTextCalculating}
+            </td>
           </tr>
           <tr>
-            <td i18n-content="removeUserWarningTextPasswords"></td>
+            <td>$i18n{removeUserWarningTextPasswords}</td>
             <td class="action-box-remove-user-warning-passwords
-                       action-box-remove-user-warning-table-numbers"
-                i18n-content="removeUserWarningTextCalculating"></td>
+                       action-box-remove-user-warning-table-numbers">
+              $i18n{removeUserWarningTextCalculating}
+            </td>
           </tr>
           <tr>
-            <td i18n-content="removeUserWarningTextBookmarks"></td>
+            <td>$i18n{removeUserWarningTextBookmarks}</td>
             <td class="action-box-remove-user-warning-bookmarks
-                       action-box-remove-user-warning-table-numbers"
-                i18n-content="removeUserWarningTextCalculating"></td>
+                       action-box-remove-user-warning-table-numbers">
+              $i18n{removeUserWarningTextCalculating}
+            </td>
           </tr>
           <tr>
-            <td i18n-content="removeUserWarningTextSettings"></td>
+            <td>$i18n{removeUserWarningTextSettings}</td>
             <td class="action-box-remove-user-warning-settings
-                       action-box-remove-user-warning-table-numbers"
-                i18n-content="removeUserWarningTextCalculating"></td>
+                       action-box-remove-user-warning-table-numbers">
+              $i18n{removeUserWarningTextCalculating}
+            </td>
           </tr>
         </tbody>
       </table>
-      <div class="action-box-remove-legacy-supervised-user-warning-text"
-          i18n-content="removeLegacySupervisedUserWarningText"></div>
-      <div class="action-box-remove-non-owner-user-warning-text"
-          i18n-content="removeNonOwnerUserWarningText"></div>
+      <div class="action-box-remove-legacy-supervised-user-warning-text">
+        $i18n{removeLegacySupervisedUserWarningText}
+      </div>
+      <div class="action-box-remove-non-owner-user-warning-text">
+        $i18n{removeNonOwnerUserWarningText}
+      </div>
       <!-- paper-button is imported inside user_manager.html -->
-      <paper-button class="remove-warning-button"
-          i18n-content="removeUserWarningButtonTitle"></paper-button>
+      <paper-button class="remove-warning-button">
+        $i18n{removeUserWarningButtonTitle}
+      </paper-button>
     </div>
   </div>
   <div class="user-type-bubble">
     <div class="user-type-bubble-header">
-      <span class="mp-policy-title"
-          i18n-content="multiProfilesRestrictedPolicyTitle"></span>
+      <span class="mp-policy-title">
+        $i18n{multiProfilesRestrictedPolicyTitle}
+      </span>
     </div>
     <div class="user-type-bubble-body">
-      <span class="mp-policy-not-allowed-msg"
-          i18n-content="multiProfilesNotAllowedPolicyMsg" hidden></span>
-      <span class="mp-policy-primary-only-msg"
-          i18n-content="multiProfilesPrimaryOnlyPolicyMsg" hidden></span>
-      <span class="mp-owner-primary-only-msg"
-          i18n-content="multiProfilesOwnerPrimaryOnlyMsg" hidden></span>
+      <span class="mp-policy-not-allowed-msg" hidden>
+        $i18n{multiProfilesNotAllowedPolicyMsg}
+      </span>
+      <span class="mp-policy-primary-only-msg" hidden>
+        $i18n{multiProfilesPrimaryOnlyPolicyMsg}
+      </span>
+      <span class="mp-owner-primary-only-msg" hidden>
+        $i18n{multiProfilesOwnerPrimaryOnlyMsg}
+      </span>
     </div>
   </div>
 </div>
@@ -174,24 +184,26 @@
           </div>
           <div class="info"></div>
           <div class="monitoring-container">
-            <span class="monitoring-warning"
-                  i18n-content="publicAccountMonitoringWarning"></span>
-            <a class="monitoring-learn-more" href="#" role="button"
-               i18n-content="publicAccountLearnMore"></a>
+            <span class="monitoring-warning">
+              $i18n{publicAccountMonitoringWarning}
+            </span>
+            <a class="monitoring-learn-more" href="#" role="button">
+              $i18n{publicAccountLearnMore}
+            </a>
           </div>
-          <div class="reminder" i18n-content="publicAccountReminder"></div>
+          <div class="reminder">$i18n{publicAccountReminder}</div>
           <div class="language-and-input-section">
             <div class="select-with-label">
-              <label class="language-select-label"
-                     i18n-content="publicSessionSelectLanguage">
+              <label class="language-select-label">
+                $i18n{publicSessionSelectLanguage}
               </label>
               <div class="select-container">
                 <select class="language-select"></select>
               </div>
             </div>
             <div class="select-with-label">
-              <label class="keyboard-select-label"
-                     i18n-content="publicSessionSelectKeyboard">
+              <label class="keyboard-select-label">
+                $i18n{publicSessionSelectKeyboard}
               </label>
               <div class="select-container">
                 <select class="keyboard-select"></select>
@@ -203,12 +215,13 @@
       <div class="horizontal-line"></div>
       <div class="bottom-container">
         <paper-button raised class="enter-button"
-                i18n-content="publicAccountEnter"
-                i18n-values="aria-label:publicAccountEnterAccessibleName">
+            aria-label="$i18n{publicAccountEnterAccessibleName}">
+          $i18n{publicAccountEnter}
         </paper-button>
         <div class="language-and-input-container">
-          <a class="language-and-input" href="#" role="button"
-             i18n-content="publicSessionLanguageAndInput"></a>
+          <a class="language-and-input" href="#" role="button">
+            $i18n{publicSessionLanguageAndInput}
+          </a>
         </div>
       </div>
     </div>
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 0758776..4a2cb6a1 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -144,8 +144,6 @@
     "controls/focus_ring.h",
     "controls/focusable_border.cc",
     "controls/focusable_border.h",
-    "controls/focusable_rounded_border_mac.cc",
-    "controls/focusable_rounded_border_mac.h",
     "controls/glow_hover_controller.cc",
     "controls/glow_hover_controller.h",
     "controls/image_view.cc",
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc
index 460517a1..32773d2 100644
--- a/ui/views/controls/button/md_text_button.cc
+++ b/ui/views/controls/button/md_text_button.cc
@@ -286,6 +286,7 @@
   set_background(Background::CreateBackgroundPainter(
       Painter::CreateRoundRectWith1PxBorderPainter(bg_color, stroke_color,
                                                    kInkDropSmallCornerRadius)));
+  SchedulePaint();
 }
 
 }  // namespace views
diff --git a/ui/views/controls/focusable_rounded_border_mac.cc b/ui/views/controls/focusable_rounded_border_mac.cc
deleted file mode 100644
index ba19855..0000000
--- a/ui/views/controls/focusable_rounded_border_mac.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/controls/focusable_rounded_border_mac.h"
-
-#include "ui/gfx/canvas.h"
-#include "ui/native_theme/native_theme_mac.h"
-
-namespace {
-
-const int kThickness = 1;
-
-}  // namespace
-
-namespace views {
-
-FocusableRoundedBorder::FocusableRoundedBorder() {
-  // TODO(ellyjones): These insets seem like they shouldn't be big enough, but
-  // they are, and insetting by corner_radius_ instead produces gargantuan
-  // padding. Why is that?
-  SetInsets(kThickness, kThickness, kThickness, kThickness);
-}
-
-FocusableRoundedBorder::~FocusableRoundedBorder() {}
-
-// For now, this is similar to RoundedRectBorder::Paint(), but this method will
-// likely diverge in future.
-// TODO(ellyjones): Diverge it by adding soft focus rings.
-void FocusableRoundedBorder::Paint(const View& view, gfx::Canvas* canvas) {
-  cc::PaintFlags flags;
-  flags.setStyle(cc::PaintFlags::kStroke_Style);
-  flags.setStrokeWidth(kThickness);
-  flags.setColor(GetCurrentColor(view));
-  flags.setAntiAlias(true);
-
-  float half_thickness = kThickness / 2.0f;
-  gfx::RectF bounds(view.GetLocalBounds());
-  bounds.Inset(half_thickness, half_thickness);
-  canvas->DrawRoundRect(bounds, ui::NativeThemeMac::kButtonCornerRadius, flags);
-}
-
-}  // namespace views
diff --git a/ui/views/controls/focusable_rounded_border_mac.h b/ui/views/controls/focusable_rounded_border_mac.h
deleted file mode 100644
index 1821cd4..0000000
--- a/ui/views/controls/focusable_rounded_border_mac.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_CONTROLS_FOCUSABLE_ROUNDED_BORDER_H_
-#define UI_VIEWS_CONTROLS_FOCUSABLE_ROUNDED_BORDER_H_
-
-#include "base/macros.h"
-#include "ui/views/controls/focusable_border.h"
-#include "ui/views/view.h"
-
-namespace views {
-
-// A Border that changes colors in accordance with the system color scheme when
-// the View it borders is focused.
-class FocusableRoundedBorder : public FocusableBorder {
- public:
-  FocusableRoundedBorder();
-  ~FocusableRoundedBorder() override;
-
-  // Border:
-  void Paint(const View& view, gfx::Canvas* canvas) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FocusableRoundedBorder);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_CONTROLS_FOCUSABLE_ROUNDED_BORDER_H_
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn
index f36dedf..3053d67 100644
--- a/ui/views/examples/BUILD.gn
+++ b/ui/views/examples/BUILD.gn
@@ -75,6 +75,7 @@
 
   deps = [
     "//base",
+    "//cc/paint",
     "//skia",
     "//third_party/icu",
     "//ui/base",
diff --git a/ui/views/examples/scroll_view_example.cc b/ui/views/examples/scroll_view_example.cc
index ce11e7b..39ffd8fb 100644
--- a/ui/views/examples/scroll_view_example.cc
+++ b/ui/views/examples/scroll_view_example.cc
@@ -7,12 +7,14 @@
 #include "base/macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "cc/paint/paint_flags.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/gfx/skia_paint_util.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/radio_button.h"
 #include "ui/views/layout/grid_layout.h"
-#include "ui/views/painter.h"
 #include "ui/views/view.h"
 
 using base::ASCIIToUTF16;
@@ -30,16 +32,9 @@
     AddChildView(new RadioButton(ASCIIToUTF16("Radio Button"), 0));
   }
 
-  gfx::Size CalculatePreferredSize() const override {
-    return gfx::Size(width(), height());
-  }
-
   void SetColor(SkColor from, SkColor to) {
-    Background* background = Background::CreateBackgroundPainter(
-        Painter::CreateVerticalGradient(from, to));
-    background->SetNativeControlColor(
-        color_utils::AlphaBlend(from, to, 128));
-    set_background(background);
+    from_color_ = from;
+    to_color_ = to;
   }
 
   void PlaceChildY(int index, int y) {
@@ -48,13 +43,29 @@
     view->SetBounds(0, y, size.width(), size.height());
   }
 
+  // View
   void Layout() override {
     PlaceChildY(0, 0);
     PlaceChildY(1, height() / 2);
     SizeToPreferredSize();
   }
 
+  void OnPaintBackground(gfx::Canvas* canvas) override {
+    cc::PaintFlags flags;
+    flags.setShader(
+        gfx::CreateGradientShader(0, height(), from_color_, to_color_));
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    canvas->DrawRect(GetLocalBounds(), flags);
+  }
+
+  gfx::Size CalculatePreferredSize() const override {
+    return gfx::Size(width(), height());
+  }
+
  private:
+  SkColor from_color_;
+  SkColor to_color_;
+
   DISALLOW_COPY_AND_ASSIGN(ScrollableView);
 };
 
diff --git a/ui/views/painter.cc b/ui/views/painter.cc
index 4c4e69f2..d9b9aee1 100644
--- a/ui/views/painter.cc
+++ b/ui/views/painter.cc
@@ -4,25 +4,13 @@
 
 #include "ui/views/painter.h"
 
-#include <memory>
-
 #include "base/logging.h"
-#include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "cc/paint/paint_shader.h"
-#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "third_party/skia/include/pathops/SkPathOps.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/insets_f.h"
-#include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/nine_image_painter.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/views/view.h"
@@ -154,71 +142,6 @@
   canvas->DrawSolidFocusRect(rect, color_, thickness_);
 }
 
-// GradientPainter ------------------------------------------------------------
-
-class GradientPainter : public Painter {
- public:
-  GradientPainter(bool horizontal,
-                  SkColor* colors,
-                  SkScalar* pos,
-                  size_t count);
-  ~GradientPainter() override;
-
-  // Painter:
-  gfx::Size GetMinimumSize() const override;
-  void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
-
- private:
-  // If |horizontal_| is true then the gradient is painted horizontally.
-  bool horizontal_;
-  // The gradient colors.
-  std::unique_ptr<SkColor[]> colors_;
-  // The relative positions of the corresponding gradient colors.
-  std::unique_ptr<SkScalar[]> pos_;
-  // The number of elements in |colors_| and |pos_|.
-  size_t count_;
-
-  DISALLOW_COPY_AND_ASSIGN(GradientPainter);
-};
-
-GradientPainter::GradientPainter(bool horizontal,
-                                 SkColor* colors,
-                                 SkScalar* pos,
-                                 size_t count)
-    : horizontal_(horizontal),
-      colors_(new SkColor[count]),
-      pos_(new SkScalar[count]),
-      count_(count) {
-  for (size_t i = 0; i < count_; ++i) {
-    pos_[i] = pos[i];
-    colors_[i] = colors[i];
-  }
-}
-
-GradientPainter::~GradientPainter() {
-}
-
-gfx::Size GradientPainter::GetMinimumSize() const {
-  return gfx::Size();
-}
-
-void GradientPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
-  cc::PaintFlags flags;
-  SkPoint p[2];
-  p[0].iset(0, 0);
-  if (horizontal_)
-    p[1].iset(size.width(), 0);
-  else
-    p[1].iset(0, size.height());
-
-  flags.setShader(cc::WrapSkShader(SkGradientShader::MakeLinear(
-      p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode)));
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-
-  canvas->sk_canvas()->drawRect(SkRect::MakeIWH(size.width(), size.height()),
-                                flags);
-}
-
 // ImagePainter ---------------------------------------------------------------
 
 // ImagePainter stores and paints nine images as a scalable grid.
@@ -311,16 +234,6 @@
 }
 
 // static
-std::unique_ptr<Painter> Painter::CreateVerticalGradient(SkColor c1,
-                                                         SkColor c2) {
-  SkColor colors[2];
-  colors[0] = c1;
-  colors[1] = c2;
-  SkScalar pos[] = {0, 1};
-  return base::MakeUnique<GradientPainter>(false, colors, pos, 2);
-}
-
-// static
 std::unique_ptr<Painter> Painter::CreateImagePainter(
     const gfx::ImageSkia& image,
     const gfx::Insets& insets) {
@@ -364,36 +277,4 @@
   return base::MakeUnique<SolidFocusPainter>(color, thickness, insets);
 }
 
-// HorizontalPainter ----------------------------------------------------------
-
-HorizontalPainter::HorizontalPainter(const int image_resource_names[]) {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  for (int i = 0; i < 3; ++i)
-    images_[i] = rb.GetImageNamed(image_resource_names[i]).ToImageSkia();
-  DCHECK_EQ(images_[LEFT]->height(), images_[CENTER]->height());
-  DCHECK_EQ(images_[LEFT]->height(), images_[RIGHT]->height());
-}
-
-HorizontalPainter::~HorizontalPainter() {
-}
-
-gfx::Size HorizontalPainter::GetMinimumSize() const {
-  return gfx::Size(
-      images_[LEFT]->width() + images_[CENTER]->width() +
-          images_[RIGHT]->width(), images_[LEFT]->height());
-}
-
-void HorizontalPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
-  if (size.width() < GetMinimumSize().width())
-    return;  // No room to paint.
-
-  canvas->DrawImageInt(*images_[LEFT], 0, 0);
-  canvas->DrawImageInt(*images_[RIGHT], size.width() - images_[RIGHT]->width(),
-                       0);
-  canvas->TileImageInt(
-      *images_[CENTER], images_[LEFT]->width(), 0,
-      size.width() - images_[LEFT]->width() - images_[RIGHT]->width(),
-      images_[LEFT]->height());
-}
-
 }  // namespace views
diff --git a/ui/views/painter.h b/ui/views/painter.h
index 5757336..57b4fb0a 100644
--- a/ui/views/painter.h
+++ b/ui/views/painter.h
@@ -60,10 +60,6 @@
       SkColor stroke_color,
       float radius);
 
-  // TODO(estade): remove. The last client (table_header.cc) is going away soon.
-  static std::unique_ptr<Painter> CreateVerticalGradient(SkColor c1,
-                                                         SkColor c2);
-
   // Creates a painter that divides |image| into nine regions. The four corners
   // are rendered at the size specified in insets (eg. the upper-left corner is
   // rendered at 0 x 0 with a size of insets.left() x insets.top()). The center
@@ -104,35 +100,6 @@
   DISALLOW_COPY_AND_ASSIGN(Painter);
 };
 
-// HorizontalPainter paints 3 images into a box: left, center and right. The
-// left and right images are drawn to size at the left/right edges of the
-// region. The center is tiled in the remaining space. All images must have the
-// same height.
-class VIEWS_EXPORT HorizontalPainter : public Painter {
- public:
-  // Constructs a new HorizontalPainter loading the specified image names.
-  // The images must be in the order left, right and center.
-  explicit HorizontalPainter(const int image_resource_names[]);
-  ~HorizontalPainter() override;
-
-  // Painter:
-  gfx::Size GetMinimumSize() const override;
-  void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
-
- private:
-  // The image chunks.
-  enum BorderElements {
-    LEFT,
-    CENTER,
-    RIGHT
-  };
-
-  // NOTE: the images are owned by ResourceBundle. Don't free them.
-  const gfx::ImageSkia* images_[3];
-
-  DISALLOW_COPY_AND_ASSIGN(HorizontalPainter);
-};
-
 }  // namespace views
 
 #endif  // UI_VIEWS_PAINTER_H_
diff --git a/ui/webui/resources/js/i18n_behavior.js b/ui/webui/resources/js/i18n_behavior.js
index 05c9cf6..95722a1 100644
--- a/ui/webui/resources/js/i18n_behavior.js
+++ b/ui/webui/resources/js/i18n_behavior.js
@@ -4,17 +4,23 @@
 
 /**
  * @fileoverview
- * 'I18nBehavior' is a behavior to mix in loading of
- * internationalization strings.
- *
- * Example:
- *   behaviors: [
- *     I18nBehavior,
- *   ],
+ * 'I18nBehavior' is a behavior to mix in loading of internationalization
+ * strings.
  */
 
 /** @polymerBehavior */
 var I18nBehavior = {
+  properties: {
+    /**
+     * The language the UI is presented in. Used to signal dynamic language
+     * change.
+     */
+    locale: {
+      type: String,
+      value: '',
+    },
+  },
+
   /**
    * Returns a translated string where $1 to $9 are replaced by the given
    * values.
@@ -60,6 +66,19 @@
   },
 
   /**
+   * Similar to 'i18n', with an unused |locale| parameter used to trigger
+   * updates when |this.locale| changes.
+   * @param {string} locale The UI language used.
+   * @param {string} id The ID of the string to translate.
+   * @param {...string} var_args Values to replace the placeholders $1 to $9
+   *     in the string.
+   * @return {string} A translated, sanitized, substituted string.
+   */
+  i18nDynamic: function(locale, id, var_args) {
+    return this.i18n.apply(this, Array.prototype.slice.call(arguments, 1));
+  },
+
+  /**
    * Returns true if a translation exists for |id|.
    * @param {string} id
    * @return {boolean}
@@ -67,6 +86,14 @@
   i18nExists: function(id) {
     return loadTimeData.valueExists(id);
   },
+
+  /**
+   * Call this when UI strings may have changed. This will send an update to any
+   * data bindings to i18nDynamic(locale, ...).
+   */
+  i18nUpdateLocale: function() {
+    this.locale = loadTimeData.getString('language');
+  },
 };
 
 /**
diff --git a/ui/wm/core/cursor_manager.cc b/ui/wm/core/cursor_manager.cc
index a411b78..839a22e 100644
--- a/ui/wm/core/cursor_manager.cc
+++ b/ui/wm/core/cursor_manager.cc
@@ -165,9 +165,17 @@
 }
 
 void CursorManager::SetDisplay(const display::Display& display) {
+  display_ = display;
+  for (auto& observer : observers_)
+    observer.OnCursorDisplayChanged(display);
+
   delegate_->SetDisplay(display, this);
 }
 
+const display::Display& CursorManager::GetDisplay() const {
+  return display_;
+}
+
 void CursorManager::LockCursor() {
   cursor_lock_count_++;
 }
diff --git a/ui/wm/core/cursor_manager.h b/ui/wm/core/cursor_manager.h
index cce4f83..003d874 100644
--- a/ui/wm/core/cursor_manager.h
+++ b/ui/wm/core/cursor_manager.h
@@ -12,6 +12,7 @@
 #include "base/observer_list.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/base/cursor/cursor.h"
+#include "ui/display/display.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/wm/core/native_cursor_manager_delegate.h"
@@ -54,6 +55,7 @@
   void DisableMouseEvents() override;
   bool IsMouseEventsEnabled() const override;
   void SetDisplay(const display::Display& display) override;
+  const display::Display& GetDisplay() const override;
   void LockCursor() override;
   void UnlockCursor() override;
   bool IsCursorLocked() const override;
@@ -70,6 +72,9 @@
 
   std::unique_ptr<NativeCursorManager> delegate_;
 
+  // Display where the cursor is located.
+  display::Display display_;
+
   // Number of times LockCursor() has been invoked without a corresponding
   // UnlockCursor().
   int cursor_lock_count_;