diff --git a/DEPS b/DEPS
index 1ad950f..985b494 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': 'db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9',
+  'skia_revision': '79a3aafc34c1a1b561f9fbb415b12cb1ff4772dd',
   # 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': 'ec37390b2ba2b4051f46f153a8cc179ed4656f5d',
+  'v8_revision': '17f4706e3823954a661ad9823c2e988d22d556b5',
   # 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': '5b2092a1ec59077b430bd2cab91554cad2eb5128',
+  'pdfium_revision': 'f2ca50ffa2d26a6c023add24e92adbe6b28bfcc9',
   # 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.
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 5697dc1b..5f83f690 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -48,33 +48,18 @@
 namespace android_webview {
 namespace {
 
-class AwAccessTokenStore : public device::AccessTokenStore {
- public:
-  AwAccessTokenStore() { }
-
-  // device::AccessTokenStore implementation
-  void LoadAccessTokens(const LoadAccessTokensCallback& request) override {
-    AccessTokenStore::AccessTokenMap access_token_map;
-    // AccessTokenMap and net::URLRequestContextGetter not used on Android,
-    // but Run needs to be called to finish the geolocation setup.
-    request.Run(access_token_map, NULL);
-  }
-  void SaveAccessToken(const GURL& server_url,
-                       const base::string16& access_token) override {}
-
- private:
-  ~AwAccessTokenStore() override {}
-
-  DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore);
-};
-
 // A provider of Geolocation services to override AccessTokenStore.
 class AwGeolocationDelegate : public device::GeolocationDelegate {
  public:
   AwGeolocationDelegate() = default;
 
+  // Android doesn't use NetworkLocationProvider (the capability is folded into
+  // the system location provider).
+  bool UseNetworkLocationProviders() override { return false; }
+
   scoped_refptr<device::AccessTokenStore> CreateAccessTokenStore() final {
-    return new AwAccessTokenStore();
+    NOTREACHED() << "No network geolocation for Android webview";
+    return nullptr;
   }
 
  private:
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 5e7c7b97..ae37466 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -319,8 +319,11 @@
         Voice input
       </message>
 
+      <message name="IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_TITLE" desc="The title used for locale change notifications in the system tray.">
+        Language has been changed
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_MESSAGE" desc="The message used for locale change notifications in the system tray.">
-        The language has changed from "<ph name="FROM_LOCALE">$1<ex>Italian</ex></ph>" to "<ph name="TO_LOCALE">$2<ex>English (United States)</ex></ph>" after syncing your settings.
+        From "<ph name="FROM_LOCALE">$1<ex>Italian</ex></ph>" to "<ph name="TO_LOCALE">$2<ex>English (United States)</ex></ph>" after syncing your settings.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_LOCALE_REVERT_MESSAGE" desc="Link to revert a change.">
         Change back to "<ph name="FROM_LOCALE">$1<ex>Italian</ex></ph>" (requires restart)
diff --git a/ash/system/locale/locale_notification_controller.cc b/ash/system/locale/locale_notification_controller.cc
index 83e11fb4f..4512408 100644
--- a/ash/system/locale/locale_notification_controller.cc
+++ b/ash/system/locale/locale_notification_controller.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/resources/grit/ash_resources.h"
+#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/system_notifier.h"
 #include "ash/system/tray/system_tray_notifier.h"
@@ -110,16 +111,20 @@
   optional.never_timeout = true;
 
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  std::unique_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE, kLocaleChangeNotificationId,
-      base::string16() /* title */,
-      l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_MESSAGE,
-                                 from, to),
-      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_LOCALE),
-      base::string16() /* display_source */, GURL(),
-      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
-                                 system_notifier::kNotifierLocale),
-      optional, new LocaleNotificationDelegate(std::move(callback))));
+  std::unique_ptr<Notification> notification =
+      system_notifier::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kLocaleChangeNotificationId,
+          l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_TITLE),
+          l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_MESSAGE,
+                                     from, to),
+          bundle.GetImageNamed(IDR_AURA_UBER_TRAY_LOCALE),
+          base::string16() /* display_source */, GURL(),
+          message_center::NotifierId(
+              message_center::NotifierId::SYSTEM_COMPONENT,
+              system_notifier::kNotifierLocale),
+          optional, new LocaleNotificationDelegate(std::move(callback)),
+          kNotificationSettingsIcon,
+          message_center::SystemNotificationWarningLevel::NORMAL);
   message_center::MessageCenter::Get()->AddNotification(
       std::move(notification));
 }
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index db283e2..48b5b286 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -47,8 +47,12 @@
 // Indicates whether |network| belongs to this VPN provider.
 bool VpnProviderMatchesNetwork(const VPNProvider& provider,
                                const chromeos::NetworkState& network) {
+  // Never display non-VPN networks or ARC VPNs.
   if (network.type() != shill::kTypeVPN)
     return false;
+  if (network.vpn_provider_type() == shill::kProviderArcVpn)
+    return false;
+
   const bool network_uses_third_party_provider =
       network.vpn_provider_type() == shill::kProviderThirdPartyVpn;
   if (!provider.third_party)
@@ -338,6 +342,19 @@
   std::vector<VPNProvider> providers =
       Shell::Get()->vpn_list()->vpn_providers();
 
+  // Add connected ARCVPN networks. These are not normally displayed in
+  // the menu because the OS connects and disconnects them in response
+  // to events from ARC. They will never be matched in
+  // VpnProviderMatchesNetwork(), and they will not be "nested" under a
+  // provider view.
+  for (const chromeos::NetworkState* const& network : networks) {
+    if (network->vpn_provider_type() == shill::kProviderArcVpn &&
+        (network->IsConnectedState() || network->IsConnectedState())) {
+      AddNetwork(network);
+      list_empty_ = false;
+    }
+  }
+
   // Add providers with at least one configured network along with their
   // networks. Providers are added in the order of their highest priority
   // network.
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index e31ce7e8..7410f28 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -173,6 +173,10 @@
     return window_selector_controller()->window_selector_.get();
   }
 
+  SplitViewController* split_view_controller() {
+    return Shell::Get()->split_view_controller();
+  }
+
   void ToggleOverview() { window_selector_controller()->ToggleOverview(); }
 
   aura::Window* GetOverviewWindowForMinimizedState(int index,
@@ -333,6 +337,14 @@
     return window_selector()->text_filter_widget_.get();
   }
 
+  gfx::Rect GetSplitViewLeftWindowBounds(aura::Window* window) {
+    return split_view_controller()->GetLeftWindowBoundsInScreen(window);
+  }
+
+  gfx::Rect GetSplitViewRightWindowBounds(aura::Window* window) {
+    return split_view_controller()->GetRightWindowBoundsInScreen(window);
+  }
+
   gfx::Rect GetGridBounds() {
     if (window_selector())
       return window_selector()->grid_list_[0]->bounds_;
@@ -1917,47 +1929,14 @@
   resizer->RevertDrag();
 }
 
-class SplitViewWindowSelectorTest : public WindowSelectorTest {
- public:
-  SplitViewWindowSelectorTest() = default;
-  ~SplitViewWindowSelectorTest() override = default;
-
-  void SetUp() override {
-    WindowSelectorTest::SetUp();
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kAshEnableTabletSplitView);
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-  }
-
-  void TearDown() override {
-    // TODO(sammiequon|xdai): There is a memory leak if we tear down while
-    // overview mode is active. Investigate.
-    if (window_selector_controller()->IsSelecting())
-      ToggleOverview();
-    WindowSelectorTest::TearDown();
-  }
-
-  SplitViewController* split_view_controller() {
-    return Shell::Get()->split_view_controller();
-  }
-
- protected:
-  gfx::Rect GetSplitViewLeftWindowBounds(aura::Window* window) {
-    return split_view_controller()->GetLeftWindowBoundsInScreen(window);
-  }
-
-  gfx::Rect GetSplitViewRightWindowBounds(aura::Window* window) {
-    return split_view_controller()->GetRightWindowBoundsInScreen(window);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SplitViewWindowSelectorTest);
-};
-
 // Tests that dragging a overview window selector item to the edge of the screen
 // snaps the window. If two windows are snapped to left and right side of the
 // screen, exit the overview mode.
-TEST_F(SplitViewWindowSelectorTest, DragOverviewWindowToSnap) {
+TEST_F(WindowSelectorTest, DragOverviewWindowToSnap) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
@@ -1965,7 +1944,7 @@
 
   ToggleOverview();
   EXPECT_TRUE(window_selector_controller()->IsSelecting());
-  EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
+  EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false);
 
   // Drag |window1| selector item to snap to left.
   const int grid_index = 0;
@@ -1979,7 +1958,7 @@
   window_selector()->Drag(selector_item1, end_location1);
   window_selector()->CompleteDrag(selector_item1);
 
-  EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive());
+  EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true);
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::LEFT_SNAPPED);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
@@ -2020,8 +1999,13 @@
 
 // Verify the window grid size changes as expected when dragging items around in
 // overview mode when split view is enabled.
-TEST_F(SplitViewWindowSelectorTest, WindowGridSizeWhileDraggingWithSplitView) {
-  // Add three windows and enter overview mode.
+TEST_F(WindowSelectorTest, WindowGridSizeWhileDraggingWithSplitView) {
+  // Enable split view, enter maximize mode, add some windows and enter overview
+  // mode.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
@@ -2085,10 +2069,18 @@
   EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds());
   window_selector()->Drag(selector_item, center);
   EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds());
+
+  ToggleOverview();
 }
 
 // Tests dragging a unsnappable window.
-TEST_F(SplitViewWindowSelectorTest, DraggingNonSnapableAppWithSplitView) {
+TEST_F(WindowSelectorTest, DraggingNonSnapableAppWithSplitView) {
+  // Enable split view, enter maximize mode, add a unsnappable window and enter
+  // overview mode.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> unsnappable_window(CreateWindow(bounds));
   unsnappable_window->SetProperty(aura::client::kResizeBehaviorKey,
@@ -2119,12 +2111,17 @@
   window_selector()->Drag(selector_item,
                           gfx::Point(root_window_bounds.right() / 2, 0));
   EXPECT_EQ(expected_grid_bounds, GetGridBounds());
+
+  ToggleOverview();
 }
 
 // Tests that if there is only one window in the MRU window list in the overview
 // mode, snapping the window to one side of the screen will end the overview
 // mode since there is no more window left in the overview window grid.
-TEST_F(SplitViewWindowSelectorTest, EmptyWindowsListExitOverview) {
+TEST_F(WindowSelectorTest, EmptyWindowsListExitOverview) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
 
@@ -2150,7 +2147,11 @@
 }
 
 // Verify that the split view overview overlay is shown when expected.
-TEST_F(SplitViewWindowSelectorTest, SplitViewOverviewOverlayVisibility) {
+TEST_F(WindowSelectorTest, SplitViewOverviewOverlayVisibility) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
@@ -2186,7 +2187,11 @@
 
 // Verify that the split view overview overlays widget reparents when starting a
 // drag on a different display.
-TEST_F(SplitViewWindowSelectorTest, SplitViewOverviewOverlayWidgetReparenting) {
+TEST_F(WindowSelectorTest, SplitViewOverviewOverlayWidgetReparenting) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableTabletSplitView);
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+
   // Add two displays and one window on each display.
   UpdateDisplay("600x600,600x600");
   auto root_windows = Shell::Get()->GetAllRootWindows();
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 6ac22f88..d2f8a63 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -22,7 +22,7 @@
 
 class SplitViewControllerTest;
 class SplitViewDivider;
-class SplitViewWindowSelectorTest;
+class WindowSelectorTest;
 
 // The controller for the split view. It snaps a window to left/right side of
 // the screen. It also observes the two snapped windows and decides when to exit
@@ -107,7 +107,7 @@
 
  private:
   friend class SplitViewControllerTest;
-  friend class SplitViewWindowSelectorTest;
+  friend class WindowSelectorTest;
 
   // Ends the split view mode.
   void EndSplitView();
diff --git a/ash/wm/splitview/split_view_overview_overlay.h b/ash/wm/splitview/split_view_overview_overlay.h
index beaaa86..f4f0965c 100644
--- a/ash/wm/splitview/split_view_overview_overlay.h
+++ b/ash/wm/splitview/split_view_overview_overlay.h
@@ -32,7 +32,7 @@
   bool visible() const;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(SplitViewWindowSelectorTest,
+  FRIEND_TEST_ALL_PREFIXES(WindowSelectorTest,
                            SplitViewOverviewOverlayWidgetReparenting);
   class SplitViewOverviewOverlayView;
 
diff --git a/base/debug/activity_tracker.h b/base/debug/activity_tracker.h
index fb4ac8b..10a2650 100644
--- a/base/debug/activity_tracker.h
+++ b/base/debug/activity_tracker.h
@@ -664,8 +664,7 @@
   ActivityId PushActivity(const void* origin,
                           Activity::Type type,
                           const ActivityData& data) {
-    return PushActivity(::tracked_objects::GetProgramCounter(), origin, type,
-                        data);
+    return PushActivity(GetProgramCounter(), origin, type, data);
   }
 
   // Changes the activity |type| and |data| of the top-most entry on the stack.
@@ -1024,8 +1023,7 @@
   // Record exception information for the current thread.
   ALWAYS_INLINE
   void RecordException(const void* origin, uint32_t code) {
-    return RecordExceptionImpl(::tracked_objects::GetProgramCounter(), origin,
-                               code);
+    return RecordExceptionImpl(GetProgramCounter(), origin, code);
   }
   void RecordException(const void* pc, const void* origin, uint32_t code);
 
@@ -1179,31 +1177,31 @@
   const int64_t process_id_;
 
   // The activity tracker for the currently executing thread.
-  base::ThreadLocalStorage::Slot this_thread_tracker_;
+  ThreadLocalStorage::Slot this_thread_tracker_;
 
   // The number of thread trackers currently active.
   std::atomic<int> thread_tracker_count_;
 
   // A caching memory allocator for thread-tracker objects.
   ActivityTrackerMemoryAllocator thread_tracker_allocator_;
-  base::Lock thread_tracker_allocator_lock_;
+  Lock thread_tracker_allocator_lock_;
 
   // A caching memory allocator for user data attached to activity data.
   ActivityTrackerMemoryAllocator user_data_allocator_;
-  base::Lock user_data_allocator_lock_;
+  Lock user_data_allocator_lock_;
 
   // An object for holding arbitrary key value pairs with thread-safe access.
   ThreadSafeUserData process_data_;
 
   // A map of global module information, keyed by module path.
   std::map<const std::string, ModuleInfoRecord*> modules_;
-  base::Lock modules_lock_;
+  Lock modules_lock_;
 
   // The active global activity tracker.
   static subtle::AtomicWord g_tracker_;
 
   // A lock that is used to protect access to the following fields.
-  base::Lock global_tracker_lock_;
+  Lock global_tracker_lock_;
 
   // The collection of processes being tracked and their command-lines.
   std::map<int64_t, std::string> known_processes_;
@@ -1242,10 +1240,7 @@
   //   }
   ALWAYS_INLINE
   ScopedActivity(uint8_t action, uint32_t id, int32_t info)
-      : ScopedActivity(::tracked_objects::GetProgramCounter(),
-                       action,
-                       id,
-                       info) {}
+      : ScopedActivity(GetProgramCounter(), action, id, info) {}
   ScopedActivity() : ScopedActivity(0, 0, 0) {}
 
   // Changes the |action| and/or |info| of this activity on the stack. This
@@ -1278,13 +1273,11 @@
     : public GlobalActivityTracker::ScopedThreadActivity {
  public:
   ALWAYS_INLINE
-  explicit ScopedTaskRunActivity(const base::PendingTask& task)
-      : ScopedTaskRunActivity(::tracked_objects::GetProgramCounter(),
-                              task) {}
+  explicit ScopedTaskRunActivity(const PendingTask& task)
+      : ScopedTaskRunActivity(GetProgramCounter(), task) {}
 
  private:
-  ScopedTaskRunActivity(const void* program_counter,
-                        const base::PendingTask& task);
+  ScopedTaskRunActivity(const void* program_counter, const PendingTask& task);
   DISALLOW_COPY_AND_ASSIGN(ScopedTaskRunActivity);
 };
 
@@ -1293,8 +1286,7 @@
  public:
   ALWAYS_INLINE
   explicit ScopedLockAcquireActivity(const base::internal::LockImpl* lock)
-      : ScopedLockAcquireActivity(::tracked_objects::GetProgramCounter(),
-                                  lock) {}
+      : ScopedLockAcquireActivity(GetProgramCounter(), lock) {}
 
  private:
   ScopedLockAcquireActivity(const void* program_counter,
@@ -1306,13 +1298,12 @@
     : public GlobalActivityTracker::ScopedThreadActivity {
  public:
   ALWAYS_INLINE
-  explicit ScopedEventWaitActivity(const base::WaitableEvent* event)
-      : ScopedEventWaitActivity(::tracked_objects::GetProgramCounter(),
-                                event) {}
+  explicit ScopedEventWaitActivity(const WaitableEvent* event)
+      : ScopedEventWaitActivity(GetProgramCounter(), event) {}
 
  private:
   ScopedEventWaitActivity(const void* program_counter,
-                          const base::WaitableEvent* event);
+                          const WaitableEvent* event);
   DISALLOW_COPY_AND_ASSIGN(ScopedEventWaitActivity);
 };
 
@@ -1320,13 +1311,12 @@
     : public GlobalActivityTracker::ScopedThreadActivity {
  public:
   ALWAYS_INLINE
-  explicit ScopedThreadJoinActivity(const base::PlatformThreadHandle* thread)
-      : ScopedThreadJoinActivity(::tracked_objects::GetProgramCounter(),
-                                 thread) {}
+  explicit ScopedThreadJoinActivity(const PlatformThreadHandle* thread)
+      : ScopedThreadJoinActivity(GetProgramCounter(), thread) {}
 
  private:
   ScopedThreadJoinActivity(const void* program_counter,
-                           const base::PlatformThreadHandle* thread);
+                           const PlatformThreadHandle* thread);
   DISALLOW_COPY_AND_ASSIGN(ScopedThreadJoinActivity);
 };
 
@@ -1336,13 +1326,12 @@
     : public GlobalActivityTracker::ScopedThreadActivity {
  public:
   ALWAYS_INLINE
-  explicit ScopedProcessWaitActivity(const base::Process* process)
-      : ScopedProcessWaitActivity(::tracked_objects::GetProgramCounter(),
-                                  process) {}
+  explicit ScopedProcessWaitActivity(const Process* process)
+      : ScopedProcessWaitActivity(GetProgramCounter(), process) {}
 
  private:
   ScopedProcessWaitActivity(const void* program_counter,
-                            const base::Process* process);
+                            const Process* process);
   DISALLOW_COPY_AND_ASSIGN(ScopedProcessWaitActivity);
 };
 #endif
diff --git a/base/location.h b/base/location.h
index 5337792a..59b46b7 100644
--- a/base/location.h
+++ b/base/location.h
@@ -123,15 +123,6 @@
 
 }  // namespace base
 
-namespace tracked_objects {
-
-// TODO(http://crbug.com/763556): Convert all uses of Location and
-// GetProgramCounter to use the base namespace and remove these lines.
-using ::base::Location;
-using ::base::GetProgramCounter;
-
-}  // namespace tracked_objects
-
 namespace std {
 
 // Specialization for using Location in hash tables.
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index f5e2e13..43d08fc 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -331,7 +331,10 @@
 
 // Enable the core dump providers.
 #if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
-  RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
+  base::trace_event::MemoryDumpProvider::Options options;
+  options.supports_heap_profiling = true;
+  RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr,
+                       options);
 #endif
 
 #if defined(OS_ANDROID)
@@ -849,13 +852,8 @@
     scoped_refptr<MemoryDumpProviderInfo> mdpinfo,
     bool enabled) {
   lock_.AssertAcquired();
-
-  // If we do not have ability to request global dumps, then a dump cannot be in
-  // progress. So, the notification can be sent on any thread. This is done not
-  // to create thread early during startup since sandbox initialization that
-  // happens later requires no thread to be created.
-  if (!can_request_global_dumps())
-    return mdpinfo->dump_provider->OnHeapProfilingEnabled(enabled);
+  if (!mdpinfo->options.supports_heap_profiling)
+    return;
 
   const auto& task_runner = mdpinfo->task_runner
                                 ? mdpinfo->task_runner
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index bbeba6a..86874a5 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -840,7 +840,10 @@
   InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
   MockMemoryDumpProvider mdp1;
   MockMemoryDumpProvider mdp2;
-  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
+  MockMemoryDumpProvider mdp3;
+  MemoryDumpProvider::Options supported_options;
+  supported_options.supports_heap_profiling = true;
+  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), supported_options);
   {
     testing::InSequence sequence;
     EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(1);
@@ -851,6 +854,8 @@
     EXPECT_CALL(mdp2, OnHeapProfilingEnabled(true)).Times(1);
     EXPECT_CALL(mdp2, OnHeapProfilingEnabled(false)).Times(1);
   }
+  RegisterDumpProvider(&mdp3, ThreadTaskRunnerHandle::Get());
+  EXPECT_CALL(mdp3, OnHeapProfilingEnabled(_)).Times(0);
 
   EXPECT_TRUE(mdm_->EnableHeapProfiling(kHeapProfilingModePseudo));
   RunLoop().RunUntilIdle();
@@ -858,7 +863,7 @@
             AllocationContextTracker::capture_mode());
   EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModePseudo);
   EXPECT_EQ(TraceLog::FILTERING_MODE, TraceLog::GetInstance()->enabled_modes());
-  RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
+  RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), supported_options);
 
   TraceConfig::MemoryDumpConfig config;
   config.heap_profiler_options.breakdown_threshold_bytes = 100;
@@ -891,7 +896,9 @@
 TEST_F(MemoryDumpManagerTest, EnableHeapProfilingNoStack) {
   InitializeMemoryDumpManagerForInProcessTesting(true /* is_coordinator */);
   MockMemoryDumpProvider mdp1;
-  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
+  MemoryDumpProvider::Options supported_options;
+  supported_options.supports_heap_profiling = true;
+  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), supported_options);
   testing::InSequence sequence;
   EXPECT_CALL(mdp1, OnHeapProfilingEnabled(true)).Times(1);
   EXPECT_CALL(mdp1, OnHeapProfilingEnabled(false)).Times(1);
@@ -939,7 +946,9 @@
   InitializeMemoryDumpManagerForInProcessTesting(true /* is_coordinator */);
   MockMemoryDumpProvider mdp1;
   MockMemoryDumpProvider mdp2;
-  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
+  MemoryDumpProvider::Options supported_options;
+  supported_options.supports_heap_profiling = true;
+  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), supported_options);
   EXPECT_CALL(mdp1, OnHeapProfilingEnabled(_)).Times(0);
   EXPECT_CALL(mdp2, OnHeapProfilingEnabled(_)).Times(0);
 
@@ -948,7 +957,7 @@
   RunLoop().RunUntilIdle();
   ASSERT_EQ(AllocationContextTracker::CaptureMode::DISABLED,
             AllocationContextTracker::capture_mode());
-  RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
+  RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), supported_options);
   EXPECT_EQ(mdm_->GetHeapProfilingMode(), kHeapProfilingModeTaskProfiler);
   ASSERT_TRUE(debug::ThreadHeapUsageTracker::IsHeapTrackingEnabled());
   TestingThreadHeapUsageTracker::DisableHeapTrackingForTesting();
@@ -966,7 +975,9 @@
 TEST_F(MemoryDumpManagerTest, EnableHeapProfilingIfNeeded) {
   InitializeMemoryDumpManagerForInProcessTesting(false /* is_coordinator */);
   MockMemoryDumpProvider mdp1;
-  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
+  MemoryDumpProvider::Options supported_options;
+  supported_options.supports_heap_profiling = true;
+  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), supported_options);
 
   // Should be noop.
   mdm_->EnableHeapProfilingIfNeeded();
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index ff1ee19..1f656b1 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -22,7 +22,8 @@
   struct Options {
     Options()
         : dumps_on_single_thread_task_runner(false),
-          is_fast_polling_supported(false) {}
+          is_fast_polling_supported(false),
+          supports_heap_profiling(false) {}
 
     // |dumps_on_single_thread_task_runner| is true if the dump provider runs on
     // a SingleThreadTaskRunner, which is usually the case. It is faster to run
@@ -33,6 +34,10 @@
     // polling. Only providers running without task runner affinity are
     // supported.
     bool is_fast_polling_supported;
+
+    // Set to true when the dump provider supports heap profiling. MDM sends
+    // OnHeapProfiling() notifications only if this is set to true.
+    bool supports_heap_profiling;
   };
 
   virtual ~MemoryDumpProvider() {}
@@ -48,9 +53,8 @@
                             ProcessMemoryDump* pmd) = 0;
 
   // Called by the MemoryDumpManager when an allocator should start or stop
-  // collecting extensive allocation data, if supported. Can be called on any
-  // thread and MDM guarantees OnMemoryDump() and OnHeapProfilingEnabled() are
-  // not called at the same time.
+  // collecting extensive allocation data, if supported. Called only when
+  // |supports_heap_profiling| is set to true.
   virtual void OnHeapProfilingEnabled(bool enabled) {}
 
   // Quickly record the total memory usage in |memory_total|. This method will
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index d9d7df2..f0938ad 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -455,11 +455,9 @@
 }
 
 //------------------------------------------------------------------------------
-BirthOnThread::BirthOnThread(const Location& location,
+BirthOnThread::BirthOnThread(const base::Location& location,
                              const ThreadData& current)
-    : location_(location),
-      birth_thread_(&current) {
-}
+    : location_(location), birth_thread_(&current) {}
 
 //------------------------------------------------------------------------------
 BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
@@ -473,9 +471,8 @@
 }
 
 //------------------------------------------------------------------------------
-Births::Births(const Location& location, const ThreadData& current)
-    : BirthOnThread(location, current),
-      birth_count_(1) { }
+Births::Births(const base::Location& location, const ThreadData& current)
+    : BirthOnThread(location, current), birth_count_(1) {}
 
 int Births::birth_count() const { return birth_count_; }
 
@@ -665,7 +662,7 @@
   }
 }
 
-Births* ThreadData::TallyABirth(const Location& location) {
+Births* ThreadData::TallyABirth(const base::Location& location) {
   BirthMap::iterator it = birth_map_.find(location);
   Births* child;
   if (it != birth_map_.end()) {
@@ -721,7 +718,7 @@
 }
 
 // static
-Births* ThreadData::TallyABirthIfActive(const Location& location) {
+Births* ThreadData::TallyABirthIfActive(const base::Location& location) {
   if (!TrackingStatus())
     return NULL;
   ThreadData* current_thread_data = Get();
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index b0966795..405aa604 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -203,16 +203,16 @@
 class ThreadData;
 class BASE_EXPORT BirthOnThread {
  public:
-  BirthOnThread(const Location& location, const ThreadData& current);
+  BirthOnThread(const base::Location& location, const ThreadData& current);
 
-  const Location& location() const { return location_; }
+  const base::Location& location() const { return location_; }
   const ThreadData* birth_thread() const { return birth_thread_; }
 
  private:
   // File/lineno of birth.  This defines the essence of the task, as the context
   // of the birth (construction) often tell what the item is for.  This field
   // is const, and hence safe to access from any thread.
-  const Location location_;
+  const base::Location location_;
 
   // The thread that records births into this object.  Only this thread is
   // allowed to update birth_count_ (which changes over time).
@@ -238,7 +238,7 @@
 
 class BASE_EXPORT Births: public BirthOnThread {
  public:
-  Births(const Location& location, const ThreadData& current);
+  Births(const base::Location& location, const ThreadData& current);
 
   int birth_count() const;
 
@@ -549,7 +549,7 @@
     STATUS_LAST = PROFILING_ACTIVE
   };
 
-  typedef std::unordered_map<Location, Births*> BirthMap;
+  typedef std::unordered_map<base::Location, Births*> BirthMap;
   typedef std::map<const Births*, DeathData> DeathMap;
 
   // Initialize the current thread context with a new instance of ThreadData.
@@ -583,7 +583,7 @@
   // Finds (or creates) a place to count births from the given location in this
   // thread, and increment that tally.
   // TallyABirthIfActive will returns NULL if the birth cannot be tallied.
-  static Births* TallyABirthIfActive(const Location& location);
+  static Births* TallyABirthIfActive(const base::Location& location);
 
   // Record the end of a timed run of an object.  The |birth| is the record for
   // the instance, the |time_posted| records that instant, which is presumed to
@@ -669,7 +669,7 @@
 
 
   // In this thread's data, record a new birth.
-  Births* TallyABirth(const Location& location);
+  Births* TallyABirth(const base::Location& location);
 
   // Find a place to record a death on this thread.
   void TallyADeath(const Births& births,
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
index 044f231..8d39211b 100644
--- a/base/tracked_objects_unittest.cc
+++ b/base/tracked_objects_unittest.cc
@@ -60,7 +60,8 @@
 
   // Simulate a birth on the thread named |thread_name|, at the given
   // |location|.
-  void TallyABirth(const Location& location, const std::string& thread_name) {
+  void TallyABirth(const base::Location& location,
+                   const std::string& thread_name) {
     // If the |thread_name| is empty, we don't initialize system with a thread
     // name, so we're viewed as a worker thread.
     if (!thread_name.empty())
@@ -476,7 +477,7 @@
   ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
 
   const char kFunction[] = "DeactivatedBirthOnlyToSnapshotWorkerThread";
-  Location location(kFunction, kFile, kLineNumber, &kLineNumber);
+  base::Location location(kFunction, kFile, kLineNumber, &kLineNumber);
   TallyABirth(location, std::string());
 
   ProcessDataSnapshot process_data;
@@ -498,7 +499,7 @@
   ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
 
   const char kFunction[] = "DeactivatedBirthOnlyToSnapshotMainThread";
-  Location location(kFunction, kFile, kLineNumber, &kLineNumber);
+  base::Location location(kFunction, kFile, kLineNumber, &kLineNumber);
   TallyABirth(location, kMainThreadName);
 
   ProcessDataSnapshot process_data;
@@ -519,7 +520,7 @@
   ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
 
   const char kFunction[] = "BirthOnlyToSnapshotWorkerThread";
-  Location location(kFunction, kFile, kLineNumber, &kLineNumber);
+  base::Location location(kFunction, kFile, kLineNumber, &kLineNumber);
   TallyABirth(location, std::string());
 
   ProcessDataSnapshot process_data;
@@ -532,7 +533,7 @@
   ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
 
   const char kFunction[] = "BirthOnlyToSnapshotMainThread";
-  Location location(kFunction, kFile, kLineNumber, &kLineNumber);
+  base::Location location(kFunction, kFile, kLineNumber, &kLineNumber);
   TallyABirth(location, kMainThreadName);
 
   ProcessDataSnapshot process_data;
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
index d8f480f5..c1e4597 100644
--- a/base/win/scoped_handle.h
+++ b/base/win/scoped_handle.h
@@ -73,7 +73,7 @@
       if (Traits::IsHandleValid(handle)) {
         handle_ = handle;
         Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
-                                tracked_objects::GetProgramCounter());
+                                GetProgramCounter());
       }
       ::SetLastError(last_error);
     }
@@ -89,7 +89,7 @@
     handle_ = Traits::NullHandle();
     if (Traits::IsHandleValid(temp)) {
       Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
-                             tracked_objects::GetProgramCounter());
+                             GetProgramCounter());
     }
     return temp;
   }
@@ -98,7 +98,7 @@
   void Close() {
     if (Traits::IsHandleValid(handle_)) {
       Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
-                             tracked_objects::GetProgramCounter());
+                             GetProgramCounter());
 
       Traits::CloseHandle(handle_);
       handle_ = Traits::NullHandle();
diff --git a/build/android/pylib/symbols/deobfuscator.py b/build/android/pylib/symbols/deobfuscator.py
index c3f0980..2342be68 100644
--- a/build/android/pylib/symbols/deobfuscator.py
+++ b/build/android/pylib/symbols/deobfuscator.py
@@ -118,6 +118,9 @@
 
 
 class DeobfuscatorPool(object):
+  # As of Sep 2017, each instance requires about 500MB of RAM, as measured by:
+  # /usr/bin/time -v out/Release/bin/java_deobfuscate \
+  #     out/Release/apks/ChromePublic.apk.mapping
   def __init__(self, mapping_path, pool_size=4):
     self._mapping_path = mapping_path
     self._pool = [Deobfuscator(mapping_path) for _ in xrange(pool_size)]
diff --git a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
index a828cb8..07d986c 100644
--- a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
+++ b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
@@ -20,25 +20,59 @@
  *  2. Disables output buffering
  */
 public class FlushingReTrace {
-    // This regex is based on the one from:
-    // http://proguard.sourceforge.net/manual/retrace/usage.html.
-    // But with the "at" part changed to "(?::|\bat)", to account for lines like:
-    //     06-22 13:58:02.895  4674  4674 E THREAD_STATE:     bLA.a(PG:173)
-    // And .*=%c\s* added as the second subpattern to account for lines like:
-    //     INSTRUMENTATION_STATUS: class=bNs
-    // Normal stack trace lines look like:
-    // java.lang.RuntimeException: Intentional Java Crash
-    //     at org.chromium.chrome.browser.tab.Tab.handleJavaCrash(Tab.java:682)
-    //     at org.chromium.chrome.browser.tab.Tab.loadUrl(Tab.java:644)
+    // E.g.: D/ConnectivityService(18029): Message
+    // E.g.: W/GCM     (15158): Message
+    // E.g.: 09-08 14:22:59.995 18029 18055 I ProcessStatsService: Message
+    // E.g.: 09-08 14:30:59.145 17731 18020 D MDnsDS  : Message
+    private static final String LOGCAT_PREFIX =
+            "(?:[VDIWEF]/.*?\\(\\d+\\): |\\d\\d-\\d\\d [0-9:. ]+[VDIWEF] .*?: )?";
+
+    // Note: Order of these sub-patterns defines their precedence.
+    // Note: Deobfuscation of methods without the presense of line numbers basically never works.
+    // There is a test for these pattern at //build/android/stacktrace/java_deobfuscate_test.py
     private static final String LINE_PARSE_REGEX =
-            "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*)|"
-            + "(?:.*=%c\\s*)|"
-            + "(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)";
+            // Eagerly match logcat prefix to avoid conflicting with the patterns below.
+            LOGCAT_PREFIX
+            + "(?:"
+            // Based on default ReTrace regex, but with "at" changed to to allow :
+            // E.g.: 06-22 13:58:02.895  4674  4674 E THREAD_STATE:     bLA.a(PG:173)
+            // Normal stack trace lines look like:
+            // \tat org.chromium.chrome.browser.tab.Tab.handleJavaCrash(Tab.java:682)
+            + "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(%s(?::%l)?\\))|"
+            // E.g.: VFY: unable to resolve new-instance 3810 (LSome/Framework/Class;) in Lfoo/Bar;
+            + "(?:.*L%C;.*)|"
+            // E.g.: END SomeTestClass#someMethod
+            + "(?:.*?%c#%m.*?)|"
+            // E.g.: The member "Foo.bar"
+            // E.g.: The class "Foobar"
+            + "(?:.*?\"%c\\.%m\".*)|"
+            + "(?:.*?\"%c\".*)|"
+            // E.g.: java.lang.RuntimeException: Intentional Java Crash
+            + "(?:%c:.*)|"
+            // All lines that end with a class / class+method:
+            // E.g.: The class: Foo
+            // E.g.: INSTRUMENTATION_STATUS: class=Foo
+            // E.g.: NoClassDefFoundError: SomeFrameworkClass in isTestClass for Foo
+            // E.g.: Could not find class 'SomeFrameworkClass', referenced from method Foo.bar
+            // E.g.: Could not find method SomeFrameworkMethod, referenced from method Foo.bar
+            + "(?:.*(?:=|:\\s*|\\s+)%c\\.%m)|"
+            + "(?:.*(?:=|:\\s*|\\s+)%c)"
+            + ")";
+
+    private static void usage() {
+        System.err.println("Usage: echo $OBFUSCATED_CLASS | java_deobfuscate Foo.apk.mapping");
+        System.err.println("Usage: java_deobfuscate Foo.apk.mapping < foo.log");
+        System.err.println("Note: Deobfuscation of symbols outside the context of stack "
+                + "traces will work only when lines match the regular expression defined "
+                + "in FlushingReTrace.java.");
+        System.err.println("Also: Deobfuscation of method names without associated line "
+                + "numbers does not seem to work.");
+        System.exit(1);
+    }
 
     public static void main(String[] args) {
-        if (args.length != 1) {
-            System.err.println("Usage: java_deobfuscate Foo.apk.map < foo.log > bar.log");
-            System.exit(1);
+        if (args.length != 1 || args[0].startsWith("-")) {
+            usage();
         }
 
         File mappingFile = new File(args[0]);
diff --git a/build/android/stacktrace/java_deobfuscate_test.py b/build/android/stacktrace/java_deobfuscate_test.py
new file mode 100755
index 0000000..356b377
--- /dev/null
+++ b/build/android/stacktrace/java_deobfuscate_test.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# 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.
+"""Tests for java_deobfuscate."""
+
+import argparse
+import subprocess
+import sys
+import tempfile
+
+
+LINE_PREFIXES = [
+    '',
+    # logcat -v threadtime
+    '09-08 14:38:35.535 18029 18084 E qcom_sensors_hal: ',
+    # logcat
+    'W/GCM     (15158): ',
+]
+
+TEST_MAP = """\
+this.was.Deobfuscated -> FOO:
+    int[] FontFamily -> a
+    1:3:void someMethod(int,android.os.Bundle):65:65 -> bar
+"""
+
+TEST_DATA = """\
+Here is a FOO
+Here is a FOO baz
+Here is a "FOO" baz
+Here is a "FOO.bar" baz
+Here it is: FOO
+Here it is: FOO.bar
+Here is a FOO.bar
+Here is a FOO.bar baz
+END FOO#bar
+new-instance 3810 (LSome/Framework/Class;) in LFOO;
+FOO: Error message
+\tat FOO.bar(PG:1)
+""".splitlines(True)
+
+EXPECTED_OUTPUT = """\
+Here is a this.was.Deobfuscated
+Here is a FOO baz
+Here is a "this.was.Deobfuscated" baz
+Here is a "this.was.Deobfuscated.someMethod" baz
+Here it is: this.was.Deobfuscated
+Here it is: this.was.Deobfuscated.someMethod
+Here is a this.was.Deobfuscated.someMethod
+Here is a FOO.bar baz
+END this.was.Deobfuscated#someMethod
+new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated;
+this.was.Deobfuscated: Error message
+\tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65)
+""".splitlines(True)
+
+
+def _RunTest(bin_path, map_file, prefix):
+  cmd = [bin_path, map_file]
+  payload = TEST_DATA
+  expected_output = EXPECTED_OUTPUT
+
+  payload = [prefix + x for x in payload]
+  expected_output = [prefix + x for x in expected_output]
+
+  proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+  actual_output = proc.communicate(''.join(payload))[0].splitlines(True)
+  any_unexpected_failures = False
+  for actual, expected in zip(actual_output, expected_output):
+    if actual == expected:
+      sys.stdout.write('Good: ' + actual)
+    elif actual.replace('bar', 'someMethod') == expected:
+      # TODO(agrieve): Fix ReTrace's ability to deobfuscated methods.
+      sys.stdout.write('Fine: ' + actual)
+    else:
+      sys.stdout.write('BAD:  ' + actual)
+      any_unexpected_failures = True
+  return not any_unexpected_failures
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('path_to_java_deobfuscate')
+  args = parser.parse_args()
+
+  with tempfile.NamedTemporaryFile() as map_file:
+    map_file.write(TEST_MAP)
+    map_file.flush()
+    passed = True
+    for prefix in LINE_PREFIXES:
+      if not _RunTest(args.path_to_java_deobfuscate, map_file.name, prefix):
+        passed = False
+  print 'Result:', 'PASS' if passed else 'FAIL'
+  sys.exit(int(not passed))
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/mac_toolchain.py b/build/mac_toolchain.py
index 16c9c37..d456251 100755
--- a/build/mac_toolchain.py
+++ b/build/mac_toolchain.py
@@ -11,6 +11,9 @@
   * Accepts the license.
     * If xcode-select and xcodebuild are not passwordless in sudoers, requires
       user interaction.
+
+The toolchain version can be overridden by setting IOS_TOOLCHAIN_REVISION or
+MAC_TOOLCHAIN_REVISION with the full revision, e.g. 9A235-1.
 """
 
 from distutils.version import LooseVersion
@@ -34,7 +37,7 @@
 # 16 is the major version number for macOS 10.12.
 MAC_MINIMUM_OS_VERSION = 16
 
-IOS_TOOLCHAIN_VERSION = '9M214v'
+IOS_TOOLCHAIN_VERSION = '9A235'
 IOS_TOOLCHAIN_SUB_REVISION = 1
 IOS_TOOLCHAIN_VERSION = '%s-%s' % (IOS_TOOLCHAIN_VERSION,
                                    IOS_TOOLCHAIN_SUB_REVISION)
@@ -211,14 +214,11 @@
   sys.exit(1)
 
 
-def DownloadHermeticBuild(target_os, default_version, toolchain_filename):
+def DownloadHermeticBuild(target_os, toolchain_version, toolchain_filename):
   if not _UseHermeticToolchain(target_os):
     print 'Using local toolchain for %s.' % target_os
     return 0
 
-  toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
-                                      default_version)
-
   if ReadStampFile(target_os) == toolchain_version:
     print 'Toolchain (%s) is already up to date.' % toolchain_version
     FinalizeUnpack(target_os)
@@ -261,14 +261,16 @@
       continue
 
     if target_os == 'ios':
-      default_version = IOS_TOOLCHAIN_VERSION
+      toolchain_version = os.environ.get('IOS_TOOLCHAIN_REVISION',
+                                          IOS_TOOLCHAIN_VERSION)
       toolchain_filename = 'ios-toolchain-%s.tgz'
     else:
-      default_version = MAC_TOOLCHAIN_VERSION
+      toolchain_version = os.environ.get('MAC_TOOLCHAIN_REVISION',
+                                          MAC_TOOLCHAIN_VERSION)
       toolchain_filename = 'toolchain-%s.tgz'
 
     return_value = DownloadHermeticBuild(
-        target_os, default_version, toolchain_filename)
+        target_os, toolchain_version, toolchain_filename)
     if return_value:
       return return_value
 
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
index 26712cd..05d9f83 100644
--- a/cc/blink/web_display_item_list_impl.cc
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -202,4 +202,8 @@
   display_item_list_->EndPaintOfPairedEnd();
 }
 
+cc::DisplayItemList* WebDisplayItemListImpl::GetCcDisplayItemList() {
+  return display_item_list_.get();
+}
+
 }  // namespace cc_blink
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
index c8da1b5..4346d9e 100644
--- a/cc/blink/web_display_item_list_impl.h
+++ b/cc/blink/web_display_item_list_impl.h
@@ -65,6 +65,7 @@
   void AppendScrollItem(const blink::WebSize& scrollOffset,
                         ScrollContainerId) override;
   void AppendEndScrollItem() override;
+  cc::DisplayItemList* GetCcDisplayItemList() override;
 
  private:
   void AppendRestore();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index c4b120c4..86d05b6 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2016,7 +2016,9 @@
   // Adjust the viewport layers by shrinking/expanding the container to account
   // for changes in the size (e.g. browser controls) since the last resize from
   // Blink.
-  gfx::Vector2dF amount_to_expand(0.f, delta_from_top_controls);
+  gfx::Vector2dF amount_to_expand(
+      0.f,
+      delta_from_top_controls * active_tree_->painted_device_scale_factor());
   inner_container->SetViewportBoundsDelta(amount_to_expand);
 
   if (outer_container && !outer_container->BoundsForScrolling().IsEmpty()) {
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 05ed957..a25d09d 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -5092,6 +5092,40 @@
   ASSERT_EQ(0, host_impl_->active_tree()->CurrentBrowserControlsShownRatio());
 }
 
+TEST_F(LayerTreeHostImplBrowserControlsTest, ViewportBoundsUseZoomForDSF) {
+  SetupBrowserControlsAndScrollLayerWithVirtualViewport(
+      gfx::Size(50, 50), gfx::Size(100, 100), gfx::Size(100, 100));
+  DrawFrame();
+
+  LayerImpl* inner_container =
+      host_impl_->active_tree()->InnerViewportContainerLayer();
+
+  gfx::Vector2dF scroll_delta(0.f, 10.f);
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+            host_impl_
+                ->ScrollBegin(BeginState(gfx::Point()).get(),
+                              InputHandler::TOUCHSCREEN)
+                .thread);
+  host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
+
+  gfx::Vector2dF bounds_delta = inner_container->ViewportBoundsDelta();
+  host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f);
+  host_impl_->ScrollEnd(EndState().get());
+
+  float device_scale = 3.5f;
+  host_impl_->active_tree()->set_painted_device_scale_factor(device_scale);
+
+  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+            host_impl_
+                ->ScrollBegin(BeginState(gfx::Point()).get(),
+                              InputHandler::TOUCHSCREEN)
+                .thread);
+  host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get());
+
+  bounds_delta.Scale(device_scale);
+  EXPECT_EQ(bounds_delta, inner_container->ViewportBoundsDelta());
+}
+
 // Test that if only the browser controls are scrolled, we shouldn't request a
 // commit.
 TEST_F(LayerTreeHostImplBrowserControlsTest, BrowserControlsDontTriggerCommit) {
diff --git a/chrome/VERSION b/chrome/VERSION
index 906bad2..79d37823 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=63
 MINOR=0
-BUILD=3214
+BUILD=3215
 PATCH=0
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 9b3fa3b..936da9c0 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1490,7 +1490,7 @@
   "javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java",
   "javatests/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBarTest.java",
   "javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java",
-  "javatests/src/org/chromium/chrome/browser/input/TextSuggestionMenuTest.java",
+  "javatests/src/org/chromium/chrome/browser/input/SpellCheckMenuTest.java",
   "javatests/src/org/chromium/chrome/browser/instantapps/InstantAppsHandlerTest.java",
   "javatests/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterTest.java",
   "javatests/src/org/chromium/chrome/browser/invalidation/DelayedInvalidationsControllerTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/TextSuggestionMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SpellCheckMenuTest.java
similarity index 86%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/input/TextSuggestionMenuTest.java
rename to chrome/android/javatests/src/org/chromium/chrome/browser/input/SpellCheckMenuTest.java
index 371204b5..da1c1aa6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/TextSuggestionMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SpellCheckMenuTest.java
@@ -7,7 +7,6 @@
 import android.support.test.filters.LargeTest;
 import android.view.View;
 
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -29,17 +28,18 @@
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.content_public.browser.WebContents;
 
+import java.util.concurrent.Callable;
 import java.util.concurrent.TimeoutException;
 
 /**
- * Integration tests for the text suggestion menu.
+ * Integration tests for the spell check menu.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({
         ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG,
 })
-public class TextSuggestionMenuTest {
+public class SpellCheckMenuTest {
     @Rule
     public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
             new ChromeActivityTestRule<>(ChromeActivity.class);
@@ -75,7 +75,7 @@
             @Override
             public boolean isSatisfied() {
                 SuggestionsPopupWindow suggestionsPopupWindow =
-                        cvc.getTextSuggestionHostForTesting().getSuggestionsPopupWindowForTesting();
+                        cvc.getTextSuggestionHostForTesting().getSpellCheckPopupWindowForTesting();
                 if (suggestionsPopupWindow == null) {
                     return false;
                 }
@@ -90,12 +90,22 @@
         });
 
         TouchCommon.singleClickView(getDeleteButton(cvc));
-        Assert.assertEquals("", DOMUtils.getNodeContents(cvc.getWebContents(), "div"));
+
+        CriteriaHelper.pollInstrumentationThread(Criteria.equals("", new Callable<String>() {
+            @Override
+            public String call() {
+                try {
+                    return DOMUtils.getNodeContents(cvc.getWebContents(), "div");
+                } catch (InterruptedException | TimeoutException e) {
+                    return null;
+                }
+            }
+        }));
     }
 
     private View getDeleteButton(ContentViewCore cvc) {
         View contentView = cvc.getTextSuggestionHostForTesting()
-                                   .getSuggestionsPopupWindowForTesting()
+                                   .getSpellCheckPopupWindowForTesting()
                                    .getContentViewForTesting();
         return contentView.findViewById(R.id.deleteButton);
     }
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index c17750e1..0261c6e 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -102,7 +102,7 @@
 
 // Delegate for the app/extension crash notification balloon. Restarts the
 // app/extension when the balloon is clicked.
-class CrashNotificationDelegate : public NotificationDelegate {
+class CrashNotificationDelegate : public message_center::NotificationDelegate {
  public:
   CrashNotificationDelegate(Profile* profile,
                             const Extension* extension)
@@ -145,10 +145,6 @@
 
   bool HasClickedListener() override { return true; }
 
-  std::string id() const override {
-    return kNotificationPrefix + extension_id_;
-  }
-
  private:
   ~CrashNotificationDelegate() override {}
 
@@ -160,12 +156,12 @@
   DISALLOW_COPY_AND_ASSIGN(CrashNotificationDelegate);
 };
 
-void NotificationImageReady(
-    const std::string extension_name,
-    const base::string16 message,
-    scoped_refptr<CrashNotificationDelegate> delegate,
-    Profile* profile,
-    const gfx::Image& icon) {
+void NotificationImageReady(const std::string extension_name,
+                            const std::string extension_id,
+                            const base::string16 message,
+                            scoped_refptr<CrashNotificationDelegate> delegate,
+                            Profile* profile,
+                            const gfx::Image& icon) {
   if (g_browser_process->IsShuttingDown())
     return;
 
@@ -178,18 +174,14 @@
   // Origin URL must be different from the crashed extension to avoid the
   // conflict. NotificationSystemObserver will cancel all notifications from
   // the same origin when OnExtensionUnloaded() is called.
-  Notification notification(message_center::NOTIFICATION_TYPE_SIMPLE,
-                            base::string16(),
-                            message,
-                            notification_icon,
-                            message_center::NotifierId(
-                                message_center::NotifierId::SYSTEM_COMPONENT,
-                                kNotifierId),
-                            base::string16(),
-                            GURL("chrome://extension-crash"),
-                            delegate->id(),
-                            message_center::RichNotificationData(),
-                            delegate.get());
+  std::string id = kNotificationPrefix + extension_id;
+  Notification notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE, id, base::string16(), message,
+      notification_icon,
+      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
+                                 kNotifierId),
+      base::string16(), GURL("chrome://extension-crash"), id,
+      message_center::RichNotificationData(), delegate.get());
 
   g_browser_process->notification_ui_manager()->Add(notification, profile);
 }
@@ -210,13 +202,9 @@
   // However, it's possible that the extension went away during the interim,
   // so we'll bind all the pertinent data here.
   extensions::ImageLoader::Get(profile)->LoadImageAsync(
-      extension,
-      resource,
-      gfx::Size(size, size),
+      extension, resource, gfx::Size(size, size),
       base::Bind(
-          &NotificationImageReady,
-          extension->name(),
-          message,
+          &NotificationImageReady, extension->name(), extension->id(), message,
           make_scoped_refptr(new CrashNotificationDelegate(profile, extension)),
           profile));
 }
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
index 8cdc755..d066905 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/common/pref_names.h"
+#include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/base/layout.h"
@@ -157,7 +157,7 @@
   pref_change_registrar_->Init(profile_->GetPrefs());
   // Kiosk app can be started only when policy compliance is reported.
   pref_change_registrar_->Add(
-      prefs::kArcPolicyComplianceReported,
+      arc::prefs::kArcPolicyComplianceReported,
       base::Bind(&ArcKioskAppService::PreconditionsChanged,
                  base::Unretained(this)));
   notification_blocker_.reset(new ArcKioskNotificationBlocker());
@@ -194,13 +194,14 @@
           << (maintenance_session_running_ ? "running" : "not running");
   VLOG(2) << "Policy compliance is "
           << (profile_->GetPrefs()->GetBoolean(
-                  prefs::kArcPolicyComplianceReported)
+                  arc::prefs::kArcPolicyComplianceReported)
                   ? "reported"
                   : "not yet reported");
   VLOG(2) << "Kiosk app with id: " << app_id_ << " is "
           << (app_launcher_ ? "already launched" : "not yet launched");
   if (app_info_ && app_info_->ready && !maintenance_session_running_ &&
-      profile_->GetPrefs()->GetBoolean(prefs::kArcPolicyComplianceReported)) {
+      profile_->GetPrefs()->GetBoolean(
+          arc::prefs::kArcPolicyComplianceReported)) {
     if (!app_launcher_) {
       VLOG(2) << "Starting kiosk app";
       app_launcher_ = base::MakeUnique<ArcKioskAppLauncher>(
diff --git a/chrome/browser/chromeos/arc/arc_migration_guide_notification.cc b/chrome/browser/chromeos/arc/arc_migration_guide_notification.cc
index 6483b26..b55bd4d 100644
--- a/chrome/browser/chromeos/arc/arc_migration_guide_notification.cc
+++ b/chrome/browser/chromeos/arc/arc_migration_guide_notification.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/arc/arc_prefs.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/known_user.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
index 3742373..fa8d0cd 100644
--- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
+++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_util.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
index 21a5f3c..a13d70f0 100644
--- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
@@ -17,10 +17,10 @@
 #include "chrome/browser/chromeos/arc/test/arc_data_removed_waiter.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_arc_session.h"
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 2d8f6b2a..ccfc463 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -35,14 +35,13 @@
 #include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager_client.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
-#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -162,35 +161,6 @@
 }
 
 // static
-void ArcSessionManager::RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  // TODO(dspaid): Implement a mechanism to allow this to sync on first boot
-  // only.
-  registry->RegisterBooleanPref(prefs::kArcDataRemoveRequested, false);
-  registry->RegisterBooleanPref(prefs::kArcEnabled, false);
-  registry->RegisterBooleanPref(prefs::kArcSignedIn, false);
-  registry->RegisterBooleanPref(prefs::kArcPaiStarted, false);
-  registry->RegisterBooleanPref(prefs::kArcTermsAccepted, false);
-  registry->RegisterBooleanPref(prefs::kArcVoiceInteractionValuePropAccepted,
-                                false);
-  registry->RegisterBooleanPref(prefs::kVoiceInteractionEnabled, false);
-  registry->RegisterBooleanPref(prefs::kVoiceInteractionContextEnabled, false);
-  registry->RegisterBooleanPref(prefs::kVoiceInteractionPrefSynced, false);
-  // Note that ArcBackupRestoreEnabled and ArcLocationServiceEnabled prefs have
-  // to be off by default, until an explicit gesture from the user to enable
-  // them is received. This is crucial in the cases when these prefs transition
-  // from a previous managed state to the unmanaged.
-  registry->RegisterBooleanPref(prefs::kArcBackupRestoreEnabled, false);
-  registry->RegisterBooleanPref(prefs::kArcLocationServiceEnabled, false);
-  // This is used to delete the Play user ID if ARC is disabled for an
-  // Active Directory managed device.
-  registry->RegisterStringPref(prefs::kArcActiveDirectoryPlayUserId,
-                               std::string());
-  // This is used to decide whether migration from ecryptfs to ext4 is allowed.
-  registry->RegisterIntegerPref(prefs::kEcryptfsMigrationStrategy, 0);
-}
-
-// static
 bool ArcSessionManager::IsOobeOptInActive() {
   // ARC OOBE OptIn is optional for now. Test if it exists and login host is
   // active.
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index 993ee30b..6ad96b6 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -21,10 +21,6 @@
 class ArcAppLauncher;
 class Profile;
 
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
 namespace arc {
 
 class ArcAndroidManagementChecker;
@@ -144,9 +140,6 @@
   // Returns true if OOBE flow is active currently.
   static bool IsOobeOptInActive();
 
-  // It is called from chrome/browser/prefs/browser_prefs.cc.
-  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
   static void DisableUIForTesting();
   static void EnableCheckAndroidManagementForTesting();
 
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
index eb55871e..04a624ea 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -30,9 +30,9 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
index c59470fe..b056d1e 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
@@ -37,11 +37,11 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
@@ -619,7 +619,7 @@
         return base::Value(false);
       case 2:
         return base::Value(true);
-    };
+    }
     NOTREACHED();
     return base::Value();
   }
@@ -632,7 +632,7 @@
         return base::Value(false);
       case 2:
         return base::Value(true);
-    };
+    }
     NOTREACHED();
     return base::Value();
   }
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index 2f8a452..5e182e3 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -22,8 +22,8 @@
 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/known_user.h"
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc
index 7c715667..e826282e 100644
--- a/chrome/browser/chromeos/arc/arc_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -22,9 +22,9 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/settings/install_attributes.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_prefs.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/testing_pref_service.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
index 1aeb610..e6632a46 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
@@ -19,11 +19,11 @@
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/arc/arc_features.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index bfa5248..a2a2864 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -26,10 +26,10 @@
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/arc/arc_features.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
index 4779256..662635c 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -28,6 +28,7 @@
 #include "chromeos/settings/timezone_settings.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/intent_helper/font_size_util.h"
 #include "components/onc/onc_pref_names.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -256,13 +257,13 @@
   } else if (pref_name == prefs::kArcLocationServiceEnabled) {
     if (ShouldSyncLocationServiceEnabled())
       SyncLocationServiceEnabled();
-  } else if (pref_name == prefs::kUse24HourClock) {
+  } else if (pref_name == ::prefs::kUse24HourClock) {
     SyncUse24HourClock();
-  } else if (pref_name == prefs::kResolveTimezoneByGeolocation) {
+  } else if (pref_name == ::prefs::kResolveTimezoneByGeolocation) {
     SyncTimeZoneByGeolocation();
-  } else if (pref_name == prefs::kWebKitDefaultFixedFontSize ||
-             pref_name == prefs::kWebKitDefaultFontSize ||
-             pref_name == prefs::kWebKitMinimumFontSize) {
+  } else if (pref_name == ::prefs::kWebKitDefaultFixedFontSize ||
+             pref_name == ::prefs::kWebKitDefaultFontSize ||
+             pref_name == ::prefs::kWebKitMinimumFontSize) {
     SyncFontSize();
   } else if (pref_name == proxy_config::prefs::kProxy) {
     SyncProxySettings();
@@ -304,11 +305,11 @@
   AddPrefToObserve(ash::prefs::kAccessibilityVirtualKeyboardEnabled);
   AddPrefToObserve(prefs::kArcBackupRestoreEnabled);
   AddPrefToObserve(prefs::kArcLocationServiceEnabled);
-  AddPrefToObserve(prefs::kResolveTimezoneByGeolocation);
-  AddPrefToObserve(prefs::kUse24HourClock);
-  AddPrefToObserve(prefs::kWebKitDefaultFixedFontSize);
-  AddPrefToObserve(prefs::kWebKitDefaultFontSize);
-  AddPrefToObserve(prefs::kWebKitMinimumFontSize);
+  AddPrefToObserve(::prefs::kResolveTimezoneByGeolocation);
+  AddPrefToObserve(::prefs::kUse24HourClock);
+  AddPrefToObserve(::prefs::kWebKitDefaultFixedFontSize);
+  AddPrefToObserve(::prefs::kWebKitDefaultFontSize);
+  AddPrefToObserve(::prefs::kWebKitMinimumFontSize);
   AddPrefToObserve(proxy_config::prefs::kProxy);
   AddPrefToObserve(onc::prefs::kDeviceOpenNetworkConfiguration);
   AddPrefToObserve(onc::prefs::kOpenNetworkConfiguration);
@@ -412,9 +413,9 @@
 }
 
 void ArcSettingsServiceImpl::SyncFontSize() const {
-  int default_size = GetIntegerPref(prefs::kWebKitDefaultFontSize);
-  int default_fixed_size = GetIntegerPref(prefs::kWebKitDefaultFixedFontSize);
-  int minimum_size = GetIntegerPref(prefs::kWebKitMinimumFontSize);
+  int default_size = GetIntegerPref(::prefs::kWebKitDefaultFontSize);
+  int default_fixed_size = GetIntegerPref(::prefs::kWebKitDefaultFixedFontSize);
+  int minimum_size = GetIntegerPref(::prefs::kWebKitMinimumFontSize);
 
   double android_scale = ConvertFontSizeChromeToAndroid(
       default_size, default_fixed_size, minimum_size);
@@ -427,7 +428,7 @@
 
 void ArcSettingsServiceImpl::SyncLocale() const {
   const PrefService::Preference* pref =
-      registrar_.prefs()->FindPreference(prefs::kApplicationLocale);
+      registrar_.prefs()->FindPreference(::prefs::kApplicationLocale);
   DCHECK(pref);
   std::string locale;
   bool value_exists = pref->GetValue()->GetAsString(&locale);
@@ -533,8 +534,8 @@
 }
 
 void ArcSettingsServiceImpl::SyncTimeZoneByGeolocation() const {
-  const PrefService::Preference* pref =
-      registrar_.prefs()->FindPreference(prefs::kResolveTimezoneByGeolocation);
+  const PrefService::Preference* pref = registrar_.prefs()->FindPreference(
+      ::prefs::kResolveTimezoneByGeolocation);
   DCHECK(pref);
   bool setTimeZoneByGeolocation = false;
   bool value_exists = pref->GetValue()->GetAsBoolean(&setTimeZoneByGeolocation);
@@ -547,7 +548,7 @@
 
 void ArcSettingsServiceImpl::SyncUse24HourClock() const {
   const PrefService::Preference* pref =
-      registrar_.prefs()->FindPreference(prefs::kUse24HourClock);
+      registrar_.prefs()->FindPreference(::prefs::kUse24HourClock);
   DCHECK(pref);
   bool use24HourClock = false;
   bool value_exists = pref->GetValue()->GetAsBoolean(&use24HourClock);
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
index 5c075af..c195c9e 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/chromeos/arc/intent_helper/arc_settings_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_profile_client.h"
@@ -27,6 +26,7 @@
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/proxy/proxy_config_handler.h"
 #include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_intent_helper_instance.h"
diff --git a/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc b/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc
index ee98b6a..c1fbca28 100644
--- a/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc
@@ -17,10 +17,10 @@
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_arc_session.h"
diff --git a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
index 8ae3b0f..12cefec 100644
--- a/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_optin_preference_handler.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/chromeos/arc/optin/arc_optin_preference_handler_observer.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/metrics/metrics_reporting_state.h"
-#include "chrome/common/pref_names.h"
+#include "components/arc/arc_prefs.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/prefs/pref_service.h"
 
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
index 56687cd..3fa9c6a9a 100644
--- a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator_unittest.cc
@@ -15,9 +15,9 @@
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
index 48806d13..eda6a67 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
@@ -24,10 +24,10 @@
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/pref_names.h"
 #include "chromeos/network/onc/onc_utils.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_prefs.h"
 #include "components/onc/onc_constants.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_namespace.h"
@@ -340,12 +340,6 @@
   arc_bridge_service_->policy()->RemoveObserver(this);
 }
 
-// static
-void ArcPolicyBridge::RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterBooleanPref(prefs::kArcPolicyComplianceReported, false);
-}
-
 void ArcPolicyBridge::OverrideIsManagedForTesting(bool is_managed) {
   is_managed_ = is_managed;
 }
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
index 78a4371b..2bcb20d 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
@@ -16,7 +16,6 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/policy/core/common/policy_namespace.h"
 #include "components/policy/core/common/policy_service.h"
-#include "components/pref_registry/pref_registry_syncable.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace content {
@@ -57,8 +56,6 @@
                   policy::PolicyService* policy_service);
   ~ArcPolicyBridge() override;
 
-  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
   void OverrideIsManagedForTesting(bool is_managed);
 
   // InstanceHolder<mojom::PolicyInstance>::Observer overrides.
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
index 79362bd..b7506dd 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -12,10 +12,10 @@
 #include "chrome/browser/chromeos/arc/policy/arc_policy_bridge.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/test/fake_policy_instance.h"
 #include "components/policy/core/common/mock_policy_service.h"
 #include "components/policy/core/common/policy_map.h"
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
index 073aeee..35d3386c 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
@@ -24,10 +24,10 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/instance_holder.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
index 7565fa6..a8f4595 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
@@ -34,6 +34,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/instance_holder.h"
 #include "components/session_manager/core/session_manager.h"
diff --git a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
index f6fbd7d..78a9c495 100644
--- a/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
+++ b/chrome/browser/chromeos/authpolicy/auth_policy_credentials_manager.cc
@@ -52,27 +52,23 @@
 constexpr char kKrb5ConfFile[] = "krb5.conf";
 
 // A notification delegate for the sign-out button.
-class SigninNotificationDelegate : public NotificationDelegate {
+// TODO(estade): Can this be a HandleNotificationButtonClickDelegate?
+class SigninNotificationDelegate : public message_center::NotificationDelegate {
  public:
-  explicit SigninNotificationDelegate(const std::string& id);
+  SigninNotificationDelegate();
 
   // NotificationDelegate:
   void Click() override;
   void ButtonClick(int button_index) override;
-  std::string id() const override;
 
  protected:
   ~SigninNotificationDelegate() override = default;
 
  private:
-  // Unique id of the notification.
-  const std::string id_;
-
   DISALLOW_COPY_AND_ASSIGN(SigninNotificationDelegate);
 };
 
-SigninNotificationDelegate::SigninNotificationDelegate(const std::string& id)
-    : id_(id) {}
+SigninNotificationDelegate::SigninNotificationDelegate() {}
 
 void SigninNotificationDelegate::Click() {
   chrome::AttemptUserExit();
@@ -82,10 +78,6 @@
   chrome::AttemptUserExit();
 }
 
-std::string SigninNotificationDelegate::id() const {
-  return id_;
-}
-
 // Writes |blob| into file <UserPath>/kerberos/|file_name|. First writes into
 // temporary file and then replace existing one.
 void WriteFile(const std::string& file_name, const std::string& blob) {
@@ -314,10 +306,6 @@
   const std::string notification_id = kProfileSigninNotificationId +
                                       profile_->GetProfileUserName() +
                                       std::to_string(message_id);
-  // Set the delegate for the notification's sign-out button.
-  SigninNotificationDelegate* delegate =
-      new SigninNotificationDelegate(notification_id);
-
   message_center::NotifierId notifier_id(
       message_center::NotifierId::SYSTEM_COMPONENT,
       kProfileSigninNotificationId);
@@ -326,13 +314,14 @@
   notifier_id.profile_id = profile_->GetProfileUserName();
 
   Notification notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE,
+      message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
       l10n_util::GetStringUTF16(IDS_SIGNIN_ERROR_BUBBLE_VIEW_TITLE),
       l10n_util::GetStringUTF16(message_id),
       ui::ResourceBundle::GetSharedInstance().GetImageNamed(
           IDR_NOTIFICATION_ALERT),
       notifier_id, l10n_util::GetStringUTF16(IDS_SIGNIN_ERROR_DISPLAY_SOURCE),
-      GURL(notification_id), notification_id, data, delegate);
+      GURL(notification_id), notification_id, data,
+      new SigninNotificationDelegate());
   notification.set_accent_color(
       message_center::kSystemNotificationColorCriticalWarning);
   notification.SetSystemPriority();
diff --git a/chrome/browser/chromeos/eol_notification.cc b/chrome/browser/chromeos/eol_notification.cc
index 3f567e8..b9aca27 100644
--- a/chrome/browser/chromeos/eol_notification.cc
+++ b/chrome/browser/chromeos/eol_notification.cc
@@ -30,11 +30,10 @@
 namespace {
 
 const char kEolNotificationId[] = "eol";
-const char kDelegateId[] = "eol_delegate";
 const SkColor kButtonIconColor = SkColorSetRGB(150, 150, 152);
 const SkColor kNotificationIconColor = SkColorSetRGB(219, 68, 55);
 
-class EolNotificationDelegate : public NotificationDelegate {
+class EolNotificationDelegate : public message_center::NotificationDelegate {
  public:
   explicit EolNotificationDelegate(Profile* profile);
 
@@ -46,7 +45,6 @@
 
   // NotificationDelegate overrides:
   void ButtonClick(int button_index) override;
-  std::string id() const override;
 
   Profile* const profile_;
 
@@ -77,10 +75,6 @@
   CancelNotification();
 }
 
-std::string EolNotificationDelegate::id() const {
-  return kDelegateId;
-}
-
 void EolNotificationDelegate::OpenMoreInfoPage() {
   chrome::NavigateParams params(profile_, GURL(chrome::kEolNotificationURL),
                                 ui::PAGE_TRANSITION_LINK);
@@ -92,7 +86,7 @@
 void EolNotificationDelegate::CancelNotification() {
   // Clean up the notification
   g_browser_process->notification_ui_manager()->CancelById(
-      id(), NotificationUIManager::GetProfileID(profile_));
+      kEolNotificationId, NotificationUIManager::GetProfileID(profile_));
 }
 
 }  // namespace
@@ -154,7 +148,7 @@
   data.buttons.push_back(dismiss);
 
   Notification notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE,
+      message_center::NOTIFICATION_TYPE_SIMPLE, kEolNotificationId,
       GetStringUTF16(IDS_EOL_NOTIFICATION_TITLE),
       GetStringUTF16(IDS_EOL_NOTIFICATION_EOL),
       message_center::IsNewStyleNotificationEnabled()
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc
index d6b2d1a4..9804e6c 100644
--- a/chrome/browser/chromeos/first_run/first_run.cc
+++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -25,6 +25,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
@@ -135,7 +136,7 @@
     // shown after the voice interaction OOBE flow.
     if (account_supported && arc::IsArcPlayStoreEnabledForProfile(profile_) &&
         !profile_->GetPrefs()->GetBoolean(
-            prefs::kArcVoiceInteractionValuePropAccepted)) {
+            arc::prefs::kArcVoiceInteractionValuePropAccepted)) {
       auto* service =
           arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(
               profile_);
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.cc b/chrome/browser/chromeos/hats/hats_notification_controller.cc
index 3a1ed6e..a7c1472 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.cc
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.cc
@@ -83,9 +83,6 @@
 namespace chromeos {
 
 // static
-const char HatsNotificationController::kDelegateId[] = "hats_delegate";
-
-// static
 const char HatsNotificationController::kNotificationId[] = "hats_notification";
 
 HatsNotificationController::HatsNotificationController(Profile* profile)
@@ -159,11 +156,6 @@
   return true;
 }
 
-// NotificationDelegate override:
-std::string HatsNotificationController::id() const {
-  return kDelegateId;
-}
-
 // message_center::NotificationDelegate override:
 void HatsNotificationController::Click() {
   ButtonClick(0 /* unused */);
@@ -178,7 +170,7 @@
 
   // Remove the notification.
   g_browser_process->notification_ui_manager()->CancelById(
-      id(), NotificationUIManager::GetProfileID(profile_));
+      kNotificationId, NotificationUIManager::GetProfileID(profile_));
 }
 
 // message_center::NotificationDelegate override:
@@ -212,7 +204,7 @@
       l10n_util::GetStringUTF16(IDS_ASH_HATS_NOTIFICATION_TAKE_SURVEY_BUTTON)));
 
   Notification* notification = new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE,
+      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
       l10n_util::GetStringUTF16(IDS_ASH_HATS_NOTIFICATION_TITLE),
       l10n_util::GetStringUTF16(IDS_ASH_HATS_NOTIFICATION_BODY),
       gfx::Image(
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.h b/chrome/browser/chromeos/hats/hats_notification_controller.h
index 0138d8a5..7c1a548f 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.h
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.h
@@ -20,10 +20,9 @@
 
 // Happiness tracking survey (HaTS) notification controller is responsible for
 // managing the HaTS notification that is displayed to the user.
-class HatsNotificationController : public NotificationDelegate,
+class HatsNotificationController : public message_center::NotificationDelegate,
                                    public NetworkPortalDetector::Observer {
  public:
-  static const char kDelegateId[];
   static const char kNotificationId[];
 
   explicit HatsNotificationController(Profile* profile);
@@ -51,7 +50,6 @@
   void ButtonClick(int button_index) override;
   void Close(bool by_user) override;
   void Click() override;
-  std::string id() const override;
 
   // NetworkPortalDetector::Observer override:
   void OnPortalDetectionCompleted(
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller_unittest.cc b/chrome/browser/chromeos/hats/hats_notification_controller_unittest.cc
index 174ae48..5afdf9e 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller_unittest.cc
+++ b/chrome/browser/chromeos/hats/hats_notification_controller_unittest.cc
@@ -128,7 +128,7 @@
 
   const Notification* notification =
       g_browser_process->notification_ui_manager()->FindById(
-          HatsNotificationController::kDelegateId, &profile_);
+          HatsNotificationController::kNotificationId, &profile_);
   EXPECT_FALSE(notification);
 }
 
@@ -151,7 +151,7 @@
   // Finally check if notification was launched to confirm initialization.
   const Notification* notification =
       g_browser_process->notification_ui_manager()->FindById(
-          HatsNotificationController::kDelegateId, &profile_);
+          HatsNotificationController::kNotificationId, &profile_);
   EXPECT_TRUE(notification != nullptr);
 }
 
@@ -184,7 +184,7 @@
 
   const Notification* notification =
       g_browser_process->notification_ui_manager()->FindById(
-          HatsNotificationController::kDelegateId, &profile_);
+          HatsNotificationController::kNotificationId, &profile_);
   EXPECT_FALSE(notification);
 }
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index a07e4ed..b355915 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -93,6 +93,7 @@
 #include "chromeos/settings/timezone_settings.h"
 #include "chromeos/timezone/timezone_provider.h"
 #include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_prefs.h"
 #include "components/crash/content/app/breakpad_linux.h"
 #include "components/pairing/bluetooth_controller_pairing_controller.h"
 #include "components/pairing/bluetooth_host_pairing_controller.h"
@@ -1596,8 +1597,8 @@
     VLOG(1) << "Skip ARC Terms of Service screen because ARC is not allowed.";
     return false;
   }
-  if (profile->GetPrefs()->IsManagedPreference(prefs::kArcEnabled) &&
-      !profile->GetPrefs()->GetBoolean(prefs::kArcEnabled)) {
+  if (profile->GetPrefs()->IsManagedPreference(arc::prefs::kArcEnabled) &&
+      !profile->GetPrefs()->GetBoolean(arc::prefs::kArcEnabled)) {
     VLOG(1) << "Skip ARC Terms of Service screen because ARC is disabled.";
     return false;
   }
diff --git a/chrome/browser/chromeos/net/network_state_notifier.cc b/chrome/browser/chromeos/net/network_state_notifier.cc
index 4d78006..03b91badb 100644
--- a/chrome/browser/chromeos/net/network_state_notifier.cc
+++ b/chrome/browser/chromeos/net/network_state_notifier.cc
@@ -206,7 +206,9 @@
 void NetworkStateNotifier::UpdateVpnConnectionState(const NetworkState* vpn) {
   if (vpn->path() == connected_vpn_) {
     if (!vpn->IsConnectedState() && !vpn->IsConnectingState()) {
-      ShowVpnDisconnectedNotification(vpn);
+      if (vpn->vpn_provider_type() != shill::kProviderArcVpn) {
+        ShowVpnDisconnectedNotification(vpn);
+      }
       connected_vpn_.clear();
     }
   } else if (vpn->IsConnectedState()) {
diff --git a/chrome/browser/chromeos/note_taking_helper_unittest.cc b/chrome/browser/chromeos/note_taking_helper_unittest.cc
index 2c2277a..c3cef3f 100644
--- a/chrome/browser/chromeos/note_taking_helper_unittest.cc
+++ b/chrome/browser/chromeos/note_taking_helper_unittest.cc
@@ -31,6 +31,7 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/common/intent_helper.mojom.h"
@@ -202,7 +203,7 @@
     ASSERT_FALSE(initialized_);
     initialized_ = true;
 
-    profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled,
+    profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled,
                                       flags & ENABLE_PLAY_STORE);
     arc_test_.SetUp(profile());
     arc::ArcServiceManager::Get()
@@ -221,7 +222,7 @@
     }
 
     // TODO(derat): Sigh, something in ArcAppTest appears to be re-enabling ARC.
-    profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled,
+    profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled,
                                       flags & ENABLE_PLAY_STORE);
     NoteTakingHelper::Initialize();
     NoteTakingHelper::Get()->SetProfileWithEnabledLockScreenApps(profile());
@@ -839,7 +840,7 @@
     return;
   // When Play Store is enabled, the helper's members should be updated
   // accordingly.
-  profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled, true);
+  profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, true);
   EXPECT_TRUE(helper()->play_store_enabled());
   EXPECT_FALSE(helper()->android_apps_received());
 
@@ -866,7 +867,7 @@
   const char kSecondProfileName[] = "second-profile";
   auto prefs = base::MakeUnique<sync_preferences::TestingPrefServiceSyncable>();
   chrome::RegisterUserProfilePrefs(prefs->registry());
-  prefs->SetBoolean(prefs::kArcEnabled, true);
+  prefs->SetBoolean(arc::prefs::kArcEnabled, true);
   profile_manager_->CreateTestingProfile(
       kSecondProfileName, std::move(prefs), base::ASCIIToUTF16("Second User"),
       1 /* avatar_id */, std::string() /* supervised_user_id */,
@@ -934,7 +935,7 @@
   if (arc::ShouldArcAlwaysStart())
     return;
   // Disable Play Store and check that the apps are no longer returned.
-  profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled, false);
+  profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, false);
   EXPECT_FALSE(helper()->play_store_enabled());
   EXPECT_FALSE(helper()->android_apps_received());
   EXPECT_FALSE(helper()->IsAppAvailable(profile()));
@@ -1064,9 +1065,9 @@
 
   // Disabling and enabling Play Store should also notify the observer (and
   // enabling should request apps again).
-  profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled, false);
+  profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, false);
   EXPECT_EQ(2, observer.num_updates());
-  profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled, true);
+  profile()->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, true);
   EXPECT_EQ(3, observer.num_updates());
   // Run ARC data removing operation.
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
index 53b8300..642d7a17 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
@@ -165,6 +165,14 @@
     VoidResult(success_callback, failure_callback);
   }
 
+  void SelectCellularMobileNetwork(
+      const std::string& guid,
+      const std::string& nework_id,
+      const VoidCallback& success_callback,
+      const FailureCallback& failure_callback) override {
+    VoidResult(success_callback, failure_callback);
+  }
+
   // Synchronous methods
   std::unique_ptr<base::ListValue> GetEnabledNetworkTypes() override {
     std::unique_ptr<base::ListValue> result;
@@ -538,6 +546,10 @@
   EXPECT_TRUE(RunNetworkingSubtest("setCellularSimState")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(NetworkingPrivateApiTest, SelectCellularMobileNetwork) {
+  EXPECT_TRUE(RunNetworkingSubtest("selectCellularMobileNetwork")) << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(NetworkingPrivateApiTest, GetGlobalPolicy) {
   EXPECT_TRUE(RunNetworkingSubtest("getGlobalPolicy")) << message_;
 }
@@ -645,6 +657,11 @@
   EXPECT_FALSE(RunNetworkingSubtest("setCellularSimState")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(NetworkingPrivateApiTestFail,
+                       SelectCellularMobileNetwork) {
+  EXPECT_FALSE(RunNetworkingSubtest("selectCellularMobileNetwork")) << message_;
+}
+
 #endif // defined(OS_WIN)
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
index b62c6f5f..ebad0c2 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -53,6 +53,7 @@
 #include "extensions/browser/api/networking_private/networking_private_delegate_factory.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/switches.h"
+#include "extensions/common/value_builder.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -874,6 +875,28 @@
   EXPECT_TRUE(RunNetworkingSubtest("setCellularSimState")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
+                       SelectCellularMobileNetwork) {
+  SetupCellular();
+  // Create fake list of found networks.
+  std::unique_ptr<base::ListValue> found_networks =
+      extensions::ListBuilder()
+          .Append(extensions::DictionaryBuilder()
+                      .Set(shill::kNetworkIdProperty, "network1")
+                      .Set(shill::kTechnologyProperty, "GSM")
+                      .Set(shill::kStatusProperty, "current")
+                      .Build())
+          .Append(extensions::DictionaryBuilder()
+                      .Set(shill::kNetworkIdProperty, "network2")
+                      .Set(shill::kTechnologyProperty, "GSM")
+                      .Set(shill::kStatusProperty, "available")
+                      .Build())
+          .Build();
+  device_test_->SetDeviceProperty(
+      kCellularDevicePath, shill::kFoundNetworksProperty, *found_networks);
+  EXPECT_TRUE(RunNetworkingSubtest("selectCellularMobileNetwork")) << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, CellularSimPuk) {
   SetupCellular();
   // Lock the SIM
diff --git a/chrome/browser/extensions/api/notifications/extension_notification_display_helper.cc b/chrome/browser/extensions/api/notifications/extension_notification_display_helper.cc
index cfbdfc4..3aefc70 100644
--- a/chrome/browser/extensions/api/notifications/extension_notification_display_helper.cc
+++ b/chrome/browser/extensions/api/notifications/extension_notification_display_helper.cc
@@ -25,18 +25,18 @@
     const Notification& notification) {
   // Remove the previous version of this notification if the |notification| is
   // updating another notification.
-  EraseDataForNotificationId(notification.delegate_id());
+  EraseDataForNotificationId(notification.id());
 
   notifications_.push_back(base::MakeUnique<Notification>(notification));
 
-  GetDisplayService()->Display(NotificationCommon::EXTENSION,
-                               notification.delegate_id(), notification);
+  GetDisplayService()->Display(NotificationCommon::EXTENSION, notification.id(),
+                               notification);
 }
 
 Notification* ExtensionNotificationDisplayHelper::GetByNotificationId(
     const std::string& notification_id) {
   for (const auto& notification : notifications_) {
-    if (notification->delegate_id() == notification_id)
+    if (notification->id() == notification_id)
       return notification.get();
   }
 
@@ -49,7 +49,7 @@
   std::set<std::string> notification_ids;
   for (const auto& notification : notifications_) {
     if (notification->origin_url() == extension_origin)
-      notification_ids.insert(notification->delegate_id());
+      notification_ids.insert(notification->id());
   }
 
   return notification_ids;
@@ -60,7 +60,7 @@
   auto iter = std::find_if(
       notifications_.begin(), notifications_.end(),
       [notification_id](const std::unique_ptr<Notification>& notification) {
-        return notification->delegate_id() == notification_id;
+        return notification->id() == notification_id;
       });
 
   if (iter == notifications_.end())
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 53130323..13a5135 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
 #include "chromeos/settings/cros_settings_names.h"
+#include "components/arc/arc_prefs.h"
 #include "ui/chromeos/events/pref_names.h"
 #endif
 
@@ -278,13 +279,13 @@
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
 
   // Android Apps.
-  (*s_whitelist)[::prefs::kArcEnabled] =
+  (*s_whitelist)[arc::prefs::kArcEnabled] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
 
   // Google Assistant.
-  (*s_whitelist)[::prefs::kVoiceInteractionEnabled] =
+  (*s_whitelist)[arc::prefs::kVoiceInteractionEnabled] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_whitelist)[::prefs::kVoiceInteractionContextEnabled] =
+  (*s_whitelist)[arc::prefs::kVoiceInteractionContextEnabled] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
 
   // Misc.
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 8ca3335..fe1aca0 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -273,14 +273,7 @@
 // Test that hosted apps with the background permission but that set
 // allow_js_access to false also use a process per app instance model.
 // Separate instances should be in separate processes.
-// Flaky on XP: http://crbug.com/165834
-#if defined(OS_WIN)
-#define MAYBE_AppProcessBackgroundInstances \
-    DISABLED_AppProcessBackgroundInstances
-#else
-#define MAYBE_AppProcessBackgroundInstances AppProcessBackgroundInstances
-#endif
-IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessBackgroundInstances) {
+IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessBackgroundInstances) {
   TestAppInstancesHelper("app_process_background_instances");
 }
 
diff --git a/chrome/browser/extensions/extension_incognito_apitest.cc b/chrome/browser/extensions/extension_incognito_apitest.cc
index 225a2251..a07f0e4 100644
--- a/chrome/browser/extensions/extension_incognito_apitest.cc
+++ b/chrome/browser/extensions/extension_incognito_apitest.cc
@@ -53,14 +53,7 @@
   EXPECT_TRUE(result);
 }
 
-#if defined(OS_WIN)
-// This test is very flaky on XP. http://crbug.com/248821
-#define MAYBE_IncognitoYesScript DISABLED_IncognitoYesScript
-#else
-#define MAYBE_IncognitoYesScript IncognitoYesScript
-#endif
-
-IN_PROC_BROWSER_TEST_F(IncognitoApiTest, MAYBE_IncognitoYesScript) {
+IN_PROC_BROWSER_TEST_F(IncognitoApiTest, IncognitoYesScript) {
   // Load a dummy extension. This just tests that we don't regress a
   // crash fix when multiple incognito- and non-incognito-enabled extensions
   // are mixed.
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc
index 63a09dc..26ae695 100644
--- a/chrome/browser/notifications/message_center_notification_manager.cc
+++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -187,7 +187,7 @@
     const Notification& notification = pair.second->notification();
     if (pair.second->profile_id() == profile_id &&
         notification.origin_url() == source) {
-      delegate_ids.insert(notification.delegate_id());
+      delegate_ids.insert(notification.id());
     }
   }
 
@@ -199,7 +199,7 @@
   std::set<std::string> delegate_ids;
   for (const auto& pair : profile_notifications_) {
     if (pair.second->profile_id() == profile_id)
-      delegate_ids.insert(pair.second->notification().delegate_id());
+      delegate_ids.insert(pair.second->notification().id());
   }
 
   return delegate_ids;
diff --git a/chrome/browser/notifications/notification.cc b/chrome/browser/notifications/notification.cc
index 1f0ae13..e9d37a2 100644
--- a/chrome/browser/notifications/notification.cc
+++ b/chrome/browser/notifications/notification.cc
@@ -28,19 +28,43 @@
       tag_(tag),
       delegate_(delegate) {}
 
+Notification::Notification(
+    message_center::NotificationType type,
+    const std::string& id,
+    const base::string16& title,
+    const base::string16& body,
+    const gfx::Image& icon,
+    const message_center::NotifierId& notifier_id,
+    const base::string16& display_source,
+    const GURL& origin_url,
+    const std::string& tag,
+    const message_center::RichNotificationData& rich_notification_data,
+    scoped_refptr<message_center::NotificationDelegate> delegate)
+    : message_center::Notification(type,
+                                   id,
+                                   title,
+                                   body,
+                                   icon,
+                                   display_source,
+                                   origin_url,
+                                   notifier_id,
+                                   rich_notification_data,
+                                   delegate),
+      tag_(tag),
+      delegate_(delegate) {}
+
 Notification::Notification(const std::string& id,
                            const Notification& notification)
     : message_center::Notification(id, notification),
       tag_(notification.tag()),
       service_worker_scope_(notification.service_worker_scope()),
-      delegate_(notification.delegate()) {
-}
+      delegate_(notification.delegate_) {}
 
 Notification::Notification(const Notification& notification)
     : message_center::Notification(notification),
       tag_(notification.tag()),
       service_worker_scope_(notification.service_worker_scope()),
-      delegate_(notification.delegate()) {}
+      delegate_(notification.delegate_) {}
 
 Notification::~Notification() {}
 
@@ -48,6 +72,6 @@
   message_center::Notification::operator=(notification);
   tag_ = notification.tag();
   service_worker_scope_ = notification.service_worker_scope();
-  delegate_ = notification.delegate();
+  delegate_ = notification.delegate_;
   return *this;
 }
diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h
index 45fe6948..d7ec82ab0 100644
--- a/chrome/browser/notifications/notification.h
+++ b/chrome/browser/notifications/notification.h
@@ -23,6 +23,7 @@
 // Representation of a notification to be shown to the user.
 class Notification : public message_center::Notification {
  public:
+  // TODO(estade): remove this constructor and NotificationDelegate.
   Notification(
       message_center::NotificationType type,
       const base::string16& title,
@@ -35,6 +36,19 @@
       const message_center::RichNotificationData& rich_notification_data,
       scoped_refptr<NotificationDelegate> delegate);
 
+  Notification(
+      message_center::NotificationType type,
+      const std::string& id,
+      const base::string16& title,
+      const base::string16& body,
+      const gfx::Image& icon,
+      const message_center::NotifierId& notifier_id,
+      const base::string16& display_source,
+      const GURL& origin_url,
+      const std::string& tag,
+      const message_center::RichNotificationData& rich_notification_data,
+      scoped_refptr<message_center::NotificationDelegate> delegate);
+
   Notification(const std::string& id, const Notification& notification);
 
   Notification(const Notification& notification);
@@ -49,11 +63,6 @@
     service_worker_scope_ = service_worker_scope;
   }
 
-  // Id of the delegate embedded inside this instance.
-  std::string delegate_id() const { return delegate()->id(); }
-
-  NotificationDelegate* delegate() const { return delegate_.get(); }
-
  private:
   // The user-supplied tag for the notification.
   std::string tag_;
@@ -64,7 +73,7 @@
 
   // A proxy object that allows access back to the JavaScript object that
   // represents the notification, for firing events.
-  scoped_refptr<NotificationDelegate> delegate_;
+  scoped_refptr<message_center::NotificationDelegate> delegate_;
 };
 
 #endif  // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_
diff --git a/chrome/browser/notifications/notification_test_util.cc b/chrome/browser/notifications/notification_test_util.cc
index d78512c..551ffdb 100644
--- a/chrome/browser/notifications/notification_test_util.cc
+++ b/chrome/browser/notifications/notification_test_util.cc
@@ -42,7 +42,7 @@
     ProfileID profile_id) {
   auto iter = notifications_.begin();
   for (; iter != notifications_.end(); ++iter) {
-    if (iter->first.delegate_id() != delegate_id || iter->second != profile_id)
+    if (iter->first.id() != delegate_id || iter->second != profile_id)
       continue;
     notifications_.erase(iter);
     return true;
@@ -93,7 +93,7 @@
     ProfileID profile_id) const {
   auto iter = notifications_.begin();
   for (; iter != notifications_.end(); ++iter) {
-    if (iter->first.delegate_id() != delegate_id || iter->second != profile_id)
+    if (iter->first.id() != delegate_id || iter->second != profile_id)
       continue;
 
     return &iter->first;
@@ -106,8 +106,7 @@
                                            ProfileID profile_id) {
   auto iter = notifications_.begin();
   for (; iter != notifications_.end(); ++iter) {
-    if (iter->first.delegate_id() != delegate_id ||
-        iter->second != profile_id)
+    if (iter->first.id() != delegate_id || iter->second != profile_id)
       continue;
 
     iter->first.delegate()->Close(false /* by_user */);
@@ -125,7 +124,7 @@
   std::set<std::string> delegate_ids;
   for (const auto& pair : notifications_) {
     if (pair.second == profile_id && pair.first.origin_url() == source)
-      delegate_ids.insert(pair.first.delegate_id());
+      delegate_ids.insert(pair.first.id());
   }
   return delegate_ids;
 }
@@ -135,7 +134,7 @@
   std::set<std::string> delegate_ids;
   for (const auto& pair : notifications_) {
     if (pair.second == profile_id)
-      delegate_ids.insert(pair.first.delegate_id());
+      delegate_ids.insert(pair.first.id());
   }
   return delegate_ids;
 }
diff --git a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
index 27d68504..2b180847 100644
--- a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
+++ b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
@@ -672,8 +672,8 @@
       base::StartsWith(notification.id(), "p:", base::CompareCase::SENSITIVE));
 
   display_service_tester_->RemoveNotification(
-      NotificationCommon::PERSISTENT, notification.delegate_id(),
-      false /* by_user */, true /* silent */);
+      NotificationCommon::PERSISTENT, notification.id(), false /* by_user */,
+      true /* silent */);
 
   ASSERT_TRUE(RunScript("GetDisplayedNotifications()", &script_result));
   EXPECT_EQ("ok", script_result);
diff --git a/chrome/browser/notifications/profile_notification.cc b/chrome/browser/notifications/profile_notification.cc
index 369e0e7..a1a2940 100644
--- a/chrome/browser/notifications/profile_notification.cc
+++ b/chrome/browser/notifications/profile_notification.cc
@@ -29,7 +29,7 @@
           // Uses Notification's copy constructor to assign the message center
           // id, which should be unique for every profile + Notification pair.
           GetProfileNotificationId(
-              notification.delegate_id(),
+              notification.id(),
               NotificationUIManager::GetProfileID(profile)),
           notification),
       keep_alive_(new ScopedKeepAlive(KeepAliveOrigin::NOTIFICATION,
diff --git a/chrome/browser/notifications/stub_notification_display_service.cc b/chrome/browser/notifications/stub_notification_display_service.cc
index dd3c208..4220bc8 100644
--- a/chrome/browser/notifications/stub_notification_display_service.cc
+++ b/chrome/browser/notifications/stub_notification_display_service.cc
@@ -49,7 +49,7 @@
       notifications_.begin(), notifications_.end(),
       [notification_type, notification_id](const NotificationData& data) {
         return data.first == notification_type &&
-               data.second.delegate_id() == notification_id;
+               data.second.id() == notification_id;
       });
 
   if (iter == notifications_.end())
@@ -108,7 +108,7 @@
           notifications_.begin(), notifications_.end(),
           [notification_type, notification_id](const NotificationData& data) {
             return data.first == notification_type &&
-                   data.second.delegate_id() == notification_id;
+                   data.second.id() == notification_id;
           }),
       notifications_.end());
 }
@@ -119,7 +119,7 @@
       std::make_unique<std::set<std::string>>();
 
   for (const auto& notification_data : notifications_)
-    notifications->insert(notification_data.second.delegate_id());
+    notifications->insert(notification_data.second.id());
 
   callback.Run(std::move(notifications), true /* supports_synchronization */);
 }
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 68315b1..f3d9796c 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -73,6 +73,7 @@
 #include "chrome/browser/policy/default_geolocation_policy_handler.h"
 #include "chromeos/chromeos_pref_names.h"
 #include "chromeos/dbus/power_policy_controller.h"
+#include "components/arc/arc_prefs.h"
 #include "components/drive/drive_pref_names.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
@@ -572,13 +573,13 @@
     prefs::kUnifiedDesktopEnabledByDefault,
     base::Value::Type::BOOLEAN },
   { key::kArcEnabled,
-    prefs::kArcEnabled,
+    arc::prefs::kArcEnabled,
     base::Value::Type::BOOLEAN },
   { key::kArcBackupRestoreEnabled,
-    prefs::kArcBackupRestoreEnabled,
+    arc::prefs::kArcBackupRestoreEnabled,
     base::Value::Type::BOOLEAN },
   { key::kArcLocationServiceEnabled,
-    prefs::kArcLocationServiceEnabled,
+    arc::prefs::kArcLocationServiceEnabled,
     base::Value::Type::BOOLEAN },
   { key::kReportArcStatusEnabled,
     prefs::kReportArcStatusEnabled,
@@ -587,7 +588,7 @@
     prefs::kRecommendedNativePrinters,
     base::Value::Type::LIST },
   { key::kEcryptfsMigrationStrategy,
-    prefs::kEcryptfsMigrationStrategy,
+    arc::prefs::kEcryptfsMigrationStrategy,
     base::Value::Type::INTEGER },
   { key::kNativePrintersBulkAccessMode,
     prefs::kRecommendedNativePrintersAccessMode,
diff --git a/chrome/browser/policy/default_geolocation_policy_handler.cc b/chrome/browser/policy/default_geolocation_policy_handler.cc
index 7961761..923b73e 100644
--- a/chrome/browser/policy/default_geolocation_policy_handler.cc
+++ b/chrome/browser/policy/default_geolocation_policy_handler.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/policy/default_geolocation_policy_handler.h"
 
 #include "base/values.h"
-#include "chrome/common/pref_names.h"
+#include "components/arc/arc_prefs.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_constants.h"
@@ -25,7 +25,7 @@
   if (value && EnsureInRange(value, &value_in_range, nullptr)
       && value_in_range == CONTENT_SETTING_BLOCK) {
     // CONTENT_SETTING_BLOCK = BlockGeolocation
-    prefs->SetBoolean(prefs::kArcLocationServiceEnabled, false);
+    prefs->SetBoolean(arc::prefs::kArcLocationServiceEnabled, false);
   }
 }
 
diff --git a/chrome/browser/policy/default_geolocation_policy_handler_unittest.cc b/chrome/browser/policy/default_geolocation_policy_handler_unittest.cc
index 628623c..10717e6 100644
--- a/chrome/browser/policy/default_geolocation_policy_handler_unittest.cc
+++ b/chrome/browser/policy/default_geolocation_policy_handler_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
-#include "chrome/common/pref_names.h"
+#include "components/arc/arc_prefs.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/policy/core/browser/configuration_policy_pref_store.h"
 #include "components/policy/core/browser/configuration_policy_pref_store_test.h"
@@ -28,40 +28,44 @@
 TEST_F(DefaultGeolocationPolicyHandlerTest, AllowGeolocation) {
   // DefaultGeolocationSetting of CONTENT_SETTING_ALLOW (AllowGeolocation)
   // should not translate to the ArcLocationServiceEnabled preference.
-  EXPECT_FALSE(store_->GetValue(prefs::kArcLocationServiceEnabled, nullptr));
+  EXPECT_FALSE(
+      store_->GetValue(arc::prefs::kArcLocationServiceEnabled, nullptr));
   PolicyMap policy;
   policy.Set(key::kDefaultGeolocationSetting, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
              base::WrapUnique(new base::Value(CONTENT_SETTING_ALLOW)), nullptr);
   UpdateProviderPolicy(policy);
-  EXPECT_FALSE(store_->GetValue(prefs::kArcLocationServiceEnabled, nullptr));
+  EXPECT_FALSE(
+      store_->GetValue(arc::prefs::kArcLocationServiceEnabled, nullptr));
 }
 
 TEST_F(DefaultGeolocationPolicyHandlerTest, BlockGeolocation) {
   // DefaultGeolocationSetting of CONTENT_SETTING_BLOCK (BlockGeolocation)
   // should set the ArcLocationServiceEnabled preference to false.
-  EXPECT_FALSE(store_->GetValue(prefs::kArcLocationServiceEnabled, nullptr));
+  EXPECT_FALSE(
+      store_->GetValue(arc::prefs::kArcLocationServiceEnabled, nullptr));
   PolicyMap policy;
   policy.Set(key::kDefaultGeolocationSetting, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
              base::WrapUnique(new base::Value(CONTENT_SETTING_BLOCK)), nullptr);
   UpdateProviderPolicy(policy);
   const base::Value* value = nullptr;
-  EXPECT_TRUE(store_->GetValue(prefs::kArcLocationServiceEnabled, &value));
+  EXPECT_TRUE(store_->GetValue(arc::prefs::kArcLocationServiceEnabled, &value));
   EXPECT_TRUE(base::Value(false).Equals(value));
 }
 
 TEST_F(DefaultGeolocationPolicyHandlerTest, AskGeolocation) {
   // DefaultGeolocationSetting of CONTENT_SETTING_ASK (AskGeolocation) should
   // not translate to the ArcLocationServiceEnabled preference.
-  EXPECT_FALSE(store_->GetValue(prefs::kArcLocationServiceEnabled, nullptr));
+  EXPECT_FALSE(
+      store_->GetValue(arc::prefs::kArcLocationServiceEnabled, nullptr));
   PolicyMap policy;
   policy.Set(key::kDefaultGeolocationSetting, POLICY_LEVEL_MANDATORY,
              POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
              base::WrapUnique(new base::Value(CONTENT_SETTING_ASK)), nullptr);
   UpdateProviderPolicy(policy);
-  EXPECT_FALSE(store_->GetValue(prefs::kArcLocationServiceEnabled, nullptr));
+  EXPECT_FALSE(
+      store_->GetValue(arc::prefs::kArcLocationServiceEnabled, nullptr));
 }
 
 }  // namespace policy
-
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 440c62d..989e8f6f 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -217,6 +217,7 @@
 #include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_arc_session.h"
@@ -4239,8 +4240,9 @@
         base::MakeUnique<arc::ArcSessionRunner>(
             base::Bind(arc::FakeArcSession::Create)));
 
-    browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true);
-    browser()->profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted,
+    browser()->profile()->GetPrefs()->SetBoolean(arc::prefs::kArcSignedIn,
+                                                 true);
+    browser()->profile()->GetPrefs()->SetBoolean(arc::prefs::kArcTermsAccepted,
                                                  true);
   }
 
@@ -4262,7 +4264,7 @@
     UpdateProviderPolicy(policies);
     if (browser()) {
       const PrefService* const prefs = browser()->profile()->GetPrefs();
-      EXPECT_EQ(prefs->GetBoolean(prefs::kArcEnabled), enabled);
+      EXPECT_EQ(prefs->GetBoolean(arc::prefs::kArcEnabled), enabled);
     }
   }
 
@@ -4277,7 +4279,7 @@
 
   // ARC is switched off by default.
   EXPECT_TRUE(arc_session_manager->IsSessionStopped());
-  EXPECT_FALSE(pref->GetBoolean(prefs::kArcEnabled));
+  EXPECT_FALSE(pref->GetBoolean(arc::prefs::kArcEnabled));
 
   // Enable ARC.
   SetArcEnabledByPolicy(true);
@@ -4293,12 +4295,12 @@
   PrefService* const pref = browser()->profile()->GetPrefs();
 
   // ARC Backup & Restore is switched off by default.
-  EXPECT_FALSE(pref->GetBoolean(prefs::kArcBackupRestoreEnabled));
-  EXPECT_FALSE(pref->IsManagedPreference(prefs::kArcBackupRestoreEnabled));
+  EXPECT_FALSE(pref->GetBoolean(arc::prefs::kArcBackupRestoreEnabled));
+  EXPECT_FALSE(pref->IsManagedPreference(arc::prefs::kArcBackupRestoreEnabled));
 
   // Switch on ARC Backup & Restore in the user prefs.
-  pref->SetBoolean(prefs::kArcBackupRestoreEnabled, true);
-  EXPECT_TRUE(pref->GetBoolean(prefs::kArcBackupRestoreEnabled));
+  pref->SetBoolean(arc::prefs::kArcBackupRestoreEnabled, true);
+  EXPECT_TRUE(pref->GetBoolean(arc::prefs::kArcBackupRestoreEnabled));
 
   // Disable ARC Backup & Restore through the policy.
   PolicyMap policies;
@@ -4306,16 +4308,16 @@
                POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
                base::MakeUnique<base::Value>(false), nullptr);
   UpdateProviderPolicy(policies);
-  EXPECT_FALSE(pref->GetBoolean(prefs::kArcBackupRestoreEnabled));
-  EXPECT_TRUE(pref->IsManagedPreference(prefs::kArcBackupRestoreEnabled));
+  EXPECT_FALSE(pref->GetBoolean(arc::prefs::kArcBackupRestoreEnabled));
+  EXPECT_TRUE(pref->IsManagedPreference(arc::prefs::kArcBackupRestoreEnabled));
 
   // Enable ARC Backup & Restore through the policy.
   policies.Set(key::kArcBackupRestoreEnabled, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
                base::MakeUnique<base::Value>(true), nullptr);
   UpdateProviderPolicy(policies);
-  EXPECT_TRUE(pref->GetBoolean(prefs::kArcBackupRestoreEnabled));
-  EXPECT_TRUE(pref->IsManagedPreference(prefs::kArcBackupRestoreEnabled));
+  EXPECT_TRUE(pref->GetBoolean(arc::prefs::kArcBackupRestoreEnabled));
+  EXPECT_TRUE(pref->IsManagedPreference(arc::prefs::kArcBackupRestoreEnabled));
 }
 
 // Test ArcLocationServiceEnabled policy and its interplay with the
@@ -4337,12 +4339,13 @@
   test_default_geo_policy_values.emplace_back(3);  // 'AskGeolocation'
 
   // The pref is switched off by default.
-  EXPECT_FALSE(pref->GetBoolean(prefs::kArcLocationServiceEnabled));
-  EXPECT_FALSE(pref->IsManagedPreference(prefs::kArcLocationServiceEnabled));
+  EXPECT_FALSE(pref->GetBoolean(arc::prefs::kArcLocationServiceEnabled));
+  EXPECT_FALSE(
+      pref->IsManagedPreference(arc::prefs::kArcLocationServiceEnabled));
 
   // Switch on the pref in the user prefs.
-  pref->SetBoolean(prefs::kArcLocationServiceEnabled, true);
-  EXPECT_TRUE(pref->GetBoolean(prefs::kArcLocationServiceEnabled));
+  pref->SetBoolean(arc::prefs::kArcLocationServiceEnabled, true);
+  EXPECT_TRUE(pref->GetBoolean(arc::prefs::kArcLocationServiceEnabled));
 
   for (const auto& test_policy_value : test_policy_values) {
     for (const auto& test_default_geo_policy_value :
@@ -4369,7 +4372,7 @@
           !(should_be_disabled_by_policy ||
             should_be_disabled_by_default_geo_policy);
       EXPECT_EQ(expected_pref_value,
-                pref->GetBoolean(prefs::kArcLocationServiceEnabled))
+                pref->GetBoolean(arc::prefs::kArcLocationServiceEnabled))
           << "ArcLocationServiceEnabled policy is set to " << test_policy_value
           << "DefaultGeolocationSetting policy is set to "
           << test_default_geo_policy_value;
@@ -4378,8 +4381,9 @@
           test_policy_value.is_bool() ||
           (test_default_geo_policy_value.is_int() &&
            test_default_geo_policy_value.GetInt() == 2);
-      EXPECT_EQ(expected_pref_managed,
-                pref->IsManagedPreference(prefs::kArcLocationServiceEnabled))
+      EXPECT_EQ(
+          expected_pref_managed,
+          pref->IsManagedPreference(arc::prefs::kArcLocationServiceEnabled))
           << "ArcLocationServiceEnabled policy is set to " << test_policy_value
           << "DefaultGeolocationSetting policy is set to "
           << test_default_geo_policy_value;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 0fc2542..e4fb413 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -239,6 +239,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/network/proxy/proxy_config_handler.h"
 #include "chromeos/timezone/timezone_resolver.h"
+#include "components/arc/arc_prefs.h"
 #include "components/invalidation/impl/invalidator_storage.h"
 #include "components/onc/onc_pref_names.h"
 #include "components/quirks/quirks_manager.h"
@@ -594,8 +595,7 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-  arc::ArcSessionManager::RegisterProfilePrefs(registry);
-  arc::ArcPolicyBridge::RegisterProfilePrefs(registry);
+  arc::prefs::RegisterProfilePrefs(registry);
   chromeos::first_run::RegisterProfilePrefs(registry);
   chromeos::file_system_provider::RegisterProfilePrefs(registry);
   chromeos::KeyPermissions::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index baf5161..fd0b7e7 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -202,7 +202,7 @@
   // Attempt to dump all processes. Some of these processes will not be profiled
   // [e.g. utility processes, including the profiling process]. The profiling
   // process will gracefully handle these failures.
-  DCHECK_EQ(GetCurrentMode(), Mode::kAll);
+  DCHECK_NE(GetCurrentMode(), Mode::kNone);
   base::ProcessIterator process_iter(NULL);
   while (const base::ProcessEntry* process_entry =
              process_iter.NextProcessEntry()) {
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index da7f5f6..3f8788d8 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -99,6 +99,10 @@
     currentRoute_: Object,
   },
 
+  hostAttributes: {
+    role: 'main',
+  },
+
   listeners: {
     'subpage-expand': 'onSubpageExpanded_',
   },
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chrome/browser/resources/settings/controls/settings_toggle_button.html
index 7776cccd..3e6a81d 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.html
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -53,7 +53,7 @@
       }
     </style>
     <div id="outerRow" noSubLabel$="[[!subLabel]]">
-      <div class="flex" id="labelWrapper" hidden="[[!label]]">
+      <div class="flex" id="labelWrapper" hidden$="[[!label]]">
         <div id="label" class="label">[[label]]</div>
         <div id="subLabel" class="secondary label">[[subLabel]]</div>
       </div>
@@ -63,7 +63,8 @@
         </cr-policy-pref-indicator>
       </template>
       <paper-toggle-button id="control" checked="{{checked}}"
-          on-change="notifyChangedByUserInteraction" aria-labelledby="label"
+          on-change="notifyChangedByUserInteraction"
+          aria-label$="[[getAriaLabel_(label, ariaLabel)]]"
           aria-describedby="subLabel" on-up="resetTrackLock_"
           disabled="[[controlDisabled_(disabled, pref)]]"
           on-tap="onToggleTap_">
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chrome/browser/resources/settings/controls/settings_toggle_button.js
index 1ac827c..96c7899 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.js
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -12,6 +12,13 @@
   behaviors: [SettingsBooleanControlBehavior],
 
   properties: {
+    ariaLabel: {
+      type: String,
+      reflectToAttribute: false,  // Handled by #control.
+      observer: 'onAriaLabelSet_',
+      value: '',
+    },
+
     elideLabel: {
       type: Boolean,
       reflectToAttribute: true,
@@ -32,6 +39,26 @@
   },
 
   /**
+   * Removes the aria-label attribute if it's added by $i18n{...}.
+   * @private
+   */
+  onAriaLabelSet_: function() {
+    if (this.hasAttribute('aria-label')) {
+      let ariaLabel = this.ariaLabel;
+      this.removeAttribute('aria-label');
+      this.ariaLabel = ariaLabel;
+    }
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getAriaLabel_: function() {
+    return this.label || this.ariaLabel;
+  },
+
+  /**
    * Handle taps directly on the toggle (see: onLabelWrapperTap_ for non-toggle
    * taps).
    * @param {!Event} e
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html
index 40a923d..0b573e387 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.html
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -55,7 +55,7 @@
         <settings-toggle-button class="first"
             pref="{{prefs.settings.resolve_timezone_by_geolocation}}"
             id="timeZoneAutoDetect"
-            aria-labelledby="timezoneGeolocateToggleLabel">
+            aria-label="$i18n{timeZoneGeolocation}">
         </settings-toggle-button>
       </template>
     </div>
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index fcebde9..07e592fa 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -81,7 +81,7 @@
       }
     </style>
     <iron-selector id="topMenu" selectable="a" attr-for-selected="href"
-        on-iron-activate="onSelectorActivate_">
+        on-iron-activate="onSelectorActivate_" role="navigation">
 <if expr="chromeos">
       <a href="/internet">
         <iron-icon icon="settings:network-wifi"></iron-icon>
@@ -134,7 +134,8 @@
         </iron-icon></paper-button>
       <iron-collapse id="advancedSubmenu" opened="[[advancedOpened]]"
           hidden="[[!pageVisibility.advancedSettings]]">
-        <iron-selector id="subMenu" selectable="a" attr-for-selected="href">
+        <iron-selector id="subMenu" selectable="a" attr-for-selected="href"
+            role="navigation">
 <if expr="chromeos">
           <a href="/dateTime">
             <iron-icon icon="settings:access-time"></iron-icon>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 27bc50b..9326194 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -86,7 +86,7 @@
         spinner-active="[[toolbarSpinnerActive_]]"
         menu-label="$i18n{menuButtonLabel}"
         on-search-changed="onSearchChanged_"
-        role="none"
+        role="banner"
         show-menu>
     </cr-toolbar>
     <dialog id="drawer" is="cr-drawer" on-close="onMenuClosed_"
diff --git a/chrome/browser/status_icons/desktop_notification_balloon.cc b/chrome/browser/status_icons/desktop_notification_balloon.cc
index e511a8a9019..93b83c1 100644
--- a/chrome/browser/status_icons/desktop_notification_balloon.cc
+++ b/chrome/browser/status_icons/desktop_notification_balloon.cc
@@ -94,6 +94,6 @@
 
   g_browser_process->notification_ui_manager()->Add(notification, profile);
 
-  notification_id_ = notification.delegate_id();
+  notification_id_ = notification.id();
   profile_ = profile;
 }
diff --git a/chrome/browser/tracing/crash_service_uploader.cc b/chrome/browser/tracing/crash_service_uploader.cc
index 3dfd031e..f0b945a 100644
--- a/chrome/browser/tracing/crash_service_uploader.cc
+++ b/chrome/browser/tracing/crash_service_uploader.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
@@ -104,6 +105,7 @@
     int64_t current,
     int64_t total) {
   DCHECK(url_fetcher_.get());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   LOG(WARNING) << "Upload progress: " << current << " of " << total;
 
@@ -121,27 +123,24 @@
     const UploadProgressCallback& progress_callback,
     const UploadDoneCallback& done_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(&TraceCrashServiceUploader::DoUploadOnFileThread,
-                 base::Unretained(this), file_contents, upload_mode,
-                 upload_url_, base::Passed(std::move(metadata)),
-                 progress_callback, done_callback));
-}
-
-void TraceCrashServiceUploader::DoUploadOnFileThread(
-    const std::string& file_contents,
-    UploadMode upload_mode,
-    const std::string& upload_url,
-    std::unique_ptr<const base::DictionaryValue> metadata,
-    const UploadProgressCallback& progress_callback,
-    const UploadDoneCallback& done_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
-  DCHECK(!url_fetcher_.get());
 
   progress_callback_ = progress_callback;
   done_callback_ = done_callback;
 
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::TaskPriority::BACKGROUND},
+      base::Bind(&TraceCrashServiceUploader::DoCompressOnBackgroundThread,
+                 base::Unretained(this), file_contents, upload_mode,
+                 upload_url_, base::Passed(std::move(metadata))));
+}
+
+void TraceCrashServiceUploader::DoCompressOnBackgroundThread(
+    const std::string& file_contents,
+    UploadMode upload_mode,
+    const std::string& upload_url,
+    std::unique_ptr<const base::DictionaryValue> metadata) {
+  DCHECK(!url_fetcher_.get());
+
   if (upload_url.empty()) {
     OnUploadError("Upload URL empty or invalid");
     return;
diff --git a/chrome/browser/tracing/crash_service_uploader.h b/chrome/browser/tracing/crash_service_uploader.h
index eb555f1..06172a3c 100644
--- a/chrome/browser/tracing/crash_service_uploader.h
+++ b/chrome/browser/tracing/crash_service_uploader.h
@@ -49,13 +49,12 @@
                 const UploadDoneCallback& done_callback) override;
 
  private:
-  void DoUploadOnFileThread(
+  void DoCompressOnBackgroundThread(
       const std::string& file_contents,
       UploadMode upload_mode,
       const std::string& upload_url,
-      std::unique_ptr<const base::DictionaryValue> metadata,
-      const UploadProgressCallback& progress_callback,
-      const UploadDoneCallback& done_callback);
+      std::unique_ptr<const base::DictionaryValue> metadata);
+
   // Sets up a multipart body to be uploaded. The body is produced according
   // to RFC 2046.
   void SetupMultipart(const std::string& product,
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index ec46dad..1665e7d 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -24,8 +24,8 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/crx_file/id_util.h"
@@ -94,21 +94,21 @@
       : prefs_(prefs) {}
 
   void Put(const std::string& app_id, bool enabled) {
-    DictionaryPrefUpdate update(prefs_,
-                                prefs::kArcSetNotificationsEnabledDeferred);
+    DictionaryPrefUpdate update(
+        prefs_, arc::prefs::kArcSetNotificationsEnabledDeferred);
     base::DictionaryValue* const dict = update.Get();
     dict->SetKey(app_id, base::Value(enabled));
   }
 
   bool Get(const std::string& app_id, bool* enabled) {
     const base::DictionaryValue* dict =
-        prefs_->GetDictionary(prefs::kArcSetNotificationsEnabledDeferred);
+        prefs_->GetDictionary(arc::prefs::kArcSetNotificationsEnabledDeferred);
     return dict->GetBoolean(app_id, enabled);
   }
 
   void Remove(const std::string& app_id) {
-    DictionaryPrefUpdate update(prefs_,
-                                prefs::kArcSetNotificationsEnabledDeferred);
+    DictionaryPrefUpdate update(
+        prefs_, arc::prefs::kArcSetNotificationsEnabledDeferred);
     base::DictionaryValue* const dict = update.Get();
     dict->RemoveWithoutPathExpansion(app_id, /* out_value */ nullptr);
   }
@@ -140,7 +140,7 @@
 }
 
 void DeleteAppFolderFromFileThread(const base::FilePath& path) {
-  DCHECK(path.DirName().BaseName().MaybeAsASCII() == prefs::kArcApps &&
+  DCHECK(path.DirName().BaseName().MaybeAsASCII() == arc::prefs::kArcApps &&
          (!base::PathExists(path) || base::DirectoryExists(path)));
   const bool deleted = base::DeleteFile(path, true);
   DCHECK(deleted);
@@ -216,7 +216,7 @@
 // local prefs and renaming won't affect other user's devices.
 // TODO(khmel): Remove this after few releases http://crbug.com/722675.
 void UpdatePlayStoreDictionary(PrefService* service) {
-  DictionaryPrefUpdate update(service, prefs::kArcApps);
+  DictionaryPrefUpdate update(service, arc::prefs::kArcApps);
   base::DictionaryValue* dict = update.Get();
   std::unique_ptr<base::Value> play_store_dictionary;
   if (!dict->Remove(arc::kLegacyPlayStoreAppId, &play_store_dictionary))
@@ -241,9 +241,10 @@
 // static
 void ArcAppListPrefs::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterDictionaryPref(prefs::kArcApps);
-  registry->RegisterDictionaryPref(prefs::kArcPackages);
-  registry->RegisterDictionaryPref(prefs::kArcSetNotificationsEnabledDeferred);
+  registry->RegisterDictionaryPref(arc::prefs::kArcApps);
+  registry->RegisterDictionaryPref(arc::prefs::kArcPackages);
+  registry->RegisterDictionaryPref(
+      arc::prefs::kArcSetNotificationsEnabledDeferred);
 }
 
 // static
@@ -277,7 +278,7 @@
   DCHECK(app_instance_holder);
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   const base::FilePath& base_path = profile->GetPath();
-  base_path_ = base_path.AppendASCII(prefs::kArcApps);
+  base_path_ = base_path.AppendASCII(arc::prefs::kArcApps);
 
   invalidated_icon_scale_factor_mask_ = 0;
   for (ui::ScaleFactor scale_factor : ui::GetSupportedScaleFactors())
@@ -480,7 +481,7 @@
 
   const base::DictionaryValue* package = nullptr;
   const base::DictionaryValue* packages =
-      prefs_->GetDictionary(prefs::kArcPackages);
+      prefs_->GetDictionary(arc::prefs::kArcPackages);
   if (!packages ||
       !packages->GetDictionaryWithoutPathExpansion(package_name, &package))
     return std::unique_ptr<PackageInfo>();
@@ -524,7 +525,8 @@
 
 std::vector<std::string> ArcAppListPrefs::GetAppIdsNoArcEnabledCheck() const {
   std::vector<std::string> ids;
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   DCHECK(apps);
 
   // crx_file::id_util is de-facto utility for id generation.
@@ -548,7 +550,8 @@
     return std::unique_ptr<AppInfo>();
 
   const base::DictionaryValue* app = nullptr;
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app))
     return std::unique_ptr<AppInfo>();
 
@@ -605,7 +608,8 @@
     return false;
 
   const base::DictionaryValue* app = nullptr;
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   return apps && apps->GetDictionaryWithoutPathExpansion(app_id, &app);
 }
 
@@ -634,7 +638,7 @@
     return;
 
   const base::Time time = base::Time::Now();
-  ScopedArcPrefUpdate update(prefs_, app_id, prefs::kArcApps);
+  ScopedArcPrefUpdate update(prefs_, app_id, arc::prefs::kArcApps);
   base::DictionaryValue* app_dict = update.Get();
   const std::string string_value = base::Int64ToString(time.ToInternalValue());
   app_dict->SetString(kLastLaunchTime, string_value);
@@ -885,7 +889,7 @@
     }
   }
 
-  ScopedArcPrefUpdate update(prefs_, app_id, prefs::kArcApps);
+  ScopedArcPrefUpdate update(prefs_, app_id, arc::prefs::kArcApps);
   base::DictionaryValue* app_dict = update.Get();
   app_dict->SetString(kName, updated_name);
   app_dict->SetString(kPackageName, package_name);
@@ -962,7 +966,7 @@
   const base::FilePath app_path = GetAppPath(app_id);
 
   // Remove from prefs.
-  DictionaryPrefUpdate update(prefs_, prefs::kArcApps);
+  DictionaryPrefUpdate update(prefs_, arc::prefs::kArcApps);
   base::DictionaryValue* apps = update.Get();
   const bool removed = apps->Remove(app_id, nullptr);
   DCHECK(removed);
@@ -989,7 +993,7 @@
     return;
   }
 
-  ScopedArcPrefUpdate update(prefs, package_name, prefs::kArcPackages);
+  ScopedArcPrefUpdate update(prefs, package_name, arc::prefs::kArcPackages);
   base::DictionaryValue* package_dict = update.Get();
   const std::string id_str =
       base::Int64ToString(package.last_backup_android_id);
@@ -1017,13 +1021,13 @@
                                              const std::string& package_name) {
   default_apps_.MaybeMarkPackageUninstalled(package_name, true);
   if (!default_apps_.HasPackage(package_name)) {
-    DictionaryPrefUpdate update(prefs, prefs::kArcPackages);
+    DictionaryPrefUpdate update(prefs, arc::prefs::kArcPackages);
     base::DictionaryValue* packages = update.Get();
     const bool removed = packages->RemoveWithoutPathExpansion(package_name,
                                                               nullptr);
     DCHECK(removed);
   } else {
-    ScopedArcPrefUpdate update(prefs, package_name, prefs::kArcPackages);
+    ScopedArcPrefUpdate update(prefs, package_name, arc::prefs::kArcPackages);
     base::DictionaryValue* package_dict = update.Get();
     package_dict->SetBoolean(kUninstalled, true);
   }
@@ -1127,7 +1131,7 @@
   MaybeRemoveIconRequestRecord(app_id);
 
   {
-    ScopedArcPrefUpdate update(prefs_, app_id, prefs::kArcApps);
+    ScopedArcPrefUpdate update(prefs_, app_id, arc::prefs::kArcApps);
     base::DictionaryValue* app_dict = update.Get();
     app_dict->SetInteger(kInvalidatedIcons,
                          invalidated_icon_scale_factor_mask_);
@@ -1187,7 +1191,8 @@
 void ArcAppListPrefs::OnUninstallShortcut(const std::string& package_name,
                                           const std::string& intent_uri) {
   std::vector<std::string> shortcuts_to_remove;
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   for (base::DictionaryValue::Iterator app_it(*apps); !app_it.IsAtEnd();
        app_it.Advance()) {
     const base::Value* value = &app_it.value();
@@ -1225,7 +1230,8 @@
     const std::string& package_name,
     bool include_shortcuts) const {
   std::unordered_set<std::string> app_set;
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   for (base::DictionaryValue::Iterator app_it(*apps); !app_it.IsAtEnd();
        app_it.Advance()) {
     const base::Value* value = &app_it.value();
@@ -1347,7 +1353,8 @@
 void ArcAppListPrefs::OnNotificationsEnabledChanged(
     const std::string& package_name,
     bool enabled) {
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   for (base::DictionaryValue::Iterator app(*apps); !app.IsAtEnd();
        app.Advance()) {
     const base::DictionaryValue* app_dict;
@@ -1360,7 +1367,7 @@
     if (app_package_name != package_name) {
       continue;
     }
-    ScopedArcPrefUpdate update(prefs_, app.key(), prefs::kArcApps);
+    ScopedArcPrefUpdate update(prefs_, app.key(), arc::prefs::kArcApps);
     base::DictionaryValue* updateing_app_dict = update.Get();
     updateing_app_dict->SetBoolean(kNotificationsEnabled, enabled);
   }
@@ -1460,7 +1467,7 @@
   }
 
   const base::DictionaryValue* package_prefs =
-      prefs_->GetDictionary(prefs::kArcPackages);
+      prefs_->GetDictionary(arc::prefs::kArcPackages);
   for (base::DictionaryValue::Iterator package(*package_prefs);
        !package.IsAtEnd(); package.Advance()) {
     const base::DictionaryValue* package_info;
@@ -1482,7 +1489,8 @@
 
 base::Time ArcAppListPrefs::GetInstallTime(const std::string& app_id) const {
   const base::DictionaryValue* app = nullptr;
-  const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
+  const base::DictionaryValue* apps =
+      prefs_->GetDictionary(arc::prefs::kArcApps);
   if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app))
     return base::Time();
 
@@ -1514,7 +1522,7 @@
   if (!install_succeed)
     return;
 
-  ScopedArcPrefUpdate update(prefs_, app_id, prefs::kArcApps);
+  ScopedArcPrefUpdate update(prefs_, app_id, arc::prefs::kArcApps);
   int invalidated_icon_mask = 0;
   base::DictionaryValue* app_dict = update.Get();
   app_dict->GetInteger(kInvalidatedIcons, &invalidated_icon_mask);
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index 4103c1b..8fc87e9 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -41,9 +41,9 @@
 #include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_app_instance.h"
@@ -596,7 +596,8 @@
         policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile());
     connector->OverrideIsManagedForTesting(true);
     profile()->GetTestingPrefService()->SetManagedPref(
-        prefs::kArcEnabled, base::MakeUnique<base::Value>(IsEnabledByPolicy()));
+        arc::prefs::kArcEnabled,
+        base::MakeUnique<base::Value>(IsEnabledByPolicy()));
 
     ArcPlayStoreAppTest::OnBeforeArcTestSetup();
   }
diff --git a/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc b/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc
index 864c884..a111dfa 100644
--- a/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc
+++ b/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
-#include "chrome/common/pref_names.h"
+#include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/sync_prefs.h"
@@ -28,7 +28,7 @@
       profile_(profile) {
   pref_registrar_.Init(profile_->GetPrefs());
   pref_registrar_.Add(
-      prefs::kArcEnabled,
+      arc::prefs::kArcEnabled,
       base::Bind(&ArcPackageSyncDataTypeController::OnArcEnabledPrefChanged,
                  base::Unretained(this)));
 }
diff --git a/chrome/browser/ui/app_list/arc/arc_pai_starter.cc b/chrome/browser/ui/app_list/arc/arc_pai_starter.cc
index 3fedcea..289aa521 100644
--- a/chrome/browser/ui/app_list/arc/arc_pai_starter.cc
+++ b/chrome/browser/ui/app_list/arc/arc_pai_starter.cc
@@ -8,7 +8,7 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
-#include "chrome/common/pref_names.h"
+#include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "ui/events/event_constants.h"
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 96c63df..5c42131 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -58,6 +58,7 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
+#include "components/arc/arc_prefs.h"
 #include "components/favicon/content/content_favicon_driver.h"
 #include "components/signin/core/account_id/account_id.h"
 #include "components/strings/grit/components_strings.h"
@@ -1167,7 +1168,7 @@
   // race condition when OnAppUninstalledPrepared for ARC apps is called after
   // UpdateAppLaunchersFromPref.
   pref_change_registrar_.Add(
-      prefs::kArcEnabled,
+      arc::prefs::kArcEnabled,
       base::Bind(&ChromeLauncherController::ScheduleUpdateAppLaunchersFromPref,
                  base::Unretained(this)));
   pref_change_registrar_.Add(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 99b33ae8..44f99a61 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -82,6 +82,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_prefs.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/common/app.mojom.h"
 #include "components/arc/test/fake_app_instance.h"
@@ -3705,7 +3706,7 @@
   // ARC is managed and enabled, Play Store pin should be available.
   // Note: NEGOTIATING_TERMS_OF_SERVICE here means that opt-in flow starts.
   profile()->GetTestingPrefService()->SetManagedPref(
-      prefs::kArcEnabled, base::MakeUnique<base::Value>(true));
+      arc::prefs::kArcEnabled, base::MakeUnique<base::Value>(true));
   base::RunLoop().RunUntilIdle();
   ValidateArcState(true, true,
                    arc::ArcSessionManager::State::NEGOTIATING_TERMS_OF_SERVICE,
@@ -3713,13 +3714,14 @@
 
   // ARC is managed and disabled, Play Store pin should not be available.
   profile()->GetTestingPrefService()->SetManagedPref(
-      prefs::kArcEnabled, base::MakeUnique<base::Value>(false));
+      arc::prefs::kArcEnabled, base::MakeUnique<base::Value>(false));
   base::RunLoop().RunUntilIdle();
   ValidateArcState(false, true, arc::ArcSessionManager::State::STOPPED,
                    "AppList, Chrome");
 
   // ARC is not managed and disabled, Play Store pin should be available.
-  profile()->GetTestingPrefService()->RemoveManagedPref(prefs::kArcEnabled);
+  profile()->GetTestingPrefService()->RemoveManagedPref(
+      arc::prefs::kArcEnabled);
   base::RunLoop().RunUntilIdle();
   ValidateArcState(false, false, arc::ArcSessionManager::State::STOPPED,
                    "AppList, Chrome, Play Store");
diff --git a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
index 35479a2..5580941c 100644
--- a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
@@ -99,10 +99,8 @@
 
 // Test that in multi user environments a newly created browser gets created
 // on the same desktop as the browser is shown on.
-//
-// Flakily hits assert: http://crbug.com/469717
 IN_PROC_BROWSER_TEST_F(BrowserGuestSessionNavigatorTest,
-                       DISABLED_Browser_Gets_Created_On_Visiting_Desktop) {
+                       Browser_Gets_Created_On_Visiting_Desktop) {
   // Test 1: Test that a browser created from a visiting browser will be on the
   // same visiting desktop.
   {
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index bce381f..9930d3a 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -11,12 +11,12 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
+#include "components/arc/arc_prefs.h"
 #include "components/login/localized_values_builder.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
@@ -204,7 +204,7 @@
   // ARC is enabled (prefs::kArcEnabled = true) on showing Terms of Service. If
   // user accepts ToS then prefs::kArcEnabled is left activated. If user skips
   // ToS then prefs::kArcEnabled is automatically reset in ArcSessionManager.
-  profile->GetPrefs()->SetBoolean(prefs::kArcEnabled, true);
+  profile->GetPrefs()->SetBoolean(arc::prefs::kArcEnabled, true);
 
   action_taken_ = false;
 
@@ -216,7 +216,6 @@
   pref_handler_.reset(new arc::ArcOptInPreferenceHandler(
       this, profile->GetPrefs()));
   pref_handler_->Start();
-
 }
 
 bool ArcTermsOfServiceScreenHandler::NeedDispatchEventOnAction() {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 0725bb5..7dcbfc2 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -1429,8 +1429,13 @@
   file_type_info.extensions.resize(1);
   file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
   file_type_info.include_all_files = true;
+  // Print Preview requires native paths to write PDF files.
+  // Note that Chrome OS save-as dialog has Google Drive as a saving location
+  // even when a client requires native paths. In this case, Chrome OS save-as
+  // dialog returns native paths to write files and uploads the saved files to
+  // Google Drive later.
   file_type_info.allowed_paths =
-      ui::SelectFileDialog::FileTypeInfo::NATIVE_OR_DRIVE_PATH;
+      ui::SelectFileDialog::FileTypeInfo::NATIVE_PATH;
 
   select_file_dialog_ =
       ui::SelectFileDialog::Create(this, nullptr /*policy already checked*/);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 4514734..37e9515 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -17,62 +17,6 @@
 // *************** PROFILE PREFS ***************
 // These are attached to the user profile
 
-#if defined(OS_CHROMEOS) && BUILDFLAG(ENABLE_APP_LIST)
-// Stores the user id received from DM Server when enrolling a Play user on an
-// Active Directory managed device. Used to report to DM Server that the account
-// is still used.
-const char kArcActiveDirectoryPlayUserId[] =
-    "arc.active_directory_play_user_id";
-// A preference to keep list of Android apps and their state.
-const char kArcApps[] = "arc.apps";
-// A preference to store backup and restore state for Android apps.
-const char kArcBackupRestoreEnabled[] = "arc.backup_restore.enabled";
-// A preference to indicate that Android's data directory should be removed.
-const char kArcDataRemoveRequested[] = "arc.data.remove_requested";
-// A preference representing whether a user has opted in to use Google Play
-// Store on ARC.
-// TODO(hidehiko): For historical reason, now the preference name does not
-// directly reflect "Google Play Store". We should get and set the values via
-// utility methods (IsArcPlayStoreEnabledForProfile() and
-// SetArcPlayStoreEnabledForProfile()) in chrome/browser/chromeos/arc/arc_util.
-const char kArcEnabled[] = "arc.enabled";
-// A preference that indicated whether Android reported it's compliance status
-// with provided policies. This is used only as a signal to start Android kiosk.
-const char kArcPolicyComplianceReported[] = "arc.policy_compliance_reported";
-// A preference that indicates that user accepted PlayStore terms.
-const char kArcTermsAccepted[] = "arc.terms.accepted";
-// A preference to keep user's consent to use location service.
-const char kArcLocationServiceEnabled[] = "arc.location_service.enabled";
-// A preference to keep list of Android packages and their infomation.
-const char kArcPackages[] = "arc.packages";
-// A preference that indicates that Play Auto Install flow was already started.
-const char kArcPaiStarted[] = "arc.pai.started";
-// A preference to keep deferred requests of setting notifications enabled flag.
-const char kArcSetNotificationsEnabledDeferred[] =
-    "arc.set_notifications_enabled_deferred";
-// A preference that indicates status of Android sign-in.
-const char kArcSignedIn[] = "arc.signedin";
-// A preference that indicates an ARC comaptible filesystem was chosen for
-// the user directory (i.e., the user finished required migration.)
-extern const char kArcCompatibleFilesystemChosen[] =
-    "arc.compatible_filesystem.chosen";
-// A preference that indicates that user accepted Voice Interaction Value Prop.
-const char kArcVoiceInteractionValuePropAccepted[] =
-    "arc.voice_interaction_value_prop.accepted";
-// A preference that indicates the user has enabled voice interaction services.
-const char kVoiceInteractionEnabled[] = "settings.voice_interaction.enabled";
-// A preference that indicates the user has allowed voice interaction services
-// to access the "context" (text and graphic content that is currently on
-// screen).
-const char kVoiceInteractionContextEnabled[] =
-    "settings.voice_interaction.context.enabled";
-// A preference indicating whether voice interaction settings have been read
-// from ARC. This synchronization only happens when user goes through the flow
-// to set up voice interaction.
-const char kVoiceInteractionPrefSynced[] =
-    "settings.voice_interaction.context.synced";
-#endif
-
 // A bool pref that keeps whether the child status for this profile was already
 // successfully checked via ChildAccountService.
 const char kChildAccountStatusKnown[] = "child_account_status_known";
@@ -957,9 +901,6 @@
 // If the string is empty or blank the system name will be used.
 const char kCastReceiverName[] = "cast_receiver.name";
 
-// Integer pref indicating the ecryptfs to ext4 migration strategy. One of
-// options: forbidden = 0, migrate = 1, wipe = 2 or ask the user = 3.
-const char kEcryptfsMigrationStrategy[] = "ecryptfs_migration_strategy";
 #endif  // defined(OS_CHROMEOS)
 
 // A boolean pref set to true if a Home button to open the Home pages should be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 9377387..f954c97 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -20,25 +20,6 @@
 namespace prefs {
 
 // Profile prefs. Please add Local State prefs below instead.
-#if defined(OS_CHROMEOS) && BUILDFLAG(ENABLE_APP_LIST)
-extern const char kArcActiveDirectoryPlayUserId[];
-extern const char kArcApps[];
-extern const char kArcBackupRestoreEnabled[];
-extern const char kArcDataRemoveRequested[];
-extern const char kArcEnabled[];
-extern const char kArcPolicyComplianceReported[];
-extern const char kArcTermsAccepted[];
-extern const char kArcLocationServiceEnabled[];
-extern const char kArcPackages[];
-extern const char kArcPaiStarted[];
-extern const char kArcSetNotificationsEnabledDeferred[];
-extern const char kArcSignedIn[];
-extern const char kArcCompatibleFilesystemChosen[];
-extern const char kArcVoiceInteractionValuePropAccepted[];
-extern const char kVoiceInteractionEnabled[];
-extern const char kVoiceInteractionContextEnabled[];
-extern const char kVoiceInteractionPrefSynced[];
-#endif
 extern const char kChildAccountStatusKnown[];
 extern const char kDefaultApps[];
 extern const char kSafeBrowsingForTrustedSourcesEnabled[];
@@ -316,7 +297,6 @@
 extern const char kInstantTetheringBleAdvertisingSupported[];
 extern const char kCastReceiverEnabled[];
 extern const char kCastReceiverName[];
-extern const char kEcryptfsMigrationStrategy[];
 #endif  // defined(OS_CHROMEOS)
 extern const char kShowHomeButton[];
 extern const char kSpeechRecognitionFilterProfanities[];
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index 5c64c7d4..cfd84e9 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -1,3 +1,25 @@
+# Shows the output of a given command only on failure, or when VERBOSE is set.
+log_cmd() {
+  if [ "${VERBOSE:-}" ]; then
+    "$@"
+  else
+    # Record $- into a separate variable because it gets reset in the subshell.
+    FORWARD_SHELL_OPTS=$-
+    ERREXIT=$(echo ${FORWARD_SHELL_OPTS} | grep -o e || true)
+    set +${ERREXIT}
+    CMD_OUTPUT=$("$@" 2>&1)
+    ERRCODE=$?
+    set -${ERREXIT}
+    if [ ${ERRCODE} -ne 0 ]; then
+      echo "$@"
+      echo "${CMD_OUTPUT}"
+      if [ ${ERREXIT} ]; then
+        exit ${ERRCODE}
+      fi
+    fi
+  fi
+}
+
 # Recursively replace @@include@@ template variables with the referenced file,
 # and write the resulting text to stdout.
 process_template_includes() {
@@ -104,7 +126,7 @@
 }
 
 stage_install_common() {
-  echo "Staging common install files in '${STAGEDIR}'..."
+  log_cmd echo "Staging common install files in '${STAGEDIR}'..."
 
   # TODO(mmoss) This assumes we built the static binaries. To support shared
   # builds, we probably want an install target in scons so it can give us all
diff --git a/chrome/installer/linux/debian/build.sh b/chrome/installer/linux/debian/build.sh
index 9d3d284..8bea7e6 100755
--- a/chrome/installer/linux/debian/build.sh
+++ b/chrome/installer/linux/debian/build.sh
@@ -4,9 +4,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# TODO(mmoss) This currently only works with official builds, since non-official
-# builds don't add the "${BUILDDIR}/installer/" files needed for packaging.
-
 set -e
 set -o pipefail
 if [ "$VERBOSE" ]; then
@@ -66,14 +63,14 @@
   fi
   prep_staging_debian
   stage_install_common
-  echo "Staging Debian install files in '${STAGEDIR}'..."
+  log_cmd echo "Staging Debian install files in '${STAGEDIR}'..."
   install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/cron"
   process_template "${BUILDDIR}/installer/common/repo.cron" \
       "${STAGEDIR}/${INSTALLDIR}/cron/${PACKAGE}"
   chmod 755 "${STAGEDIR}/${INSTALLDIR}/cron/${PACKAGE}"
-  pushd "${STAGEDIR}/etc/cron.daily/"
+  pushd "${STAGEDIR}/etc/cron.daily/" > /dev/null
   ln -snf "${INSTALLDIR}/cron/${PACKAGE}" "${PACKAGE}"
-  popd
+  popd > /dev/null
   process_template "${BUILDDIR}/installer/debian/debian.menu" \
     "${STAGEDIR}/usr/share/menu/${PACKAGE}.menu"
   chmod 644 "${STAGEDIR}/usr/share/menu/${PACKAGE}.menu"
@@ -106,7 +103,7 @@
 
 # Actually generate the package file.
 do_package() {
-  echo "Packaging ${ARCHITECTURE}..."
+  log_cmd echo "Packaging ${ARCHITECTURE}..."
   PREDEPENDS="$COMMON_PREDEPS"
   DEPENDS="${COMMON_DEPS}"
   REPLACES=""
@@ -123,13 +120,13 @@
   else
     local COMPRESSION_OPTS="-Znone"
   fi
-  fakeroot dpkg-deb ${COMPRESSION_OPTS} -b "${STAGEDIR}" .
+  log_cmd fakeroot dpkg-deb ${COMPRESSION_OPTS} -b "${STAGEDIR}" .
   verify_package "$DEPENDS"
 }
 
 # Remove temporary files and unwanted packaging output.
 cleanup() {
-  echo "Cleaning..."
+  log_cmd echo "Cleaning..."
   rm -rf "${STAGEDIR}"
   rm -rf "${TMPFILEDIR}"
 }
diff --git a/chrome/installer/linux/rpm/build.sh b/chrome/installer/linux/rpm/build.sh
index e96bd9a..de683c6 100755
--- a/chrome/installer/linux/rpm/build.sh
+++ b/chrome/installer/linux/rpm/build.sh
@@ -4,9 +4,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# TODO(mmoss) This currently only works with official builds, since non-official
-# builds don't add the "${BUILDDIR}/installer/" files needed for packaging.
-
 set -e
 if [ "$VERBOSE" ]; then
   set -x
@@ -48,7 +45,7 @@
   fi
   prep_staging_rpm
   stage_install_common
-  echo "Staging RPM install files in '${STAGEDIR}'..."
+  log_cmd echo "Staging RPM install files in '${STAGEDIR}'..."
   process_template "${BUILDDIR}/installer/common/rpmrepo.cron" \
     "${STAGEDIR}/etc/cron.daily/${PACKAGE}"
   chmod 755 "${STAGEDIR}/etc/cron.daily/${PACKAGE}"
@@ -80,7 +77,7 @@
 
 # Actually generate the package file.
 do_package() {
-  echo "Packaging ${ARCHITECTURE}..."
+  log_cmd echo "Packaging ${ARCHITECTURE}..."
   PROVIDES="${PACKAGE}"
   local REPS="$REPLACES"
   REPLACES=""
@@ -120,7 +117,7 @@
   # (brp-compress, etc.), which by default appears to only be enabled on 32-bit,
   # and which doesn't gain us anything since we already explicitly do all the
   # compression, symbol stripping, etc. that we want.
-  fakeroot rpmbuild -bb --target="$ARCHITECTURE" --rmspec \
+  log_cmd fakeroot rpmbuild -bb --target="$ARCHITECTURE" --rmspec \
     --define "_topdir $RPMBUILD_DIR" \
     --define "${COMPRESSION_OPT}" \
     --define "__os_install_post  %{nil}" \
diff --git a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
index 0274335..fe75a8b 100644
--- a/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
+++ b/chrome/test/data/extensions/api_test/networking_private/chromeos/test.js
@@ -945,6 +945,31 @@
               }));
         }));
   },
+  function selectCellularMobileNetwork() {
+    chrome.networkingPrivate.getProperties(
+        kCellularGuid, callbackPass(function(result) {
+          // Ensure that there are two found networks and the first is selected.
+          assertTrue(!!result.Cellular.FoundNetworks);
+          assertTrue(result.Cellular.FoundNetworks.length >= 2);
+          assertTrue(result.Cellular.FoundNetworks[0].Status == 'current');
+          assertTrue(result.Cellular.FoundNetworks[1].Status == 'available');
+          // Select the second network
+          var secondNetworkId = result.Cellular.FoundNetworks[1].NetworkId;
+          chrome.networkingPrivate.selectCellularMobileNetwork(
+              kCellularGuid, secondNetworkId, callbackPass(function() {
+                chrome.networkingPrivate.getProperties(
+                    kCellularGuid, callbackPass(function(result) {
+                      // Ensure that the second network is selected.
+                      assertTrue(!!result.Cellular.FoundNetworks);
+                      assertTrue(result.Cellular.FoundNetworks.length >= 2);
+                      assertEq(
+                          'available', result.Cellular.FoundNetworks[0].Status);
+                      assertEq(
+                          'current', result.Cellular.FoundNetworks[1].Status);
+                    }));
+              }));
+        }));
+  },
   function cellularSimPuk() {
     var newPin = '6666';
     var incorrectPin = '2222';
diff --git a/chrome/test/data/extensions/api_test/networking_private/test.js b/chrome/test/data/extensions/api_test/networking_private/test.js
index febf79e..241cb49a 100644
--- a/chrome/test/data/extensions/api_test/networking_private/test.js
+++ b/chrome/test/data/extensions/api_test/networking_private/test.js
@@ -128,6 +128,10 @@
     chrome.networkingPrivate.setCellularSimState(
         kGuid, simState, callbackPass(callbackResult));
   },
+  function selectCellularMobileNetwork() {
+    chrome.networkingPrivate.selectCellularMobileNetwork(
+        kGuid, 'fakeId', callbackPass(callbackResult));
+  },
   function getGlobalPolicy() {
     chrome.networkingPrivate.getGlobalPolicy(callbackPass(callbackResult));
   }
diff --git a/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js b/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js
index f8f4f43..9ec1152 100644
--- a/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js
+++ b/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js
@@ -25,8 +25,6 @@
 // Default accessibility audit options. Specify in test definition to use.
 SettingsAccessibilityTest.axeOptions = {
   'rules': {
-    // TODO(hcarmona): enable 'region' after addressing violation.
-    'region': {enabled: false},
     // Disable 'skip-link' check since there are few tab stops before the main
     // content.
     'skip-link': {enabled: false},
@@ -64,4 +62,4 @@
     PolymerTest.prototype.setUp.call(this);
     settings.ensureLazyLoaded();
   },
-};
\ No newline at end of file
+};
diff --git a/chrome/test/data/webui/settings/fake_networking_private.js b/chrome/test/data/webui/settings/fake_networking_private.js
index f067574..b0b10d7d 100644
--- a/chrome/test/data/webui/settings/fake_networking_private.js
+++ b/chrome/test/data/webui/settings/fake_networking_private.js
@@ -149,6 +149,9 @@
     setCellularSimState: assertNotReached,
 
     /** @override */
+    selectCellularMobileNetwork: assertNotReached,
+
+    /** @override */
     getGlobalPolicy: function(callback) {
       callback(this.globalPolicy_);
     },
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
index 1fe92e2..6a6912c 100644
--- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
+++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
@@ -60,7 +60,8 @@
     public void testStartStartsWebContentsActivity() {
         Assume.assumeFalse(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE);
 
-        CastWebContentsComponent component = new CastWebContentsComponent(INSTANCE_ID, null, null);
+        CastWebContentsComponent component =
+                new CastWebContentsComponent(INSTANCE_ID, null, null, false);
         component.start(mActivity, mWebContents);
         Intent intent = mShadowActivity.getNextStartedActivity();
         Assert.assertEquals(
@@ -80,7 +81,8 @@
         intentFilter.addDataPath("/" + INSTANCE_ID, PatternMatcher.PATTERN_LITERAL);
         LocalBroadcastManager.getInstance(mActivity).registerReceiver(receiver, intentFilter);
 
-        CastWebContentsComponent component = new CastWebContentsComponent(INSTANCE_ID, null, null);
+        CastWebContentsComponent component =
+                new CastWebContentsComponent(INSTANCE_ID, null, null, false);
         component.start(mActivity, mWebContents);
         component.stop(mActivity);
 
@@ -93,7 +95,8 @@
     public void testStartBindsWebContentsService() {
         Assume.assumeTrue(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE);
 
-        CastWebContentsComponent component = new CastWebContentsComponent(INSTANCE_ID, null, null);
+        CastWebContentsComponent component =
+                new CastWebContentsComponent(INSTANCE_ID, null, null, false);
         component.start(mActivity, mWebContents);
         component.stop(mActivity);
 
@@ -108,7 +111,8 @@
     public void testStopUnbindsWebContentsService() {
         Assume.assumeTrue(BuildConfig.DISPLAY_WEB_CONTENTS_IN_SERVICE);
 
-        CastWebContentsComponent component = new CastWebContentsComponent(INSTANCE_ID, null, null);
+        CastWebContentsComponent component =
+                new CastWebContentsComponent(INSTANCE_ID, null, null, false);
         component.start(mActivity, mWebContents);
         component.stop(mActivity);
 
@@ -121,7 +125,7 @@
                 Mockito.mock(CastWebContentsComponent.OnComponentClosedHandler.class);
 
         CastWebContentsComponent component =
-                new CastWebContentsComponent(INSTANCE_ID, callback, null);
+                new CastWebContentsComponent(INSTANCE_ID, callback, null, false);
         component.start(mActivity, mWebContents);
         CastWebContentsComponent.onComponentClosed(mActivity, INSTANCE_ID);
         verify(callback).onComponentClosed();
@@ -135,7 +139,7 @@
                 Mockito.mock(CastWebContentsComponent.OnKeyDownHandler.class);
 
         CastWebContentsComponent component =
-                new CastWebContentsComponent(INSTANCE_ID, null, callback);
+                new CastWebContentsComponent(INSTANCE_ID, null, callback, false);
         component.start(mActivity, mWebContents);
         CastWebContentsComponent.onKeyDown(mActivity, INSTANCE_ID, 42);
         component.stop(mActivity);
@@ -145,7 +149,8 @@
 
     @Test
     public void testStopDoesNotUnbindServiceIfStartWasNotCalled() {
-        CastWebContentsComponent component = new CastWebContentsComponent(INSTANCE_ID, null, null);
+        CastWebContentsComponent component =
+                new CastWebContentsComponent(INSTANCE_ID, null, null, false);
 
         component.stop(mActivity);
 
diff --git a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
index c729404..d181535 100644
--- a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/trace_event/trace_event.h"
 #include "chromecast/base/task_runner_impl.h"
+#include "chromecast/media/cma/backend/alsa/alsa_features.h"
 #include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h"
 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
 #include "chromecast/media/cma/base/decoder_buffer_base.h"
@@ -49,10 +50,21 @@
 const CastAudioDecoder::OutputFormat kDecoderSampleFormat =
     CastAudioDecoder::kOutputPlanarFloat;
 
+const int64_t kMicrosecondsPerSecond = 1000 * 1000;
 const int64_t kInvalidTimestamp = std::numeric_limits<int64_t>::min();
 
 const int64_t kNoPendingOutput = -1;
 
+int64_t MonotonicClockNow() {
+  timespec now = {0, 0};
+#if BUILDFLAG(ALSA_MONOTONIC_RAW_TSTAMPS)
+  clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+#else
+  clock_gettime(CLOCK_MONOTONIC, &now);
+#endif
+  return static_cast<int64_t>(now.tv_sec) * 1000000 + now.tv_nsec / 1000;
+}
+
 }  // namespace
 
 AudioDecoderAlsa::RateShifterInfo::RateShifterInfo(float playback_rate)
@@ -68,7 +80,11 @@
       mixer_error_(false),
       rate_shifter_output_(
           ::media::AudioBus::Create(kNumChannels, kDefaultFramesPerBuffer)),
-      current_pts_(kInvalidTimestamp),
+      first_push_pts_(kInvalidTimestamp),
+      last_push_pts_(kInvalidTimestamp),
+      last_push_timestamp_(kInvalidTimestamp),
+      last_push_pts_length_(0),
+      paused_pts_(kInvalidTimestamp),
       pending_output_frames_(kNoPendingOutput),
       volume_multiplier_(1.0f),
       pool_(new ::media::AudioBufferMemoryPool()),
@@ -97,7 +113,11 @@
   pending_buffer_complete_ = false;
   got_eos_ = false;
   pushed_eos_ = false;
-  current_pts_ = kInvalidTimestamp;
+  first_push_pts_ = kInvalidTimestamp;
+  last_push_pts_ = kInvalidTimestamp;
+  last_push_timestamp_ = kInvalidTimestamp;
+  last_push_pts_length_ = 0;
+  paused_pts_ = kInvalidTimestamp;
   pending_output_frames_ = kNoPendingOutput;
 
   last_mixer_delay_.timestamp_microseconds = kInvalidTimestamp;
@@ -106,7 +126,6 @@
 
 bool AudioDecoderAlsa::Start(int64_t start_pts) {
   TRACE_FUNCTION_ENTRY0();
-  current_pts_ = start_pts;
   DCHECK(IsValidConfig(config_));
   mixer_input_.reset(new StreamMixerAlsaInput(
       this, config_.samples_per_second, config_.playout_channel,
@@ -137,12 +156,14 @@
   TRACE_FUNCTION_ENTRY0();
   DCHECK(mixer_input_);
   mixer_input_->SetPaused(true);
+  paused_pts_ = GetCurrentPts();
   return true;
 }
 
 bool AudioDecoderAlsa::Resume() {
   TRACE_FUNCTION_ENTRY0();
   DCHECK(mixer_input_);
+  paused_pts_ = kInvalidTimestamp;
   mixer_input_->SetPaused(false);
   return true;
 }
@@ -170,6 +191,22 @@
   return true;
 }
 
+int64_t AudioDecoderAlsa::GetCurrentPts() const {
+  if (paused_pts_ != kInvalidTimestamp)
+    return paused_pts_;
+  if (last_push_pts_ == kInvalidTimestamp)
+    return kInvalidTimestamp;
+
+  DCHECK(!rate_shifter_info_.empty());
+  int64_t now = MonotonicClockNow();
+  int64_t estimate =
+      last_push_pts_ +
+      std::min(static_cast<int64_t>((now - last_push_timestamp_) *
+                                    rate_shifter_info_.front().rate),
+               last_push_pts_length_);
+  return (estimate < first_push_pts_ ? kInvalidTimestamp : estimate);
+}
+
 AudioDecoderAlsa::BufferStatus AudioDecoderAlsa::PushBuffer(
     CastDecoderBuffer* buffer) {
   TRACE_FUNCTION_ENTRY0();
@@ -182,9 +219,6 @@
   uint64_t input_bytes = buffer->end_of_stream() ? 0 : buffer->data_size();
   scoped_refptr<DecoderBufferBase> buffer_base(
       static_cast<DecoderBufferBase*>(buffer));
-  if (!buffer->end_of_stream()) {
-    current_pts_ = buffer->timestamp();
-  }
 
   // If the buffer is already decoded, do not attempt to decode. Call
   // OnBufferDecoded asynchronously on the main thread.
@@ -359,6 +393,23 @@
   } else {
     int input_frames = decoded->data_size() / (kNumChannels * sizeof(float));
 
+    last_push_pts_ = decoded->timestamp();
+    last_push_pts_length_ =
+        input_frames * kMicrosecondsPerSecond / config_.samples_per_second;
+    if (last_push_pts_ != kInvalidTimestamp) {
+      if (first_push_pts_ == kInvalidTimestamp) {
+        first_push_pts_ = last_push_pts_;
+      }
+
+      RenderingDelay delay = GetRenderingDelay();
+      if (delay.timestamp_microseconds == kInvalidTimestamp) {
+        last_push_pts_ = kInvalidTimestamp;
+      } else {
+        last_push_timestamp_ =
+            delay.timestamp_microseconds + delay.delay_microseconds;
+      }
+    }
+
     DCHECK(!rate_shifter_info_.empty());
     RateShifterInfo* rate_info = &rate_shifter_info_.front();
     // Bypass rate shifter if the rate is 1.0, and there are no frames queued
diff --git a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h
index c5560b6..e9872d1 100644
--- a/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h
+++ b/chromecast/media/cma/backend/alsa/audio_decoder_alsa.h
@@ -46,7 +46,7 @@
   bool Resume();
   bool SetPlaybackRate(float rate);
 
-  int64_t current_pts() const { return current_pts_; }
+  int64_t GetCurrentPts() const;
 
   // MediaPipelineBackend::AudioDecoder implementation:
   void SetDelegate(
@@ -104,7 +104,11 @@
   std::deque<RateShifterInfo> rate_shifter_info_;
   std::unique_ptr<::media::AudioBus> rate_shifter_output_;
 
-  int64_t current_pts_;
+  int64_t first_push_pts_;
+  int64_t last_push_pts_;
+  int64_t last_push_timestamp_;
+  int64_t last_push_pts_length_;
+  int64_t paused_pts_;
 
   std::unique_ptr<StreamMixerAlsaInput> mixer_input_;
   RenderingDelay last_mixer_delay_;
diff --git a/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc b/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc
index 118d6db99..5a7329dc 100644
--- a/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.cc
@@ -89,7 +89,7 @@
 
 int64_t MediaPipelineBackendAlsa::GetCurrentPts() {
   if (audio_decoder_)
-    return audio_decoder_->current_pts();
+    return audio_decoder_->GetCurrentPts();
   return std::numeric_limits<int64_t>::min();
 }
 
diff --git a/chromecast/media/cma/pipeline/BUILD.gn b/chromecast/media/cma/pipeline/BUILD.gn
index 0db8d65..92d4d4f 100644
--- a/chromecast/media/cma/pipeline/BUILD.gn
+++ b/chromecast/media/cma/pipeline/BUILD.gn
@@ -2,6 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
+import("//build/config/chromecast_build.gni")
+
+declare_args() {
+  # Set true to use accurate but more expensive method for GetMediaTime().
+  cma_use_accurate_media_time = is_cast_audio_only
+}
+
 source_set("pipeline") {
   sources = [
     "audio_decoder_software_wrapper.cc",
@@ -31,6 +39,7 @@
   ]
 
   deps = [
+    ":cma_pipeline_features",
     "//base",
     "//chromecast/base/metrics:metrics",
     "//chromecast/media/base",
@@ -44,3 +53,9 @@
     "//third_party/boringssl",
   ]
 }
+
+buildflag_header("cma_pipeline_features") {
+  header = "cma_pipeline_features.h"
+
+  flags = [ "CMA_USE_ACCURATE_MEDIA_TIME=$cma_use_accurate_media_time" ]
+}
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index aba86cf..d7a429b 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -22,6 +22,7 @@
 #include "chromecast/media/cma/base/coded_frame_provider.h"
 #include "chromecast/media/cma/pipeline/audio_decoder_software_wrapper.h"
 #include "chromecast/media/cma/pipeline/audio_pipeline_impl.h"
+#include "chromecast/media/cma/pipeline/cma_pipeline_features.h"
 #include "chromecast/media/cma/pipeline/video_pipeline_impl.h"
 #include "chromecast/public/media/media_pipeline_backend.h"
 #include "media/base/timestamp_constants.h"
@@ -228,7 +229,8 @@
       "Cast.Platform.Playing");
 
   // Enable time updates.
-  last_media_time_ = time;
+  start_media_time_ = time;
+  last_media_time_ = ::media::kNoTimestamp;
   statistics_rolling_counter_ = 0;
   if (!pending_time_update_task_) {
     pending_time_update_task_ = true;
@@ -320,7 +322,13 @@
 
 base::TimeDelta MediaPipelineImpl::GetMediaTime() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return last_media_time_;
+#if BUILDFLAG(CMA_USE_ACCURATE_MEDIA_TIME)
+  base::TimeDelta time = base::TimeDelta::FromMicroseconds(
+      media_pipeline_backend_->GetCurrentPts());
+#else
+  base::TimeDelta time = last_media_time_;
+#endif
+  return (time == ::media::kNoTimestamp ? start_media_time_ : time);
 }
 
 bool MediaPipelineImpl::HasAudio() const {
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h
index 940c423..5ed8644 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -110,6 +110,7 @@
 
   // The media time is retrieved at regular intervals.
   bool pending_time_update_task_;
+  base::TimeDelta start_media_time_;
   base::TimeDelta last_media_time_;
 
   // Used to make the statistics update period a multiplier of the time update
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index b80d07d..1930d091 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -215,6 +215,8 @@
     "dbus/fake_system_clock_client.h",
     "dbus/fake_upstart_client.cc",
     "dbus/fake_upstart_client.h",
+    "dbus/fake_virtual_file_provider_client.cc",
+    "dbus/fake_virtual_file_provider_client.h",
     "dbus/gsm_sms_client.cc",
     "dbus/gsm_sms_client.h",
     "dbus/image_burner_client.cc",
@@ -269,6 +271,8 @@
     "dbus/update_engine_client.h",
     "dbus/upstart_client.cc",
     "dbus/upstart_client.h",
+    "dbus/virtual_file_provider_client.cc",
+    "dbus/virtual_file_provider_client.h",
     "dbus/volume_state.cc",
     "dbus/volume_state.h",
     "disks/disk_mount_manager.cc",
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index aea75094..66534ea 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -25,11 +25,13 @@
 #include "chromeos/dbus/fake_lorgnette_manager_client.h"
 #include "chromeos/dbus/fake_media_analytics_client.h"
 #include "chromeos/dbus/fake_upstart_client.h"
+#include "chromeos/dbus/fake_virtual_file_provider_client.h"
 #include "chromeos/dbus/image_burner_client.h"
 #include "chromeos/dbus/image_loader_client.h"
 #include "chromeos/dbus/lorgnette_manager_client.h"
 #include "chromeos/dbus/media_analytics_client.h"
 #include "chromeos/dbus/upstart_client.h"
+#include "chromeos/dbus/virtual_file_provider_client.h"
 
 namespace chromeos {
 
@@ -92,6 +94,11 @@
     upstart_client_.reset(UpstartClient::Create());
   else
     upstart_client_.reset(new FakeUpstartClient);
+
+  if (use_real_clients)
+    virtual_file_provider_client_.reset(VirtualFileProviderClient::Create());
+  else
+    virtual_file_provider_client_.reset(new FakeVirtualFileProviderClient);
 }
 
 DBusClientsBrowser::~DBusClientsBrowser() {}
@@ -111,6 +118,7 @@
   lorgnette_manager_client_->Init(system_bus);
   media_analytics_client_->Init(system_bus);
   upstart_client_->Init(system_bus);
+  virtual_file_provider_client_->Init(system_bus);
 }
 
 }  // namespace chromeos
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index 5344846..cf4d014 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -28,6 +28,7 @@
 class LorgnetteManagerClient;
 class MediaAnalyticsClient;
 class UpstartClient;
+class VirtualFileProviderClient;
 
 // D-Bus clients used only in the browser process.
 // TODO(jamescook): Move this under //chrome/browser. http://crbug.com/647367
@@ -56,6 +57,7 @@
   std::unique_ptr<LorgnetteManagerClient> lorgnette_manager_client_;
   std::unique_ptr<MediaAnalyticsClient> media_analytics_client_;
   std::unique_ptr<UpstartClient> upstart_client_;
+  std::unique_ptr<VirtualFileProviderClient> virtual_file_provider_client_;
 
   DISALLOW_COPY_AND_ASSIGN(DBusClientsBrowser);
 };
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index e61c8f75..9fd9c48d 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -239,6 +239,12 @@
   return clients_browser_ ? clients_browser_->upstart_client_.get() : nullptr;
 }
 
+VirtualFileProviderClient* DBusThreadManager::GetVirtualFileProviderClient() {
+  return clients_browser_
+             ? clients_browser_->virtual_file_provider_client_.get()
+             : nullptr;
+}
+
 void DBusThreadManager::InitializeClients() {
   // Some clients call DBusThreadManager::Get() during initialization.
   DCHECK(g_dbus_thread_manager);
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index ee4e636f..9da19e9 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -56,6 +56,7 @@
 class SystemClockClient;
 class UpdateEngineClient;
 class UpstartClient;
+class VirtualFileProviderClient;
 
 // DBusThreadManager manages the D-Bus thread, the thread dedicated to
 // handling asynchronous D-Bus operations.
@@ -151,6 +152,7 @@
   SystemClockClient* GetSystemClockClient();
   UpdateEngineClient* GetUpdateEngineClient();
   UpstartClient* GetUpstartClient();
+  VirtualFileProviderClient* GetVirtualFileProviderClient();
 
  private:
   friend class DBusThreadManagerSetter;
diff --git a/chromeos/dbus/fake_shill_device_client.cc b/chromeos/dbus/fake_shill_device_client.cc
index 4aab386..e920b83 100644
--- a/chromeos/dbus/fake_shill_device_client.cc
+++ b/chromeos/dbus/fake_shill_device_client.cc
@@ -246,10 +246,22 @@
                                      const std::string& network_id,
                                      const base::Closure& callback,
                                      const ErrorCallback& error_callback) {
-  if (!stub_devices_.HasKey(device_path.value())) {
+  base::Value* device_properties = stub_devices_.FindKey(device_path.value());
+  if (!device_properties || !device_properties->is_dict()) {
     PostNotFoundError(error_callback);
     return;
   }
+  base::Value* scan_results =
+      device_properties->FindKey(shill::kFoundNetworksProperty);
+  if (!scan_results) {
+    PostError("No Cellular scan results", error_callback);
+    return;
+  }
+  for (auto& network : scan_results->GetList()) {
+    std::string id = network.FindKey(shill::kNetworkIdProperty)->GetString();
+    std::string status = id == network_id ? "current" : "available";
+    network.SetKey(shill::kStatusProperty, base::Value(status));
+  }
   base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
@@ -392,10 +404,6 @@
     properties->SetKey(shill::kCellularAllowRoamingProperty,
                        base::Value(false));
   }
-  if (type == shill::kTypeWifi) {
-    properties->SetKey(shill::kMACAddressRandomizationSupportedProperty,
-                       base::Value(false));
-  }
 }
 
 void FakeShillDeviceClient::RemoveDevice(const std::string& device_path) {
diff --git a/chromeos/dbus/fake_virtual_file_provider_client.cc b/chromeos/dbus/fake_virtual_file_provider_client.cc
new file mode 100644
index 0000000..2465291
--- /dev/null
+++ b/chromeos/dbus/fake_virtual_file_provider_client.cc
@@ -0,0 +1,19 @@
+// 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 "chromeos/dbus/fake_virtual_file_provider_client.h"
+
+#include "base/callback.h"
+
+namespace chromeos {
+
+FakeVirtualFileProviderClient::FakeVirtualFileProviderClient() = default;
+FakeVirtualFileProviderClient::~FakeVirtualFileProviderClient() = default;
+
+void FakeVirtualFileProviderClient::Init(dbus::Bus* bus) {}
+
+void FakeVirtualFileProviderClient::OpenFile(int64_t size,
+                                             OpenFileCallback callback) {}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_virtual_file_provider_client.h b/chromeos/dbus/fake_virtual_file_provider_client.h
new file mode 100644
index 0000000..958d3498
--- /dev/null
+++ b/chromeos/dbus/fake_virtual_file_provider_client.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_FAKE_VIRTUAL_FILE_PROVIDER_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_VIRTUAL_FILE_PROVIDER_CLIENT_H_
+
+#include "chromeos/dbus/virtual_file_provider_client.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT FakeVirtualFileProviderClient
+    : public VirtualFileProviderClient {
+ public:
+  FakeVirtualFileProviderClient();
+  ~FakeVirtualFileProviderClient() override;
+
+  // DBusClient override.
+  void Init(dbus::Bus* bus) override;
+
+  // VirtualFileProviderClient overrides:
+  void OpenFile(int64_t size, OpenFileCallback callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeVirtualFileProviderClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_VIRTUAL_FILE_PROVIDER_CLIENT_H_
diff --git a/chromeos/dbus/virtual_file_provider_client.cc b/chromeos/dbus/virtual_file_provider_client.cc
new file mode 100644
index 0000000..541575c
--- /dev/null
+++ b/chromeos/dbus/virtual_file_provider_client.cc
@@ -0,0 +1,84 @@
+// 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 "chromeos/dbus/virtual_file_provider_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+
+class VirtualFileProviderClientImpl : public VirtualFileProviderClient {
+ public:
+  VirtualFileProviderClientImpl() : weak_ptr_factory_(this) {}
+  ~VirtualFileProviderClientImpl() override = default;
+
+  // VirtualFileProviderClient override:
+  void OpenFile(int64_t size, OpenFileCallback callback) override {
+    dbus::MethodCall method_call(
+        virtual_file_provider::kVirtualFileProviderInterface,
+        virtual_file_provider::kOpenFileMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendInt64(size);
+    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+                       base::Bind(&VirtualFileProviderClientImpl::OnOpenFile,
+                                  weak_ptr_factory_.GetWeakPtr(),
+                                  base::Passed(std::move(callback))));
+  }
+
+ protected:
+  // DBusClient override.
+  void Init(dbus::Bus* bus) override {
+    proxy_ = bus->GetObjectProxy(
+        virtual_file_provider::kVirtualFileProviderServiceName,
+        dbus::ObjectPath(
+            virtual_file_provider::kVirtualFileProviderServicePath));
+  }
+
+ private:
+  // Runs the callback with OpenFile method call result.
+  void OnOpenFile(OpenFileCallback callback, dbus::Response* response) {
+    if (!response) {
+      std::move(callback).Run(std::string(), base::ScopedFD());
+      return;
+    }
+    dbus::MessageReader reader(response);
+    std::string id;
+    base::ScopedFD fd;
+    if (!reader.PopString(&id) || !reader.PopFileDescriptor(&fd)) {
+      LOG(ERROR) << "Invalid method call result.";
+      std::move(callback).Run(std::string(), base::ScopedFD());
+      return;
+    }
+    std::move(callback).Run(id, std::move(fd));
+  }
+
+  dbus::ObjectProxy* proxy_ = nullptr;
+
+  base::WeakPtrFactory<VirtualFileProviderClientImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(VirtualFileProviderClientImpl);
+};
+
+}  // namespace
+
+VirtualFileProviderClient::VirtualFileProviderClient() = default;
+
+VirtualFileProviderClient::~VirtualFileProviderClient() = default;
+
+// static
+VirtualFileProviderClient* VirtualFileProviderClient::Create() {
+  return new VirtualFileProviderClientImpl();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/virtual_file_provider_client.h b/chromeos/dbus/virtual_file_provider_client.h
new file mode 100644
index 0000000..e0c4ead
--- /dev/null
+++ b/chromeos/dbus/virtual_file_provider_client.h
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_VIRTUAL_FILE_PROVIDER_CLIENT_H_
+#define CHROMEOS_DBUS_VIRTUAL_FILE_PROVIDER_CLIENT_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_client.h"
+
+namespace chromeos {
+
+// VirtualFileProviderClient is used to communicate with the VirtualFileProvider
+// service. The VirtualFileProvider service provides file descriptors which
+// forward read requests to Chrome. From the reading process's perspective, the
+// file descriptor behaves like a regular file descriptor (unlike a pipe, it
+// supports seek), while actually there is no real file associated with it.
+class CHROMEOS_EXPORT VirtualFileProviderClient : public DBusClient {
+ public:
+  using OpenFileCallback =
+      base::OnceCallback<void(const std::string& id, base::ScopedFD fd)>;
+
+  VirtualFileProviderClient();
+  ~VirtualFileProviderClient() override;
+
+  // Factory function, creates a new instance and returns ownership.
+  // For normal usage, access the singleton via DBusThreadManager::Get().
+  static VirtualFileProviderClient* Create();
+
+  // Creates a new file descriptor and returns it with a unique ID.
+  // |size| will be used to perform boundary check when FD is seeked.
+  // When the FD is read, the read request is forwarded to the request handler.
+  virtual void OpenFile(int64_t size, OpenFileCallback callback) = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_VIRTUAL_FILE_PROVIDER_CLIENT_H_
diff --git a/chromeos/network/onc/onc_normalizer.cc b/chromeos/network/onc/onc_normalizer.cc
index 84ecaf1..3076748 100644
--- a/chromeos/network/onc/onc_normalizer.cc
+++ b/chromeos/network/onc/onc_normalizer.cc
@@ -229,6 +229,7 @@
   RemoveEntryUnless(vpn, kIPsec, type == kIPsec || type == kTypeL2TP_IPsec);
   RemoveEntryUnless(vpn, kL2TP, type == kTypeL2TP_IPsec);
   RemoveEntryUnless(vpn, kThirdPartyVpn, type == kThirdPartyVpn);
+  RemoveEntryUnless(vpn, kArcVpn, type == kArcVpn);
 }
 
 void Normalizer::NormalizeWiFi(base::DictionaryValue* wifi) {
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index 1a72037..84d7d06 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -146,6 +146,11 @@
     {::onc::third_party_vpn::kExtensionID, &kStringSignature},
     {NULL}};
 
+const OncFieldSignature arc_vpn_fields[] = {
+    {::onc::kRecommended, &kRecommendedSignature},
+    {::onc::arc_vpn::kTunnelChrome, &kStringSignature},
+    {NULL}};
+
 const OncFieldSignature verify_x509_fields[] = {
     {::onc::verify_x509::kName, &kStringSignature},
     {::onc::verify_x509::kType, &kStringSignature},
@@ -159,6 +164,7 @@
     {::onc::vpn::kL2TP, &kL2TPSignature},
     {::onc::vpn::kOpenVPN, &kOpenVPNSignature},
     {::onc::vpn::kThirdPartyVpn, &kThirdPartyVPNSignature},
+    {::onc::vpn::kArcVpn, &kARCVPNSignature},
     {::onc::vpn::kType, &kStringSignature},
     {NULL}};
 
@@ -401,6 +407,8 @@
                                              openvpn_fields, NULL};
 const OncValueSignature kThirdPartyVPNSignature = {
     base::Value::Type::DICTIONARY, third_party_vpn_fields, NULL};
+const OncValueSignature kARCVPNSignature = {base::Value::Type::DICTIONARY,
+                                            arc_vpn_fields, NULL};
 const OncValueSignature kVerifyX509Signature = {base::Value::Type::DICTIONARY,
                                                 verify_x509_fields, NULL};
 const OncValueSignature kVPNSignature = {base::Value::Type::DICTIONARY,
diff --git a/chromeos/network/onc/onc_signature.h b/chromeos/network/onc/onc_signature.h
index 9b7a732..7b7974d 100644
--- a/chromeos/network/onc/onc_signature.h
+++ b/chromeos/network/onc/onc_signature.h
@@ -43,6 +43,7 @@
 CHROMEOS_EXPORT extern const OncValueSignature kXAUTHSignature;
 CHROMEOS_EXPORT extern const OncValueSignature kOpenVPNSignature;
 CHROMEOS_EXPORT extern const OncValueSignature kThirdPartyVPNSignature;
+CHROMEOS_EXPORT extern const OncValueSignature kARCVPNSignature;
 CHROMEOS_EXPORT extern const OncValueSignature kVerifyX509Signature;
 CHROMEOS_EXPORT extern const OncValueSignature kVPNSignature;
 CHROMEOS_EXPORT extern const OncValueSignature kEthernetSignature;
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc
index 6e13d31e..27e5853 100644
--- a/chromeos/network/onc/onc_translation_tables.cc
+++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -101,6 +101,10 @@
     {::onc::openvpn::kVerifyHash, shill::kOpenVPNVerifyHashProperty},
     {NULL}};
 
+const FieldTranslationEntry arc_vpn_fields[] = {
+    {::onc::arc_vpn::kTunnelChrome, shill::kArcVpnTunnelChromeProperty},
+    {NULL}};
+
 const FieldTranslationEntry verify_x509_fields[] = {
     {::onc::verify_x509::kName, shill::kOpenVPNVerifyX509NameProperty},
     {::onc::verify_x509::kType, shill::kOpenVPNVerifyX509TypeProperty},
@@ -251,6 +255,7 @@
     {&kL2TPSignature, l2tp_fields},
     {&kXAUTHSignature, xauth_fields},
     {&kOpenVPNSignature, openvpn_fields},
+    {&kARCVPNSignature, arc_vpn_fields},
     {&kVerifyX509Signature, verify_x509_fields},
     {&kVPNSignature, vpn_fields},
     {&kTetherSignature, tether_fields},
@@ -306,6 +311,7 @@
     {::onc::vpn::kTypeL2TP_IPsec, shill::kProviderL2tpIpsec},
     {::onc::vpn::kOpenVPN, shill::kProviderOpenVpn},
     {::onc::vpn::kThirdPartyVpn, shill::kProviderThirdPartyVpn},
+    {::onc::vpn::kArcVpn, shill::kProviderArcVpn},
     {NULL}};
 
 const StringTranslationEntry kWiFiSecurityTable[] = {
diff --git a/chromeos/network/onc/onc_translator_shill_to_onc.cc b/chromeos/network/onc/onc_translator_shill_to_onc.cc
index 0ae0c73..831c351 100644
--- a/chromeos/network/onc/onc_translator_shill_to_onc.cc
+++ b/chromeos/network/onc/onc_translator_shill_to_onc.cc
@@ -322,6 +322,7 @@
 
   bool save_credentials;
   if (onc_provider_type != ::onc::vpn::kThirdPartyVpn &&
+      onc_provider_type != ::onc::vpn::kArcVpn &&
       shill_dictionary_->GetBooleanWithoutPathExpansion(
           shill::kSaveCredentialsProperty, &save_credentials)) {
     SetNestedOncValue(provider_type_dictionary, ::onc::vpn::kSaveCredentials,
diff --git a/chromeos/network/onc/onc_translator_unittest.cc b/chromeos/network/onc/onc_translator_unittest.cc
index fea3e09..8701a890 100644
--- a/chromeos/network/onc/onc_translator_unittest.cc
+++ b/chromeos/network/onc/onc_translator_unittest.cc
@@ -68,7 +68,8 @@
                        "shill_openvpn_clientcert.json"),
         std::make_pair("cellular.onc", "shill_cellular.json"),
         std::make_pair("wimax.onc", "shill_wimax.json"),
-        std::make_pair("third_party_vpn.onc", "shill_third_party_vpn.json")));
+        std::make_pair("third_party_vpn.onc", "shill_third_party_vpn.json"),
+        std::make_pair("arc_vpn.onc", "shill_arc_vpn.json")));
 
 // First parameter: Filename of source Shill json.
 // Second parameter: Filename of expected translated ONC network part.
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc
index f0dde18..d2f69fd 100644
--- a/chromeos/network/onc/onc_validator.cc
+++ b/chromeos/network/onc/onc_validator.cc
@@ -116,6 +116,8 @@
       valid = ValidateOpenVPN(repaired.get());
     } else if (&signature == &kThirdPartyVPNSignature) {
       valid = ValidateThirdPartyVPN(repaired.get());
+    } else if (&signature == &kARCVPNSignature) {
+      valid = ValidateARCVPN(repaired.get());
     } else if (&signature == &kVerifyX509Signature) {
       valid = ValidateVerifyX509(repaired.get());
     } else if (&signature == &kCertificatePatternSignature) {
@@ -696,8 +698,8 @@
 bool Validator::ValidateVPN(base::DictionaryValue* result) {
   using namespace ::onc::vpn;
 
-  const char* const kValidTypes[] = {
-      kIPsec, kTypeL2TP_IPsec, kOpenVPN, kThirdPartyVpn};
+  const char* const kValidTypes[] = {kIPsec, kTypeL2TP_IPsec, kOpenVPN,
+                                     kThirdPartyVpn, kArcVpn};
   const std::vector<const char*> valid_types(toVector(kValidTypes));
   if (FieldExistsAndHasNoValidValue(*result, ::onc::vpn::kType, valid_types))
     return false;
@@ -714,6 +716,8 @@
         RequireField(*result, kIPsec) && RequireField(*result, kL2TP);
   } else if (type == kThirdPartyVpn) {
     all_required_exist &= RequireField(*result, kThirdPartyVpn);
+  } else if (type == kArcVpn) {
+    all_required_exist &= RequireField(*result, kArcVpn);
   }
 
   return !error_on_missing_field_ || all_required_exist;
@@ -825,6 +829,13 @@
   return !error_on_missing_field_ || all_required_exist;
 }
 
+bool Validator::ValidateARCVPN(base::DictionaryValue* result) {
+  const bool all_required_exist =
+      RequireField(*result, ::onc::arc_vpn::kTunnelChrome);
+
+  return !error_on_missing_field_ || all_required_exist;
+}
+
 bool Validator::ValidateVerifyX509(base::DictionaryValue* result) {
   using namespace ::onc::verify_x509;
 
diff --git a/chromeos/network/onc/onc_validator.h b/chromeos/network/onc/onc_validator.h
index 0610a6bf..b9e8f67 100644
--- a/chromeos/network/onc/onc_validator.h
+++ b/chromeos/network/onc/onc_validator.h
@@ -164,6 +164,7 @@
   bool ValidateIPsec(base::DictionaryValue* result);
   bool ValidateOpenVPN(base::DictionaryValue* result);
   bool ValidateThirdPartyVPN(base::DictionaryValue* result);
+  bool ValidateARCVPN(base::DictionaryValue* result);
   bool ValidateVerifyX509(base::DictionaryValue* result);
   bool ValidateCertificatePattern(base::DictionaryValue* result);
   bool ValidateGlobalNetworkConfiguration(base::DictionaryValue* result);
diff --git a/chromeos/network/onc/onc_validator_unittest.cc b/chromeos/network/onc/onc_validator_unittest.cc
index e6f1d7c..846272ecf 100644
--- a/chromeos/network/onc/onc_validator_unittest.cc
+++ b/chromeos/network/onc/onc_validator_unittest.cc
@@ -226,6 +226,7 @@
         OncParams("third_party_vpn.onc",
                   &kNetworkConfigurationSignature,
                   false),
+        OncParams("arc_vpn.onc", &kNetworkConfigurationSignature, false),
         OncParams("tether.onc", &kNetworkWithStateSignature, false)));
 
 namespace {
diff --git a/chromeos/test/data/network/arc_vpn.onc b/chromeos/test/data/network/arc_vpn.onc
new file mode 100644
index 0000000..6ad9b2c
--- /dev/null
+++ b/chromeos/test/data/network/arc_vpn.onc
@@ -0,0 +1,21 @@
+{
+    "GUID": "guid",
+    "Name": "ARC VPN",
+    "Type": "VPN",
+    "VPN": {
+        "Type": "ARCVPN",
+        "ARCVPN": {
+            "TunnelChrome": "true",
+        }
+    },
+    "StaticIPConfig": {
+        "Type": "IPv4",
+        "IPAddress": "192.168.10.6",
+        "RoutingPrefix": 24,
+        "Gateway": "192.168.10.1",
+        "IncludedRoutes": [ "192.168.11.0/24", "192.168.12.0/24" ],
+        "ExcludedRoutes": [ "192.168.1.0/24" ],
+        "NameServers": [ "8.8.8.8", "8.8.4.4" ],
+        "SearchDomains": [ "example.com" ],
+    }
+}
diff --git a/chromeos/test/data/network/shill_arc_vpn.json b/chromeos/test/data/network/shill_arc_vpn.json
new file mode 100644
index 0000000..115d7366
--- /dev/null
+++ b/chromeos/test/data/network/shill_arc_vpn.json
@@ -0,0 +1,16 @@
+{
+   "GUID": "guid",
+   "Name": "ARC VPN",
+   "Type": "vpn",
+   "Provider.Type": "arcvpn",
+   "ArcVpn.TunnelChrome": "true",
+   "StaticIPConfig": {
+      "Address": "192.168.10.6",
+      "Prefixlen": 24,
+      "Gateway": "192.168.10.1",
+      "IncludedRoutes": [ "192.168.11.0/24", "192.168.12.0/24" ],
+      "ExcludedRoutes": [ "192.168.1.0/24" ],
+      "NameServers": [ "8.8.8.8", "8.8.4.4" ],
+      "SearchDomains": [ "example.com" ]
+   }
+}
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 20a8b24..85d42ad 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -61,6 +61,7 @@
 
   public_deps = [
     ":arc_base",
+    ":prefs",
   ]
 
   deps = [
@@ -93,6 +94,20 @@
   ]
 }
 
+static_library("prefs") {
+  sources = [
+    "arc_export.h",
+    "arc_prefs.cc",
+    "arc_prefs.h",
+  ]
+
+  defines = [ "ARC_IMPLEMENTATION" ]
+
+  deps = [
+    "//components/pref_registry",
+  ]
+}
+
 static_library("arc_base") {
   # TODO(hidehiko): Revisit here and move back some files to "arc"
   # on completion to move ArcSession task to ArcSessionManager.
diff --git a/components/arc/DEPS b/components/arc/DEPS
index 9e1e368..cbf51bdb 100644
--- a/components/arc/DEPS
+++ b/components/arc/DEPS
@@ -5,6 +5,7 @@
   "+chromeos/dbus",
   "+components/exo",
   "+components/keyed_service",
+  "+components/pref_registry",
   "+components/prefs",
   "+components/session_manager/core",
   "+components/signin/core/account_id",
diff --git a/components/arc/arc_export.h b/components/arc/arc_export.h
new file mode 100644
index 0000000..d1a9fae3
--- /dev/null
+++ b/components/arc/arc_export.h
@@ -0,0 +1,18 @@
+// 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_ARC_ARC_EXPORT_H_
+#define COMPONENTS_ARC_ARC_EXPORT_H_
+
+#if !defined(OS_CHROMEOS)
+#error "ARC can be built only for Chrome OS."
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(COMPONENT_BUILD) && defined(ARC_IMPLEMENTATION)
+#define ARC_EXPORT __attribute__((visibility("default")))
+#else  // !defined(COMPONENT_BUILD) || !defined(ARC_IMPLEMENTATION)
+#define ARC_EXPORT
+#endif
+
+#endif  // COMPONENTS_ARC_ARC_EXPORT_H_
diff --git a/components/arc/arc_prefs.cc b/components/arc/arc_prefs.cc
new file mode 100644
index 0000000..34db454
--- /dev/null
+++ b/components/arc/arc_prefs.cc
@@ -0,0 +1,103 @@
+// 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/arc/arc_prefs.h"
+
+#include <string>
+
+#include "components/pref_registry/pref_registry_syncable.h"
+
+namespace arc {
+namespace prefs {
+
+// Stores the user id received from DM Server when enrolling a Play user on an
+// Active Directory managed device. Used to report to DM Server that the account
+// is still used.
+const char kArcActiveDirectoryPlayUserId[] =
+    "arc.active_directory_play_user_id";
+// A preference to keep list of Android apps and their state.
+const char kArcApps[] = "arc.apps";
+// A preference to store backup and restore state for Android apps.
+const char kArcBackupRestoreEnabled[] = "arc.backup_restore.enabled";
+// A preference to indicate that Android's data directory should be removed.
+const char kArcDataRemoveRequested[] = "arc.data.remove_requested";
+// A preference representing whether a user has opted in to use Google Play
+// Store on ARC.
+// TODO(hidehiko): For historical reason, now the preference name does not
+// directly reflect "Google Play Store". We should get and set the values via
+// utility methods (IsArcPlayStoreEnabledForProfile() and
+// SetArcPlayStoreEnabledForProfile()) in chrome/browser/chromeos/arc/arc_util.
+const char kArcEnabled[] = "arc.enabled";
+// A preference that indicated whether Android reported it's compliance status
+// with provided policies. This is used only as a signal to start Android kiosk.
+const char kArcPolicyComplianceReported[] = "arc.policy_compliance_reported";
+// A preference that indicates that user accepted PlayStore terms.
+const char kArcTermsAccepted[] = "arc.terms.accepted";
+// A preference to keep user's consent to use location service.
+const char kArcLocationServiceEnabled[] = "arc.location_service.enabled";
+// A preference to keep list of Android packages and their infomation.
+const char kArcPackages[] = "arc.packages";
+// A preference that indicates that Play Auto Install flow was already started.
+const char kArcPaiStarted[] = "arc.pai.started";
+// A preference to keep deferred requests of setting notifications enabled flag.
+const char kArcSetNotificationsEnabledDeferred[] =
+    "arc.set_notifications_enabled_deferred";
+// A preference that indicates status of Android sign-in.
+const char kArcSignedIn[] = "arc.signedin";
+// A preference that indicates an ARC comaptible filesystem was chosen for
+// the user directory (i.e., the user finished required migration.)
+extern const char kArcCompatibleFilesystemChosen[] =
+    "arc.compatible_filesystem.chosen";
+// A preference that indicates that user accepted Voice Interaction Value Prop.
+const char kArcVoiceInteractionValuePropAccepted[] =
+    "arc.voice_interaction_value_prop.accepted";
+// Integer pref indicating the ecryptfs to ext4 migration strategy. One of
+// options: forbidden = 0, migrate = 1, wipe = 2 or ask the user = 3.
+const char kEcryptfsMigrationStrategy[] = "ecryptfs_migration_strategy";
+// A preference that indicates the user has enabled voice interaction services.
+const char kVoiceInteractionEnabled[] = "settings.voice_interaction.enabled";
+// A preference that indicates the user has allowed voice interaction services
+// to access the "context" (text and graphic content that is currently on
+// screen).
+const char kVoiceInteractionContextEnabled[] =
+    "settings.voice_interaction.context.enabled";
+// A preference indicating whether voice interaction settings have been read
+// from ARC. This synchronization only happens when user goes through the flow
+// to set up voice interaction.
+const char kVoiceInteractionPrefSynced[] =
+    "settings.voice_interaction.context.synced";
+
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
+  // TODO(dspaid): Implement a mechanism to allow this to sync on first boot
+  // only.
+
+  // This is used to delete the Play user ID if ARC is disabled for an
+  // Active Directory managed device.
+  registry->RegisterStringPref(kArcActiveDirectoryPlayUserId, std::string());
+
+  // Note that ArcBackupRestoreEnabled and ArcLocationServiceEnabled prefs have
+  // to be off by default, until an explicit gesture from the user to enable
+  // them is received. This is crucial in the cases when these prefs transition
+  // from a previous managed state to the unmanaged.
+  registry->RegisterBooleanPref(kArcBackupRestoreEnabled, false);
+  registry->RegisterBooleanPref(kArcLocationServiceEnabled, false);
+
+  // This is used to decide whether migration from ecryptfs to ext4 is allowed.
+  registry->RegisterIntegerPref(prefs::kEcryptfsMigrationStrategy, 0);
+
+  // Sorted in lexicographical order.
+  registry->RegisterBooleanPref(kArcDataRemoveRequested, false);
+  registry->RegisterBooleanPref(kArcEnabled, false);
+  registry->RegisterBooleanPref(kArcPaiStarted, false);
+  registry->RegisterBooleanPref(kArcPolicyComplianceReported, false);
+  registry->RegisterBooleanPref(kArcSignedIn, false);
+  registry->RegisterBooleanPref(kArcTermsAccepted, false);
+  registry->RegisterBooleanPref(kArcVoiceInteractionValuePropAccepted, false);
+  registry->RegisterBooleanPref(kVoiceInteractionContextEnabled, false);
+  registry->RegisterBooleanPref(kVoiceInteractionEnabled, false);
+  registry->RegisterBooleanPref(kVoiceInteractionPrefSynced, false);
+}
+
+}  // namespace prefs
+}  // namespace arc
diff --git a/components/arc/arc_prefs.h b/components/arc/arc_prefs.h
new file mode 100644
index 0000000..6e82dfa
--- /dev/null
+++ b/components/arc/arc_prefs.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ARC_ARC_PREFS_H_
+#define COMPONENTS_ARC_ARC_PREFS_H_
+
+#include "components/arc/arc_export.h"
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}  // namespace user_prefs
+
+namespace arc {
+namespace prefs {
+
+// Sorted in lexicographical order.
+ARC_EXPORT extern const char kArcActiveDirectoryPlayUserId[];
+ARC_EXPORT extern const char kArcApps[];
+ARC_EXPORT extern const char kArcBackupRestoreEnabled[];
+ARC_EXPORT extern const char kArcDataRemoveRequested[];
+ARC_EXPORT extern const char kArcEnabled[];
+ARC_EXPORT extern const char kArcPolicyComplianceReported[];
+ARC_EXPORT extern const char kArcTermsAccepted[];
+ARC_EXPORT extern const char kArcLocationServiceEnabled[];
+ARC_EXPORT extern const char kArcPackages[];
+ARC_EXPORT extern const char kArcPaiStarted[];
+ARC_EXPORT extern const char kArcSetNotificationsEnabledDeferred[];
+ARC_EXPORT extern const char kArcSignedIn[];
+ARC_EXPORT extern const char kArcCompatibleFilesystemChosen[];
+ARC_EXPORT extern const char kArcVoiceInteractionValuePropAccepted[];
+ARC_EXPORT extern const char kEcryptfsMigrationStrategy[];
+ARC_EXPORT extern const char kVoiceInteractionEnabled[];
+ARC_EXPORT extern const char kVoiceInteractionContextEnabled[];
+ARC_EXPORT extern const char kVoiceInteractionPrefSynced[];
+
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+}  // namespace prefs
+}  // namespace arc
+
+#endif  // COMPONENTS_ARC_ARC_PREFS_H_
diff --git a/components/arc/common/video_encode_accelerator.mojom b/components/arc/common/video_encode_accelerator.mojom
index 98fe048..2aaf61e5 100644
--- a/components/arc/common/video_encode_accelerator.mojom
+++ b/components/arc/common/video_encode_accelerator.mojom
@@ -56,7 +56,10 @@
   DOLBYVISION_PROFILE5 = 21,
   DOLBYVISION_PROFILE7 = 22,
   DOLBYVISION_MAX = DOLBYVISION_PROFILE7,
-  VIDEO_CODEC_PROFILE_MAX = DOLBYVISION_MAX,
+  THEORAPROFILE_MIN = 23,
+  THEORAPROFILE_ANY = THEORAPROFILE_MIN,
+  THEORAPROFILE_MAX = THEORAPROFILE_ANY,
+  VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY,
 };
 
 // Specification of an encoding profile supported by an encoder.
diff --git a/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc b/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc
index 32a5737..9b3c645 100644
--- a/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc
+++ b/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc
@@ -113,6 +113,9 @@
 CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE5);
 CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE7);
 CHECK_PROFILE_ENUM(DOLBYVISION_MAX);
+CHECK_PROFILE_ENUM(THEORAPROFILE_MIN);
+CHECK_PROFILE_ENUM(THEORAPROFILE_ANY);
+CHECK_PROFILE_ENUM(THEORAPROFILE_MAX);
 CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_MAX);
 
 #undef CHECK_PROFILE_ENUM
@@ -153,6 +156,7 @@
     case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE4:
     case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE5:
     case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7:
+    case arc::mojom::VideoCodecProfile::THEORAPROFILE_ANY:
       *output = static_cast<media::VideoCodecProfile>(input);
       return true;
   }
diff --git a/components/exo/data_offer_unittest.cc b/components/exo/data_offer_unittest.cc
index 34c3212..7a00294 100644
--- a/components/exo/data_offer_unittest.cc
+++ b/components/exo/data_offer_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "components/exo/data_offer.h"
 
+#include <fcntl.h>
+#include <stdio.h>
+
 #include <memory>
 #include <string>
 #include <vector>
@@ -15,8 +18,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/exo/data_device.h"
 #include "components/exo/data_offer_delegate.h"
+#include "components/exo/file_helper.h"
 #include "components/exo/test/exo_test_base.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
+#include "url/gurl.h"
 
 namespace exo {
 namespace {
@@ -59,33 +64,120 @@
   DISALLOW_COPY_AND_ASSIGN(TestDataOfferDelegate);
 };
 
-TEST_F(DataOfferTest, SendEvents) {
-  ui::OSExchangeData data;
-  data.SetString(base::string16(base::ASCIIToUTF16("Test data")));
+class TestFileHelper : public FileHelper {
+ public:
+  TestFileHelper() = default;
 
+  // Overridden from FileHelper:
+  std::string GetMimeTypeForUriList() const override { return "text/uri-list"; }
+  bool ConvertPathToUrl(const base::FilePath& path, GURL* out) override {
+    *out = GURL("file://" + path.AsUTF8Unsafe());
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestFileHelper);
+};
+
+void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
+  int raw_pipe[2];
+  PCHECK(0 == pipe(raw_pipe));
+  read_pipe->reset(raw_pipe[0]);
+  write_pipe->reset(raw_pipe[1]);
+}
+
+bool ReadString16(base::ScopedFD fd, base::string16* out) {
+  std::array<char, 128> buffer;
+  char* it = buffer.begin();
+  while (it != buffer.end()) {
+    int result = read(fd.get(), it, buffer.end() - it);
+    PCHECK(-1 != result);
+    if (result == 0)
+      break;
+    it += result;
+  }
+  *out = base::string16(reinterpret_cast<base::char16*>(buffer.data()),
+                        (it - buffer.begin()) / sizeof(base::char16));
+  return true;
+}
+
+TEST_F(DataOfferTest, SetTextDropData) {
   base::flat_set<DndAction> source_actions;
   source_actions.insert(DndAction::kCopy);
   source_actions.insert(DndAction::kMove);
 
-  std::unique_ptr<TestDataOfferDelegate> delegate =
-      base::MakeUnique<TestDataOfferDelegate>();
-  std::unique_ptr<DataOffer> data_offer =
-      base::MakeUnique<DataOffer>(delegate.get());
+  ui::OSExchangeData data;
+  data.SetString(base::string16(base::ASCIIToUTF16("Test data")));
 
-  EXPECT_EQ(0u, delegate->mime_types().size());
-  EXPECT_EQ(0u, delegate->source_actions().size());
-  EXPECT_EQ(DndAction::kNone, delegate->dnd_action());
+  TestDataOfferDelegate delegate;
+  DataOffer data_offer(&delegate);
 
-  data_offer->SetDropData(nullptr, data);
-  data_offer->SetSourceActions(source_actions);
-  data_offer->SetActions(base::flat_set<DndAction>(), DndAction::kMove);
+  EXPECT_EQ(0u, delegate.mime_types().size());
+  EXPECT_EQ(0u, delegate.source_actions().size());
+  EXPECT_EQ(DndAction::kNone, delegate.dnd_action());
 
-  EXPECT_EQ(1u, delegate->mime_types().size());
-  EXPECT_EQ("text/plain", delegate->mime_types()[0]);
-  EXPECT_EQ(2u, delegate->source_actions().size());
-  EXPECT_EQ(1u, delegate->source_actions().count(DndAction::kCopy));
-  EXPECT_EQ(1u, delegate->source_actions().count(DndAction::kMove));
-  EXPECT_EQ(DndAction::kMove, delegate->dnd_action());
+  TestFileHelper file_helper;
+  data_offer.SetDropData(&file_helper, data);
+  data_offer.SetSourceActions(source_actions);
+  data_offer.SetActions(base::flat_set<DndAction>(), DndAction::kMove);
+
+  EXPECT_EQ(1u, delegate.mime_types().size());
+  EXPECT_EQ("text/plain", delegate.mime_types()[0]);
+  EXPECT_EQ(2u, delegate.source_actions().size());
+  EXPECT_EQ(1u, delegate.source_actions().count(DndAction::kCopy));
+  EXPECT_EQ(1u, delegate.source_actions().count(DndAction::kMove));
+  EXPECT_EQ(DndAction::kMove, delegate.dnd_action());
+}
+
+TEST_F(DataOfferTest, SetFileDropData) {
+  TestDataOfferDelegate delegate;
+  DataOffer data_offer(&delegate);
+
+  TestFileHelper file_helper;
+  ui::OSExchangeData data;
+  data.SetFilename(base::FilePath("/test/downloads/file"));
+  data_offer.SetDropData(&file_helper, data);
+
+  EXPECT_EQ(1u, delegate.mime_types().size());
+  EXPECT_EQ("text/uri-list", delegate.mime_types()[0]);
+}
+
+TEST_F(DataOfferTest, ReceiveString) {
+  TestDataOfferDelegate delegate;
+  DataOffer data_offer(&delegate);
+
+  TestFileHelper file_helper;
+  ui::OSExchangeData data;
+  data.SetString(base::ASCIIToUTF16("Test data"));
+  data_offer.SetDropData(&file_helper, data);
+
+  base::ScopedFD read_pipe;
+  base::ScopedFD write_pipe;
+  CreatePipe(&read_pipe, &write_pipe);
+
+  data_offer.Receive("text/plain", std::move(write_pipe));
+  base::string16 result;
+  ASSERT_TRUE(ReadString16(std::move(read_pipe), &result));
+  EXPECT_EQ(base::ASCIIToUTF16("Test data"), result);
+}
+
+TEST_F(DataOfferTest, ReceiveUriList) {
+  TestDataOfferDelegate delegate;
+  DataOffer data_offer(&delegate);
+
+  TestFileHelper file_helper;
+  ui::OSExchangeData data;
+  data.SetFilename(base::FilePath("/test/downloads/file"));
+  data_offer.SetDropData(&file_helper, data);
+
+  base::ScopedFD read_pipe;
+  base::ScopedFD write_pipe;
+  CreatePipe(&read_pipe, &write_pipe);
+
+  data_offer.Receive("text/uri-list", std::move(write_pipe));
+  base::string16 result;
+  ASSERT_TRUE(ReadString16(std::move(read_pipe), &result));
+  EXPECT_EQ(base::ASCIIToUTF16("file:///test/downloads/file"), result);
 }
 
 }  // namespace
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc
index c3f6cd51..81c05fd 100644
--- a/components/onc/onc_constants.cc
+++ b/components/onc/onc_constants.cc
@@ -327,6 +327,7 @@
 const char kPassword[] = "Password";
 const char kSaveCredentials[] = "SaveCredentials";
 const char kThirdPartyVpn[] = "ThirdPartyVPN";
+const char kArcVpn[] = "ARCVPN";
 const char kTypeL2TP_IPsec[] = "L2TP-IPsec";
 const char kType[] = "Type";
 const char kUsername[] = "Username";
@@ -403,6 +404,10 @@
 const char kProviderName[] = "ProviderName";
 }  // third_party_vpn
 
+namespace arc_vpn {
+const char kTunnelChrome[] = "TunnelChrome";
+}  // namespace arc_vpn
+
 namespace verify_x509 {
 const char kName[] = "Name";
 const char kType[] = "Type";
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h
index 94b3e7c..71454a8f 100644
--- a/components/onc/onc_constants.h
+++ b/components/onc/onc_constants.h
@@ -340,6 +340,7 @@
 ONC_EXPORT extern const char kPassword[];
 ONC_EXPORT extern const char kSaveCredentials[];
 ONC_EXPORT extern const char kThirdPartyVpn[];
+ONC_EXPORT extern const char kArcVpn[];
 ONC_EXPORT extern const char kTypeL2TP_IPsec[];
 ONC_EXPORT extern const char kType[];
 ONC_EXPORT extern const char kUsername[];
@@ -416,6 +417,10 @@
 ONC_EXPORT extern const char kProviderName[];
 }  // third_party_vpn
 
+namespace arc_vpn {
+ONC_EXPORT extern const char kTunnelChrome[];
+}  // namespace arc_vpn
+
 namespace verify_x509 {
 ONC_EXPORT extern const char kName[];
 ONC_EXPORT extern const char kType[];
diff --git a/content/browser/android/ime_adapter_android.cc b/content/browser/android/ime_adapter_android.cc
index 256b762e..5d3869bd 100644
--- a/content/browser/android/ime_adapter_android.cc
+++ b/content/browser/android/ime_adapter_android.cc
@@ -87,8 +87,33 @@
       reinterpret_cast<std::vector<ui::ImeTextSpan>*>(ime_text_spans_ptr);
   ime_text_spans->push_back(ui::ImeTextSpan(
       ui::ImeTextSpan::Type::kComposition, static_cast<unsigned>(start),
-      static_cast<unsigned>(end), SK_ColorTRANSPARENT, false,
-      static_cast<unsigned>(background_color)));
+      static_cast<unsigned>(end), static_cast<unsigned>(background_color),
+      false, SK_ColorTRANSPARENT, SK_ColorTRANSPARENT,
+      std::vector<std::string>()));
+}
+
+// Callback from Java to convert SuggestionSpan data to a
+// blink::WebImeTextSpan instance, and append it to |ime_text_spans_ptr|.
+void AppendSuggestionSpan(JNIEnv* env,
+                          const JavaParamRef<jclass>&,
+                          jlong ime_text_spans_ptr,
+                          jint start,
+                          jint end,
+                          jint underline_color,
+                          jint suggestion_highlight_color,
+                          const JavaParamRef<jobjectArray>& suggestions) {
+  DCHECK_GE(start, 0);
+  DCHECK_GE(end, 0);
+
+  std::vector<blink::WebImeTextSpan>* ime_text_spans =
+      reinterpret_cast<std::vector<blink::WebImeTextSpan>*>(ime_text_spans_ptr);
+  std::vector<std::string> suggestions_vec;
+  AppendJavaStringArrayToStringVector(env, suggestions, &suggestions_vec);
+  ime_text_spans->push_back(blink::WebImeTextSpan(
+      blink::WebImeTextSpan::Type::kSuggestion, static_cast<unsigned>(start),
+      static_cast<unsigned>(end), static_cast<unsigned>(underline_color), true,
+      SK_ColorTRANSPARENT, static_cast<unsigned>(suggestion_highlight_color),
+      suggestions_vec));
 }
 
 // Callback from Java to convert UnderlineSpan data to a
@@ -104,7 +129,8 @@
       reinterpret_cast<std::vector<ui::ImeTextSpan>*>(ime_text_spans_ptr);
   ime_text_spans->push_back(ui::ImeTextSpan(
       ui::ImeTextSpan::Type::kComposition, static_cast<unsigned>(start),
-      static_cast<unsigned>(end), SK_ColorBLACK, false, SK_ColorTRANSPARENT));
+      static_cast<unsigned>(end), SK_ColorBLACK, false, SK_ColorTRANSPARENT,
+      SK_ColorTRANSPARENT, std::vector<std::string>()));
 }
 
 ImeAdapterAndroid::ImeAdapterAndroid(JNIEnv* env,
@@ -218,7 +244,8 @@
   if (ime_text_spans.empty()) {
     ime_text_spans.push_back(
         ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition, 0, text16.length(),
-                        SK_ColorBLACK, false, SK_ColorTRANSPARENT));
+                        SK_ColorBLACK, false, SK_ColorTRANSPARENT,
+                        SK_ColorTRANSPARENT, std::vector<std::string>()));
   }
 
   // relative_cursor_pos is as described in the Android API for
@@ -339,9 +366,9 @@
     return;
 
   std::vector<ui::ImeTextSpan> ime_text_spans;
-  ime_text_spans.push_back(ui::ImeTextSpan(ui::ImeTextSpan::Type::kComposition,
-                                           0, end - start, SK_ColorBLACK, false,
-                                           SK_ColorTRANSPARENT));
+  ime_text_spans.push_back(ui::ImeTextSpan(
+      ui::ImeTextSpan::Type::kComposition, 0, end - start, SK_ColorBLACK, false,
+      SK_ColorTRANSPARENT, SK_ColorTRANSPARENT, std::vector<std::string>()));
 
   rfh->GetFrameInputHandler()->SetCompositionFromExistingText(start, end,
                                                               ime_text_spans);
diff --git a/content/browser/android/text_suggestion_host_android.cc b/content/browser/android/text_suggestion_host_android.cc
index 24c647ff..9669364 100644
--- a/content/browser/android/text_suggestion_host_android.cc
+++ b/content/browser/android/text_suggestion_host_android.cc
@@ -12,18 +12,27 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "jni/SuggestionInfo_jni.h"
 #include "jni/TextSuggestionHost_jni.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/gfx/android/view_configuration.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::GetClass;
 using base::android::JavaParamRef;
+using base::android::MethodID;
 using base::android::ScopedJavaLocalRef;
 using base::android::ToJavaArrayOfStrings;
 
 namespace content {
 
+namespace {
+
+const size_t kMaxNumberOfSuggestions = 5;
+
+}  // namespace
+
 jlong Init(JNIEnv* env,
            const JavaParamRef<jobject>& obj,
            const JavaParamRef<jobject>& jweb_contents) {
@@ -43,8 +52,8 @@
       WebContentsObserver(web_contents),
       rwhva_(nullptr),
       java_text_suggestion_host_(JavaObjectWeakGlobalRef(env, obj)),
-      spellcheck_menu_timeout_(
-          base::Bind(&TextSuggestionHostAndroid::OnSpellCheckMenuTimeout,
+      suggestion_menu_timeout_(
+          base::Bind(&TextSuggestionHostAndroid::OnSuggestionMenuTimeout,
                      base::Unretained(this))) {
   registry_.AddInterface(base::Bind(&TextSuggestionHostMojoImplAndroid::Create,
                                     base::Unretained(this)));
@@ -80,6 +89,18 @@
       ConvertJavaStringToUTF8(env, replacement));
 }
 
+void TextSuggestionHostAndroid::ApplyTextSuggestion(
+    JNIEnv*,
+    const JavaParamRef<jobject>&,
+    int marker_tag,
+    int suggestion_index) {
+  const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
+      GetTextSuggestionBackend();
+  if (!text_suggestion_backend)
+    return;
+  text_suggestion_backend->ApplyTextSuggestion(marker_tag, suggestion_index);
+}
+
 void TextSuggestionHostAndroid::DeleteActiveSuggestionRange(
     JNIEnv*,
     const JavaParamRef<jobject>&) {
@@ -90,7 +111,7 @@
   text_suggestion_backend->DeleteActiveSuggestionRange();
 }
 
-void TextSuggestionHostAndroid::NewWordAddedToDictionary(
+void TextSuggestionHostAndroid::OnNewWordAddedToDictionary(
     JNIEnv* env,
     const JavaParamRef<jobject>&,
     const base::android::JavaParamRef<jstring>& word) {
@@ -98,18 +119,18 @@
       GetTextSuggestionBackend();
   if (!text_suggestion_backend)
     return;
-  text_suggestion_backend->NewWordAddedToDictionary(
+  text_suggestion_backend->OnNewWordAddedToDictionary(
       ConvertJavaStringToUTF8(env, word));
 }
 
-void TextSuggestionHostAndroid::SuggestionMenuClosed(
+void TextSuggestionHostAndroid::OnSuggestionMenuClosed(
     JNIEnv*,
     const JavaParamRef<jobject>&) {
   const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
       GetTextSuggestionBackend();
   if (!text_suggestion_backend)
     return;
-  text_suggestion_backend->SuggestionMenuClosed();
+  text_suggestion_backend->OnSuggestionMenuClosed();
 }
 
 void TextSuggestionHostAndroid::ShowSpellCheckSuggestionMenu(
@@ -118,8 +139,10 @@
     const std::string& marked_text,
     const std::vector<blink::mojom::SpellCheckSuggestionPtr>& suggestions) {
   std::vector<std::string> suggestion_strings;
-  for (const auto& suggestion_ptr : suggestions)
-    suggestion_strings.push_back(suggestion_ptr->suggestion);
+  // Enforce kMaxNumberOfSuggestions here in case the renderer is hijacked and
+  // tries to send bad input.
+  for (size_t i = 0; i < suggestions.size() && i < kMaxNumberOfSuggestions; ++i)
+    suggestion_strings.push_back(suggestions[i]->suggestion);
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = java_text_suggestion_host_.get(env);
   if (obj.is_null())
@@ -130,14 +153,44 @@
       ToJavaArrayOfStrings(env, suggestion_strings));
 }
 
-void TextSuggestionHostAndroid::StartSpellCheckMenuTimer() {
-  spellcheck_menu_timeout_.Stop();
-  spellcheck_menu_timeout_.Start(base::TimeDelta::FromMilliseconds(
+void TextSuggestionHostAndroid::ShowTextSuggestionMenu(
+    double caret_x,
+    double caret_y,
+    const std::string& marked_text,
+    const std::vector<blink::mojom::TextSuggestionPtr>& suggestions) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_text_suggestion_host_.get(env);
+
+  // Enforce kMaxNumberOfSuggestions here in case the renderer is hijacked and
+  // tries to send bad input.
+  size_t suggestion_count =
+      std::min(suggestions.size(), kMaxNumberOfSuggestions);
+  ScopedJavaLocalRef<jobjectArray> jsuggestion_infos =
+      Java_SuggestionInfo_createArray(env, suggestion_count);
+
+  for (size_t i = 0; i < suggestion_count; ++i) {
+    const blink::mojom::TextSuggestionPtr& suggestion_ptr = suggestions[i];
+    Java_SuggestionInfo_createSuggestionInfoAndPutInArray(
+        env, jsuggestion_infos, i, suggestion_ptr->marker_tag,
+        suggestion_ptr->suggestion_index,
+        ConvertUTF8ToJavaString(env, suggestion_ptr->prefix),
+        ConvertUTF8ToJavaString(env, suggestion_ptr->suggestion),
+        ConvertUTF8ToJavaString(env, suggestion_ptr->suffix));
+  }
+
+  Java_TextSuggestionHost_showTextSuggestionMenu(
+      env, obj, caret_x, caret_y, ConvertUTF8ToJavaString(env, marked_text),
+      jsuggestion_infos);
+}
+
+void TextSuggestionHostAndroid::StartSuggestionMenuTimer() {
+  suggestion_menu_timeout_.Stop();
+  suggestion_menu_timeout_.Start(base::TimeDelta::FromMilliseconds(
       gfx::ViewConfiguration::GetDoubleTapTimeoutInMs()));
 }
 
 void TextSuggestionHostAndroid::OnKeyEvent() {
-  spellcheck_menu_timeout_.Stop();
+  suggestion_menu_timeout_.Stop();
 
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = java_text_suggestion_host_.get(env);
@@ -147,8 +200,8 @@
   Java_TextSuggestionHost_hidePopups(env, obj);
 }
 
-void TextSuggestionHostAndroid::StopSpellCheckMenuTimer() {
-  spellcheck_menu_timeout_.Stop();
+void TextSuggestionHostAndroid::StopSuggestionMenuTimer() {
+  suggestion_menu_timeout_.Stop();
 }
 
 void TextSuggestionHostAndroid::OnInterfaceRequestFromFrame(
@@ -187,12 +240,13 @@
   return text_suggestion_backend_;
 }
 
-void TextSuggestionHostAndroid::OnSpellCheckMenuTimeout() {
+void TextSuggestionHostAndroid::OnSuggestionMenuTimeout() {
   const blink::mojom::TextSuggestionBackendPtr& text_suggestion_backend =
       GetTextSuggestionBackend();
   if (!text_suggestion_backend)
     return;
-  text_suggestion_backend->SpellCheckMenuTimeoutCallback();
+  text_suggestion_backend->SuggestionMenuTimeoutCallback(
+      kMaxNumberOfSuggestions);
 }
 
 }  // namespace content
diff --git a/content/browser/android/text_suggestion_host_android.h b/content/browser/android/text_suggestion_host_android.h
index 61435ef2..e0c9a180 100644
--- a/content/browser/android/text_suggestion_host_android.h
+++ b/content/browser/android/text_suggestion_host_android.h
@@ -39,6 +39,12 @@
       JNIEnv*,
       const base::android::JavaParamRef<jobject>&,
       const base::android::JavaParamRef<jstring>& replacement);
+  // Called from the Java text suggestion menu to have Blink apply a text
+  // suggestion.
+  void ApplyTextSuggestion(JNIEnv*,
+                           const base::android::JavaParamRef<jobject>&,
+                           int marker_tag,
+                           int suggestion_index);
   // Called from the Java text suggestion menu to have Blink delete the
   // currently highlighted region of text that the open suggestion menu pertains
   // to.
@@ -47,32 +53,39 @@
   // Called from the Java text suggestion menu to tell Blink that a word is
   // being added to the dictionary (so Blink can clear the spell check markers
   // for that word).
-  void NewWordAddedToDictionary(
+  void OnNewWordAddedToDictionary(
       JNIEnv*,
       const base::android::JavaParamRef<jobject>&,
       const base::android::JavaParamRef<jstring>& word);
   // Called from the Java text suggestion menu to tell Blink that the user
   // closed the menu without performing one of the available actions, so Blink
   // can re-show the insertion caret and remove the suggestion range highlight.
-  void SuggestionMenuClosed(JNIEnv*,
-                            const base::android::JavaParamRef<jobject>&);
-  // Called from Blink to tell the Java TextSuggestionHost to open the text
-  // suggestion menu.
+  void OnSuggestionMenuClosed(JNIEnv*,
+                              const base::android::JavaParamRef<jobject>&);
+  // Called from Blink to tell the Java TextSuggestionHost to open the spell
+  // check suggestion menu.
   void ShowSpellCheckSuggestionMenu(
       double caret_x,
       double caret_y,
       const std::string& marked_text,
       const std::vector<blink::mojom::SpellCheckSuggestionPtr>& suggestions);
+  // Called from Blink to tell the Java TextSuggestionHost to open the text
+  // suggestion menu.
+  void ShowTextSuggestionMenu(
+      double caret_x,
+      double caret_y,
+      const std::string& marked_text,
+      const std::vector<blink::mojom::TextSuggestionPtr>& suggestions);
 
   // Called by browser-side code in response to an input event to stop the
   // spell check menu timer and close the suggestion menu (if open).
   void OnKeyEvent();
   // Called by Blink when the user taps on a spell check marker and we might
   // want to show the text suggestion menu after the double-tap timer expires.
-  void StartSpellCheckMenuTimer();
+  void StartSuggestionMenuTimer();
   // Called by browser-side code in response to an input event to stop the
-  // spell check menu timer.
-  void StopSpellCheckMenuTimer();
+  // suggestion menu timer.
+  void StopSuggestionMenuTimer();
 
   // WebContentsObserver overrides
   void OnInterfaceRequestFromFrame(
@@ -85,14 +98,14 @@
   const blink::mojom::TextSuggestionBackendPtr& GetTextSuggestionBackend();
   // Used by the spell check menu timer to notify Blink that the timer has
   // expired.
-  void OnSpellCheckMenuTimeout();
+  void OnSuggestionMenuTimeout();
 
   service_manager::BinderRegistry registry_;
   // Current RenderWidgetHostView connected to this instance. Can be null.
   RenderWidgetHostViewAndroid* rwhva_;
   JavaObjectWeakGlobalRef java_text_suggestion_host_;
   blink::mojom::TextSuggestionBackendPtr text_suggestion_backend_;
-  TimeoutMonitor spellcheck_menu_timeout_;
+  TimeoutMonitor suggestion_menu_timeout_;
 };
 
 }  // namespace content
diff --git a/content/browser/android/text_suggestion_host_mojo_impl_android.cc b/content/browser/android/text_suggestion_host_mojo_impl_android.cc
index 6510499c..9105c2a 100644
--- a/content/browser/android/text_suggestion_host_mojo_impl_android.cc
+++ b/content/browser/android/text_suggestion_host_mojo_impl_android.cc
@@ -22,8 +22,8 @@
       std::move(request));
 }
 
-void TextSuggestionHostMojoImplAndroid::StartSpellCheckMenuTimer() {
-  text_suggestion_host_->StartSpellCheckMenuTimer();
+void TextSuggestionHostMojoImplAndroid::StartSuggestionMenuTimer() {
+  text_suggestion_host_->StartSuggestionMenuTimer();
 }
 
 void TextSuggestionHostMojoImplAndroid::ShowSpellCheckSuggestionMenu(
@@ -35,4 +35,13 @@
                                                       marked_text, suggestions);
 }
 
+void TextSuggestionHostMojoImplAndroid::ShowTextSuggestionMenu(
+    double caret_x,
+    double caret_y,
+    const std::string& marked_text,
+    std::vector<blink::mojom::TextSuggestionPtr> suggestions) {
+  text_suggestion_host_->ShowTextSuggestionMenu(caret_x, caret_y, marked_text,
+                                                suggestions);
+}
+
 }  // namespace content
diff --git a/content/browser/android/text_suggestion_host_mojo_impl_android.h b/content/browser/android/text_suggestion_host_mojo_impl_android.h
index 4281948e..29c66797 100644
--- a/content/browser/android/text_suggestion_host_mojo_impl_android.h
+++ b/content/browser/android/text_suggestion_host_mojo_impl_android.h
@@ -20,13 +20,18 @@
   static void Create(TextSuggestionHostAndroid*,
                      blink::mojom::TextSuggestionHostRequest request);
 
-  void StartSpellCheckMenuTimer() final;
+  void StartSuggestionMenuTimer() final;
 
   void ShowSpellCheckSuggestionMenu(
       double caret_x,
       double caret_y,
       const std::string& marked_text,
       std::vector<blink::mojom::SpellCheckSuggestionPtr> suggestions) final;
+  void ShowTextSuggestionMenu(
+      double caret_x,
+      double caret_y,
+      const std::string& marked_text,
+      std::vector<blink::mojom::TextSuggestionPtr> suggestions) final;
 
  private:
   TextSuggestionHostAndroid* const text_suggestion_host_;
diff --git a/content/browser/appcache/appcache_job.h b/content/browser/appcache/appcache_job.h
index 88a0628..b5965c5 100644
--- a/content/browser/appcache/appcache_job.h
+++ b/content/browser/appcache/appcache_job.h
@@ -111,9 +111,6 @@
   // Returns a weak pointer reference to the job.
   virtual base::WeakPtr<AppCacheJob> GetWeakPtr();
 
-  // Returns the URL of the job.
-  virtual const GURL& GetURL() const = 0;
-
   // Returns the underlying URLRequestJob if any. This only applies to
   // AppCaches loaded via the URLLoader mechanism.
   virtual net::URLRequestJob* AsURLRequestJob();
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 4af11d6..44f342d8 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -264,6 +264,7 @@
 
   subresource_load_info_ = std::move(subresource_load_info);
   network_url_loader_factory_getter_ = loader_factory_getter;
+  request_->AsURLLoaderRequest()->set_request(subresource_load_info_->request);
 
   AppCacheJob* job = MaybeLoadResource(nullptr);
   if (!job)
@@ -542,7 +543,7 @@
   DCHECK(job_.get());
   DCHECK(host_->associated_cache() && host_->associated_cache()->is_complete());
 
-  const GURL& url = job_->GetURL();
+  const GURL& url = request_->GetURL();
   AppCache* cache = host_->associated_cache();
   storage()->FindResponseForSubRequest(
       host_->associated_cache(), url,
@@ -613,7 +614,8 @@
     LoaderCallback callback) {
   // MaybeLoadMainResource will invoke navigation_request_job's methods
   // asynchronously via AppCacheStorage::Delegate.
-  navigation_request_job_ = MaybeLoadMainResource(nullptr);
+  request_->AsURLLoaderRequest()->set_request(resource_request);
+  navigation_request_job_.reset(MaybeLoadResource(nullptr));
   if (!navigation_request_job_.get()) {
     std::move(callback).Run(StartLoaderCallback());
     return;
diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc
index e240389..dc0de727 100644
--- a/content/browser/appcache/appcache_url_loader_job.cc
+++ b/content/browser/appcache/appcache_url_loader_job.cc
@@ -135,10 +135,6 @@
                                                   start_time_tick_);
 }
 
-const GURL& AppCacheURLLoaderJob::GetURL() const {
-  return request_.url;
-}
-
 AppCacheURLLoaderJob* AppCacheURLLoaderJob::AsURLLoaderJob() {
   return this;
 }
diff --git a/content/browser/appcache/appcache_url_loader_job.h b/content/browser/appcache/appcache_url_loader_job.h
index 508c548..670d268 100644
--- a/content/browser/appcache/appcache_url_loader_job.h
+++ b/content/browser/appcache/appcache_url_loader_job.h
@@ -73,7 +73,6 @@
                                 bool is_fallback) override;
   void DeliverNetworkResponse() override;
   void DeliverErrorResponse() override;
-  const GURL& GetURL() const override;
   AppCacheURLLoaderJob* AsURLLoaderJob() override;
 
   // mojom::URLLoader implementation:
diff --git a/content/browser/appcache/appcache_url_loader_request.h b/content/browser/appcache/appcache_url_loader_request.h
index 19a893bb..cdd6285b 100644
--- a/content/browser/appcache/appcache_url_loader_request.h
+++ b/content/browser/appcache/appcache_url_loader_request.h
@@ -23,25 +23,21 @@
   ~AppCacheURLLoaderRequest() override;
 
   // AppCacheRequest overrides.
-  // TODO(ananta)
-  // Add support to the GetURL() call to return the updated URL while following
-  // a chain of redirects.
   const GURL& GetURL() const override;
   const std::string& GetMethod() const override;
   const GURL& GetSiteForCookies() const override;
   const GURL GetReferrer() const override;
-  // TODO(ananta)
-  // ResourceRequest only identifies the request unlike URLRequest which
-  // contains response information as well. We need the following methods to
-  // work for AppCache. Look into this.
+
   bool IsSuccess() const override;
   bool IsCancelled() const override;
   bool IsError() const override;
   int GetResponseCode() const override;
   std::string GetResponseHeaderByName(const std::string& name) const override;
+
   ResourceRequest* GetResourceRequest() override;
   AppCacheURLLoaderRequest* AsURLLoaderRequest() override;
 
+  void set_request(const ResourceRequest& request) { request_ = request; }
   void set_response(const ResourceResponseHead& response) {
     response_ = response;
   }
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc
index da5a584..1061c5f5 100644
--- a/content/browser/appcache/appcache_url_request_job.cc
+++ b/content/browser/appcache/appcache_url_request_job.cc
@@ -87,10 +87,6 @@
   MaybeBeginDelivery();
 }
 
-const GURL& AppCacheURLRequestJob::GetURL() const {
-  return request()->url();
-}
-
 net::URLRequestJob* AppCacheURLRequestJob::AsURLRequestJob() {
   return this;
 }
diff --git a/content/browser/appcache/appcache_url_request_job.h b/content/browser/appcache/appcache_url_request_job.h
index 25ea060..1d6ba831 100644
--- a/content/browser/appcache/appcache_url_request_job.h
+++ b/content/browser/appcache/appcache_url_request_job.h
@@ -48,7 +48,6 @@
                                 bool is_fallback) override;
   void DeliverNetworkResponse() override;
   void DeliverErrorResponse() override;
-  const GURL& GetURL() const override;
   net::URLRequestJob* AsURLRequestJob() override;
 
   // Accessors for the info about the appcached response, if any,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index a516093..80baeaa 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -167,6 +167,16 @@
 #include "device/vr/vr_service.mojom.h"  // nogncheck
 #endif
 
+// This is temporary to try to locate a core trampler.
+// TODO(bcwhite):  Remove when crbug/736675 is resolved.
+#if defined(OS_ANDROID)
+#include "base/metrics/statistics_recorder.h"
+#define VALIDATE_ALL_HISTOGRAMS(x) \
+  base::StatisticsRecorder::ValidateAllHistograms(x)
+#else
+#define VALIDATE_ALL_HISTOGRAMS(x)
+#endif
+
 using base::TimeDelta;
 
 namespace content {
@@ -558,6 +568,8 @@
 }
 
 RenderFrameHostImpl::~RenderFrameHostImpl() {
+  VALIDATE_ALL_HISTOGRAMS(11);
+
   // Destroying navigation handle may call into delegates/observers,
   // so we do it early while |this| object is still in a sane state.
   navigation_handle_.reset();
@@ -566,12 +578,16 @@
   // RenderFrameHost during cleanup.
   ClearAllWebUI();
 
+  VALIDATE_ALL_HISTOGRAMS(12);
+
   SetLastCommittedSiteUrl(GURL());
 
   GetProcess()->RemoveRoute(routing_id_);
   g_routing_id_frame_map.Get().erase(
       RenderFrameHostID(GetProcess()->GetID(), routing_id_));
 
+  VALIDATE_ALL_HISTOGRAMS(13);
+
   if (overlay_routing_token_)
     g_token_frame_map.Get().erase(*overlay_routing_token_);
 
@@ -580,11 +596,15 @@
   if (delegate_ && render_frame_created_)
     delegate_->RenderFrameDeleted(this);
 
+  VALIDATE_ALL_HISTOGRAMS(14);
+
   // If this was the last active frame in the SiteInstance, the
   // DecrementActiveFrameCount call will trigger the deletion of the
   // SiteInstance's proxies.
   GetSiteInstance()->DecrementActiveFrameCount();
 
+  VALIDATE_ALL_HISTOGRAMS(15);
+
   // If this RenderFrameHost is swapping with a RenderFrameProxyHost, the
   // RenderFrame will already be deleted in the renderer process. Main frame
   // RenderFrames will be cleaned up as part of deleting its RenderView if the
@@ -601,18 +621,26 @@
   // the dtor has run.  (It may also be null in tests.)
   swapout_event_monitor_timeout_.reset();
 
+  VALIDATE_ALL_HISTOGRAMS(16);
+
   for (const auto& iter : visual_state_callbacks_)
     iter.second.Run(false);
 
+  VALIDATE_ALL_HISTOGRAMS(17);
+
   if (render_widget_host_ &&
       render_widget_host_->owned_by_render_frame_host()) {
     // Shutdown causes the RenderWidgetHost to delete itself.
     render_widget_host_->ShutdownAndDestroyWidget(true);
   }
 
+  VALIDATE_ALL_HISTOGRAMS(18);
+
   // Notify the FrameTree that this RFH is going away, allowing it to shut down
   // the corresponding RenderViewHost if it is no longer needed.
   frame_tree_->ReleaseRenderViewHostRef(render_view_host_);
+
+  VALIDATE_ALL_HISTOGRAMS(19);
 }
 
 int RenderFrameHostImpl::GetRoutingID() {
@@ -1854,12 +1882,16 @@
   if (!is_waiting_for_swapout_ack_)
     return;
 
+  VALIDATE_ALL_HISTOGRAMS(21);
+
   TRACE_EVENT_ASYNC_END0("navigation", "RenderFrameHostImpl::SwapOut", this);
   if (swapout_event_monitor_timeout_)
     swapout_event_monitor_timeout_->Stop();
 
   ClearAllWebUI();
 
+  VALIDATE_ALL_HISTOGRAMS(22);
+
   // If this is a main frame RFH that's about to be deleted, update its RVH's
   // swapped-out state here. https://crbug.com/505887
   if (frame_tree_node_->IsMainFrame()) {
@@ -1867,9 +1899,13 @@
     render_view_host_->set_is_swapped_out(true);
   }
 
+  VALIDATE_ALL_HISTOGRAMS(23);
+
   bool deleted =
       frame_tree_node_->render_manager()->DeleteFromPendingList(this);
   CHECK(deleted);
+
+  VALIDATE_ALL_HISTOGRAMS(24);
 }
 
 void RenderFrameHostImpl::DisableSwapOutTimerForTesting() {
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index 2c04b2c..eb96d04 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -51,6 +51,9 @@
 // as ResourceDispatcherHostImpl.
 int g_next_request_id = -2;
 
+// Max number of http redirects to follow.  Same number as the net library.
+const int kMaxRedirects = 20;
+
 WebContents* GetWebContentsFromFrameTreeNodeID(int frame_tree_node_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   FrameTreeNode* frame_tree_node =
@@ -106,6 +109,7 @@
 // of URLLoaderRequestHandler's and successively calls MaybeCreateLoader
 // on each until the request is successfully handled. The same sequence
 // may be performed multiple times when redirects happen.
+// TODO(michaeln): Expose this class and add unittests.
 class NavigationURLLoaderNetworkService::URLLoaderRequestController
     : public mojom::URLLoaderClient {
  public:
@@ -187,7 +191,7 @@
     Restart();
   }
 
-  // This could be called multiple times.
+  // This could be called multiple times to follow a chain of redirects.
   void Restart() {
     handler_index_ = 0;
     received_response_ = false;
@@ -196,6 +200,7 @@
 
   void MaybeStartLoader(StartLoaderCallback start_loader_callback) {
     if (start_loader_callback) {
+      default_loader_used_ = false;
       url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
           std::move(start_loader_callback),
           GetContentClient()->browser()->CreateURLLoaderThrottles(
@@ -221,6 +226,12 @@
       return;
     }
 
+    if (url_loader_) {
+      DCHECK(!redirect_info_.new_url.is_empty());
+      url_loader_->FollowRedirect();
+      return;
+    }
+
     mojom::URLLoaderFactory* factory = nullptr;
     DCHECK_EQ(handlers_.size(), handler_index_);
     if (resource_request_->url.SchemeIs(url::kBlobScheme)) {
@@ -241,10 +252,76 @@
   void FollowRedirect() {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     DCHECK(url_loader_);
-
     DCHECK(!response_url_loader_);
+    DCHECK(!redirect_info_.new_url.is_empty());
 
-    url_loader_->FollowRedirect();
+    // Update resource_request_ and call Restart to give our handlers_ a chance
+    // at handling the new location. If no handler wants to take over, we'll
+    // use the existing url_loader to follow the redirect, see MaybeStartLoader.
+    // TODO(michaeln): This is still WIP and is based on URLRequest::Redirect,
+    // there likely remains more to be done.
+    // a. For subframe navigations, the Origin header may need to be modified
+    //    differently?
+    // b. How should redirect_info_.referred_token_binding_host be handled?
+    // c. Maybe refactor for code reuse.
+
+    if (redirect_info_.new_method != resource_request_->method) {
+      resource_request_->method = redirect_info_.new_method;
+
+      // TODO(davidben): This logic still needs to be replicated at the
+      // consumers.
+      if (resource_request_->method == "POST") {
+        // If being switched from POST, must remove Origin header.
+        // TODO(jww): This is Origin header removal is probably layering
+        // violation and should be refactored into //content.
+        // See https://crbug.com/471397.
+        // See also: https://crbug.com/760487
+        resource_request_->headers.RemoveHeader(
+            net::HttpRequestHeaders::kOrigin);
+      }
+      // The inclusion of a multipart Content-Type header can cause problems
+      // with some servers:
+      // http://code.google.com/p/chromium/issues/detail?id=843
+      resource_request_->headers.RemoveHeader(
+          net::HttpRequestHeaders::kContentLength);
+      resource_request_->headers.RemoveHeader(
+          net::HttpRequestHeaders::kContentType);
+
+      // The request body is no longer applicable.
+      resource_request_->request_body = nullptr;
+      blob_handles_.clear();
+    }
+
+    // Cross-origin redirects should not result in an Origin header value that
+    // is equal to the original request's Origin header. This is necessary to
+    // a reflection of POST requests to bypass CSRF protections. If the header
+    // was prevent not set to "null", a POST request from origin A to a
+    // malicious origin M could be redirected by M back to A.
+    //
+    // This behavior is specified in step 10 of the HTTP-redirect fetch
+    // algorithm[1] (which supercedes the behavior outlined in RFC 6454[2].
+    //
+    // [1]: https://fetch.spec.whatwg.org/#http-redirect-fetch
+    // [2]: https://tools.ietf.org/html/rfc6454#section-7
+    //
+    // TODO(jww): This is a layering violation and should be refactored
+    // somewhere up into //net's embedder. https://crbug.com/471397
+    if (!url::Origin(redirect_info_.new_url)
+             .IsSameOriginWith(url::Origin(resource_request_->url)) &&
+        resource_request_->headers.HasHeader(
+            net::HttpRequestHeaders::kOrigin)) {
+      resource_request_->headers.SetHeader(net::HttpRequestHeaders::kOrigin,
+                                           url::Origin().Serialize());
+    }
+
+    resource_request_->url = redirect_info_.new_url;
+    resource_request_->site_for_cookies = redirect_info_.new_site_for_cookies;
+    resource_request_->referrer = GURL(redirect_info_.new_referrer);
+    resource_request_->referrer_policy =
+        Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
+            redirect_info_.new_referrer_policy);
+
+    Restart();
   }
 
   // Ownership of the URLLoaderFactoryPtrInfo instance is transferred to the
@@ -283,6 +360,15 @@
 
   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
                          const ResourceResponseHead& head) override {
+    if (--redirect_limit_ == 0) {
+      OnComplete(ResourceRequestCompletionStatus(net::ERR_TOO_MANY_REDIRECTS));
+      return;
+    }
+
+    // Store the redirect_info for later use in FollowRedirect where we give
+    // our handlers_ a chance to intercept the request for the new location.
+    redirect_info_ = redirect_info;
+
     scoped_refptr<ResourceResponse> response(new ResourceResponse());
     response->head = head;
 
@@ -299,13 +385,10 @@
   }
 
   void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override {}
-
   void OnUploadProgress(int64_t current_position,
                         int64_t total_size,
                         OnUploadProgressCallback callback) override {}
-
   void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
-
   void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
 
   void OnStartLoadingResponseBody(
@@ -333,50 +416,35 @@
   }
 
   // Returns true if a handler wants to handle the response, i.e. return a
-  // different response. For e.g. AppCache may have fallback content to be
-  // returned for a TLD.
+  // different response. For e.g. AppCache may have fallback content.
   bool MaybeCreateLoaderForResponse(const ResourceResponseHead& response) {
     if (!default_loader_used_)
       return false;
 
-    // URLLoaderClient request pointer for response loaders, i.e loaders created
-    // for handing responses received from the network URLLoader.
-    mojom::URLLoaderClientRequest response_client_request;
-
-    for (size_t index = 0; index < handlers_.size(); ++index) {
-      if (handlers_[index]->MaybeCreateLoaderForResponse(
-              response, &response_url_loader_, &response_client_request)) {
-        OnResponseHandlerFound(std::move(response_client_request));
+    for (auto& handler : handlers_) {
+      mojom::URLLoaderClientRequest response_client_request;
+      if (handler->MaybeCreateLoaderForResponse(response, &response_url_loader_,
+                                                &response_client_request)) {
+        response_loader_binding_.Bind(std::move(response_client_request));
+        default_loader_used_ = false;
+        url_loader_.reset();
         return true;
       }
     }
     return false;
   }
 
-  // Called if we find a handler who delivers different content for the URL.
-  void OnResponseHandlerFound(
-      mojom::URLLoaderClientRequest response_client_request) {
-    response_loader_binding_.Bind(std::move(response_client_request));
-    // We reset this flag as we expect a new response from the handler.
-    default_loader_used_ = false;
-    // Disconnect from the network loader to stop receiving further data
-    // or notifications for the URL.
-    url_loader_->DisconnectClient();
-  }
-
   std::vector<std::unique_ptr<URLLoaderRequestHandler>> handlers_;
   size_t handler_index_ = 0;
 
   std::unique_ptr<ResourceRequest> resource_request_;
+  net::RedirectInfo redirect_info_;
+  int redirect_limit_ = kMaxRedirects;
   ResourceContext* resource_context_;
   base::Callback<WebContents*()> web_contents_getter_;
-
   scoped_refptr<URLLoaderFactoryGetter> default_url_loader_factory_getter_;
-
   mojom::URLLoaderFactoryPtr webui_factory_ptr_;
-
   std::unique_ptr<ThrottlingURLLoader> url_loader_;
-
   BlobHandles blob_handles_;
 
   // Currently used by the AppCache loader to pass its factory to the
@@ -520,8 +588,6 @@
     const net::RedirectInfo& redirect_info,
     scoped_refptr<ResourceResponse> response) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // TODO(kinuko): Perform the necessary check and call
-  // URLLoaderRequestController::Restart with the new URL??
   delegate_->OnRequestRedirected(redirect_info, std::move(response));
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index fa13aa7..0180d75 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -90,7 +90,6 @@
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/display/display_switches.h"
-#include "ui/display/screen.h"
 #include "ui/events/blink/web_input_event_traits.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -756,18 +755,9 @@
     // ScaleToCeiledSize(new_size, device_scale_factor) ??
     resize_params->physical_backing_size = view_->GetPhysicalBackingSize();
     resize_params->top_controls_height = view_->GetTopControlsHeight();
-    resize_params->bottom_controls_height = view_->GetBottomControlsHeight();
-    if (IsUseZoomForDSFEnabled() && display::Screen::GetScreen()) {
-      const display::Display& display =
-          display::Screen::GetScreen()->GetPrimaryDisplay();
-      if (display.id() != display::kInvalidDisplayId) {
-        float device_scale = display.device_scale_factor();
-        resize_params->top_controls_height *= device_scale;
-        resize_params->bottom_controls_height *= device_scale;
-      }
-    }
     resize_params->browser_controls_shrink_blink_size =
         view_->DoBrowserControlsShrinkBlinkSize();
+    resize_params->bottom_controls_height = view_->GetBottomControlsHeight();
     resize_params->visible_viewport_size = view_->GetVisibleViewportSize();
     viz::LocalSurfaceId local_surface_id = view_->GetLocalSurfaceId();
     if (local_surface_id.is_valid())
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index c3cd93e..fa6a10a 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -308,14 +308,6 @@
     bounds_ = bounds;
   }
 
-  void set_top_controls_height(float top_controls_height) {
-    top_controls_height_ = top_controls_height;
-  }
-
-  void set_bottom_controls_height(float bottom_controls_height) {
-    bottom_controls_height_ = bottom_controls_height;
-  }
-
   const WebTouchEvent& acked_event() const { return acked_event_; }
   int acked_event_count() const { return acked_event_count_; }
   void ClearAckedEvent() {
@@ -342,10 +334,6 @@
 
   // RenderWidgetHostView override.
   gfx::Rect GetViewBounds() const override { return bounds_; }
-  float GetTopControlsHeight() const override { return top_controls_height_; }
-  float GetBottomControlsHeight() const override {
-    return bottom_controls_height_;
-  }
   void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
                               InputEventAckState ack_result) override {
     acked_event_ = touch.event;
@@ -379,8 +367,6 @@
   bool use_fake_physical_backing_size_;
   gfx::Size mock_physical_backing_size_;
   InputEventAckState ack_result_;
-  float top_controls_height_;
-  float bottom_controls_height_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestView);
@@ -2590,30 +2576,6 @@
   EXPECT_EQ(physical_backing_size, resize_params.physical_backing_size);
 }
 
-TEST_F(RenderWidgetHostTest, ResizeParamsDeviceScale) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  command_line->AppendSwitchASCII(switches::kEnableUseZoomForDSF, "true");
-
-  DCHECK(display::Screen::GetScreen());
-  const display::Display& display =
-      display::Screen::GetScreen()->GetPrimaryDisplay();
-  DCHECK(display.id() != display::kInvalidDisplayId);
-
-  float device_scale = display.device_scale_factor();
-
-  float top_controls_height = 10.0f;
-  float bottom_controls_height = 20.0f;
-  view_->set_top_controls_height(top_controls_height);
-  view_->set_bottom_controls_height(bottom_controls_height);
-
-  ResizeParams resize_params;
-  host_->GetResizeParams(&resize_params);
-  EXPECT_EQ(top_controls_height * device_scale,
-            resize_params.top_controls_height);
-  EXPECT_EQ(bottom_controls_height * device_scale,
-            resize_params.bottom_controls_height);
-}
-
 // Make sure no dragging occurs after renderer exited. See crbug.com/704832.
 TEST_F(RenderWidgetHostTest, RendererExitedNoDrag) {
   host_->SetView(new TestView(host_.get()));
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 7f43dc9..8406645 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -64,7 +64,6 @@
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
 #include "content/browser/renderer_host/ui_events_helper.h"
-#include "content/common/content_switches_internal.h"
 #include "content/common/gpu_stream_constants.h"
 #include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
@@ -976,7 +975,7 @@
   // Receiving any other touch event before the double-tap timeout expires
   // cancels opening the spellcheck menu.
   if (text_suggestion_host_)
-    text_suggestion_host_->StopSpellCheckMenuTimer();
+    text_suggestion_host_->StopSuggestionMenuTimer();
 
   // If a browser-based widget consumes the touch event, it's critical that
   // touch event interception be disabled. This avoids issues with
@@ -1489,7 +1488,7 @@
   bool is_mobile_optimized = IsMobileOptimizedFrame(frame_metadata);
   gesture_provider_.SetDoubleTapSupportForPageEnabled(!is_mobile_optimized);
 
-  float dip_scale = IsUseZoomForDSFEnabled() ? 1.f : view_.GetDipScale();
+  float dip_scale = view_.GetDipScale();
   float top_controls_pix = frame_metadata.top_controls_height * dip_scale;
   float top_content_offset = frame_metadata.top_controls_height *
                              frame_metadata.top_controls_shown_ratio;
diff --git a/content/browser/screen_orientation/screen_orientation_browsertest.cc b/content/browser/screen_orientation/screen_orientation_browsertest.cc
index 08c3c6b..507ed06 100644
--- a/content/browser/screen_orientation/screen_orientation_browsertest.cc
+++ b/content/browser/screen_orientation/screen_orientation_browsertest.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -356,6 +357,64 @@
   }
 }
 
+// Regression test for triggering a screen orientation change for a pending
+// main frame RenderFrameHost.  See https://crbug.com/764202.  In the bug, this
+// was triggered via the DevTools audit panel and
+// ViewMsg_EnableDeviceEmulation, which calls RenderWidget::Resize on the
+// renderer side.  The test fakes this by directly sending the resize message
+// to the widget.
+IN_PROC_BROWSER_TEST_F(ScreenOrientationOOPIFBrowserTest,
+                       ScreenOrientationInPendingMainFrame) {
+  GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+#if USE_AURA || defined(OS_ANDROID)
+  WaitForResizeComplete(shell()->web_contents());
+#endif  // USE_AURA || defined(OS_ANDROID)
+
+  // Set up a fake Resize message with a screen orientation change.
+  RenderWidgetHost* main_frame_rwh =
+      web_contents()->GetMainFrame()->GetRenderWidgetHost();
+  ScreenInfo screen_info;
+  main_frame_rwh->GetScreenInfo(&screen_info);
+  int expected_angle = (screen_info.orientation_angle + 90) % 360;
+  screen_info.orientation_angle = expected_angle;
+
+  ResizeParams params;
+  params.screen_info = screen_info;
+  params.new_size = gfx::Size(300, 300);
+  params.physical_backing_size = gfx::Size(300, 300);
+  params.top_controls_height = 0.f;
+  params.browser_controls_shrink_blink_size = false;
+  params.is_fullscreen_granted = false;
+
+  // Start a cross-site navigation, but don't commit yet.
+  GURL second_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
+  TestNavigationManager delayer(shell()->web_contents(), second_url);
+  shell()->LoadURL(second_url);
+  EXPECT_TRUE(delayer.WaitForRequestStart());
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  RenderFrameHostImpl* pending_rfh =
+      IsBrowserSideNavigationEnabled()
+          ? root->render_manager()->speculative_frame_host()
+          : root->render_manager()->pending_frame_host();
+
+  // Send the orientation change to the pending RFH's widget.
+  pending_rfh->GetRenderWidgetHost()->Send(new ViewMsg_Resize(
+      pending_rfh->GetRenderWidgetHost()->GetRoutingID(), params));
+
+  // Let the navigation finish and make sure it succeeded.
+  delayer.WaitForNavigationFinished();
+  EXPECT_EQ(second_url, web_contents()->GetMainFrame()->GetLastCommittedURL());
+
+  int orientation_angle;
+  EXPECT_TRUE(ExecuteScriptAndExtractInt(
+      root->current_frame_host(),
+      "window.domAutomationController.send(screen.orientation.angle)",
+      &orientation_angle));
+  EXPECT_EQ(expected_angle, orientation_angle);
+}
+
 #ifdef OS_ANDROID
 // This test is disabled because th trybots run in system portrait lock, which
 // prevents the test from changing the screen orientation.
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 4d74754..95c9eee 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -919,15 +919,6 @@
     return;
   }
 
-  ServiceWorkerRegistration* registration =
-      GetContext()->GetLiveRegistration(registration_id);
-  DCHECK(registration);
-
-  ServiceWorkerRegistrationObjectInfo info;
-  ServiceWorkerVersionAttributes attrs;
-  GetRegistrationObjectInfoAndVersionAttributes(provider_host->AsWeakPtr(),
-                                                registration, &info, &attrs);
-
   Send(new ServiceWorkerMsg_ServiceWorkerUpdated(thread_id, request_id));
 }
 
diff --git a/content/browser/service_worker/service_worker_script_url_loader.cc b/content/browser/service_worker/service_worker_script_url_loader.cc
index 2de0c7c8..4cfc827 100644
--- a/content/browser/service_worker/service_worker_script_url_loader.cc
+++ b/content/browser/service_worker/service_worker_script_url_loader.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_version.h"
 #include "content/browser/url_loader_factory_getter.h"
 #include "content/public/common/resource_response.h"
 
@@ -20,9 +21,14 @@
     scoped_refptr<ServiceWorkerVersion> version,
     scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
-    : network_client_binding_(this),
+    : resource_type_(resource_request.resource_type),
+      network_client_binding_(this),
       forwarding_client_(std::move(client)),
       version_(version) {
+  DCHECK_EQ(ServiceWorkerVersion::NEW, version->status());
+  DCHECK(resource_type_ == RESOURCE_TYPE_SERVICE_WORKER ||
+         resource_type_ == RESOURCE_TYPE_SCRIPT);
+
   mojom::URLLoaderClientPtr network_client;
   network_client_binding_.Bind(mojo::MakeRequest(&network_client));
   loader_factory_getter->GetNetworkFactory()->get()->CreateLoaderAndStart(
@@ -63,7 +69,8 @@
   response_info.connection_info = response_head.connection_info;
   response_info.socket_address = response_head.socket_address;
 
-  version_->SetMainScriptHttpResponseInfo(response_info);
+  if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER)
+    version_->SetMainScriptHttpResponseInfo(response_info);
 
   forwarding_client_->OnReceiveResponse(response_head, ssl_info,
                                         std::move(downloaded_file));
diff --git a/content/browser/service_worker/service_worker_script_url_loader.h b/content/browser/service_worker/service_worker_script_url_loader.h
index 6ed1b6c..232c2ed 100644
--- a/content/browser/service_worker/service_worker_script_url_loader.h
+++ b/content/browser/service_worker/service_worker_script_url_loader.h
@@ -15,6 +15,7 @@
 
 namespace content {
 
+class ServiceWorkerVersion;
 class URLLoaderFactoryGetter;
 
 // S13nServiceWorker:
@@ -60,6 +61,10 @@
   void OnComplete(const ResourceRequestCompletionStatus& status) override;
 
  private:
+  // This is RESOURCE_TYPE_SERVICE_WORKER for the main script or
+  // RESOURCE_TYPE_SCRIPT for an imported script.
+  const ResourceType resource_type_;
+
   mojom::URLLoaderPtr network_loader_;
   mojo::Binding<mojom::URLLoaderClient> network_client_binding_;
   mojom::URLLoaderClientPtr forwarding_client_;
diff --git a/content/browser/service_worker/service_worker_script_url_loader_unittest.cc b/content/browser/service_worker/service_worker_script_url_loader_unittest.cc
index 192b543..04bec38 100644
--- a/content/browser/service_worker/service_worker_script_url_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_script_url_loader_unittest.cc
@@ -110,6 +110,7 @@
     ResourceRequest request;
     request.url = version_->script_url();
     request.method = "GET";
+    request.resource_type = RESOURCE_TYPE_SERVICE_WORKER;
 
     DCHECK(!loader_);
     loader_ = base::MakeUnique<ServiceWorkerScriptURLLoader>(
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 59b81fe..e11c38b 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -18,6 +18,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_info.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -134,7 +135,9 @@
       maximum_trace_buffer_usage_(0),
       approximate_event_count_(0),
       pending_clock_sync_ack_count_(0),
-      enabled_tracing_modes_(0) {
+      enabled_tracing_modes_(0),
+      background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+          {base::TaskPriority::BACKGROUND})) {
   // Deliberately leaked, like this class.
   base::FileTracing::SetProvider(new FileTracingProviderImpl);
 }
@@ -166,19 +169,15 @@
   return true;
 }
 
-void TracingControllerImpl::SetEnabledOnFileThread(
+void TracingControllerImpl::SetEnabledOnBackgroundThread(
     const TraceConfig& trace_config,
     const base::Closure& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
   TraceLog::GetInstance()->SetEnabled(trace_config, enabled_tracing_modes_);
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
 }
 
-void TracingControllerImpl::SetDisabledOnFileThread(
+void TracingControllerImpl::SetDisabledOnBackgroundThread(
     const base::Closure& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
   DCHECK(enabled_tracing_modes_);
   TraceLog::GetInstance()->SetDisabled(enabled_tracing_modes_);
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
@@ -338,9 +337,9 @@
   // interfering with the process.
   base::Closure on_stop_tracing_done_callback = base::Bind(
       &TracingControllerImpl::OnStopTracingDone, base::Unretained(this));
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::BindOnce(&TracingControllerImpl::SetDisabledOnFileThread,
+  background_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&TracingControllerImpl::SetDisabledOnBackgroundThread,
                      base::Unretained(this), on_stop_tracing_done_callback));
 }
 
@@ -418,7 +417,7 @@
 
 void TracingControllerImpl::RemoveTraceMessageFilter(
     TraceMessageFilter* trace_message_filter) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // If a filter is removed while a response from that filter is pending then
   // simulate the response. Otherwise the response count will be wrong and the
@@ -457,7 +456,8 @@
   if (agent_name == debug_daemon->GetTracingAgentName()) {
     additional_tracing_agents_.push_back(debug_daemon);
     debug_daemon->SetStopAgentTracingTaskRunner(
-        BrowserThread::GetBlockingPool());
+        base::CreateSequencedTaskRunnerWithTraits(
+            {base::MayBlock(), base::TaskPriority::BACKGROUND}));
     return;
   }
 
@@ -678,16 +678,10 @@
 
   base::Closure on_agent_started =
       base::Bind(callback, kChromeTracingAgentName, true);
-  if (!BrowserThread::PostTask(
-          BrowserThread::FILE, FROM_HERE,
-          base::BindOnce(&TracingControllerImpl::SetEnabledOnFileThread,
-                         base::Unretained(this), trace_config,
-                         on_agent_started))) {
-    // BrowserThread::PostTask fails if the threads haven't been created yet,
-    // so it should be safe to just use TraceLog::SetEnabled directly.
-    TraceLog::GetInstance()->SetEnabled(trace_config, enabled_tracing_modes_);
-    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, on_agent_started);
-  }
+  background_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&TracingControllerImpl::SetEnabledOnBackgroundThread,
+                 base::Unretained(this), trace_config, on_agent_started));
 }
 
 void TracingControllerImpl::StopAgentTracing(
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h
index be873583..0f4e0cb1 100644
--- a/content/browser/tracing/tracing_controller_impl.h
+++ b/content/browser/tracing/tracing_controller_impl.h
@@ -143,10 +143,10 @@
   void OnTraceLogStatusReply(TraceMessageFilter* trace_message_filter,
                              const base::trace_event::TraceLogStatus& status);
 
-  void SetEnabledOnFileThread(
+  void SetEnabledOnBackgroundThread(
       const base::trace_event::TraceConfig& trace_config,
       const base::Closure& callback);
-  void SetDisabledOnFileThread(const base::Closure& callback);
+  void SetDisabledOnBackgroundThread(const base::Closure& callback);
   void OnAllTracingAgentsStarted();
   void StopTracingAfterClockSync();
   void OnStopTracingDone();
@@ -198,6 +198,7 @@
   scoped_refptr<TraceDataSink> trace_data_sink_;
   scoped_refptr<TraceDataSink> monitoring_data_sink_;
   std::unique_ptr<base::DictionaryValue> metadata_;
+  const scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl);
 };
diff --git a/content/browser/tracing/tracing_controller_impl_data_sinks.cc b/content/browser/tracing/tracing_controller_impl_data_sinks.cc
index fa6b7d7..013da86 100644
--- a/content/browser/tracing/tracing_controller_impl_data_sinks.cc
+++ b/content/browser/tracing/tracing_controller_impl_data_sinks.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/pattern.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/zlib/zlib.h"
@@ -65,29 +66,30 @@
         file_(NULL) {}
 
   void ReceiveTraceChunk(std::unique_ptr<std::string> chunk) override {
-    BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&FileTraceDataEndpoint::ReceiveTraceChunkOnFileThread,
-                       this, base::Passed(std::move(chunk))));
+    background_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&FileTraceDataEndpoint::ReceiveTraceChunkOnBlockingThread,
+                   this, base::Passed(std::move(chunk))));
   }
 
   void ReceiveTraceFinalContents(
       std::unique_ptr<const base::DictionaryValue>) override {
-    BrowserThread::PostTask(
-        BrowserThread::FILE, FROM_HERE,
-        base::BindOnce(&FileTraceDataEndpoint::CloseOnFileThread, this));
+    background_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&FileTraceDataEndpoint::CloseOnBlockingThread, this));
   }
 
  private:
   ~FileTraceDataEndpoint() override { DCHECK(file_ == NULL); }
 
-  void ReceiveTraceChunkOnFileThread(std::unique_ptr<std::string> chunk) {
-    if (!OpenFileIfNeededOnFileThread())
+  void ReceiveTraceChunkOnBlockingThread(std::unique_ptr<std::string> chunk) {
+    if (!OpenFileIfNeededOnBlockingThread())
       return;
     ignore_result(fwrite(chunk->c_str(), chunk->size(), 1, file_));
   }
 
-  bool OpenFileIfNeededOnFileThread() {
+  bool OpenFileIfNeededOnBlockingThread() {
+    base::ThreadRestrictions::AssertIOAllowed();
     if (file_ != NULL)
       return true;
     file_ = base::OpenFile(file_path_, "w");
@@ -98,11 +100,12 @@
     return true;
   }
 
-  void CloseOnFileThread() {
-    if (OpenFileIfNeededOnFileThread()) {
+  void CloseOnBlockingThread() {
+    if (OpenFileIfNeededOnBlockingThread()) {
       base::CloseFile(file_);
       file_ = NULL;
     }
+
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE,
         base::BindOnce(&FileTraceDataEndpoint::FinalizeOnUIThread, this));
@@ -113,6 +116,9 @@
   base::FilePath file_path_;
   base::Closure completion_callback_;
   FILE* file_;
+  const scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BACKGROUND});
 
   DISALLOW_COPY_AND_ASSIGN(FileTraceDataEndpoint);
 };
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index b973b04..e1d1eae 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -39,6 +39,7 @@
 #include "content/public/child/request_peer.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/referrer.h"
 #include "content/public/common/resource_request.h"
 #include "content/public/common/resource_request_body.h"
 #include "content/public/common/service_worker_modes.h"
@@ -187,35 +188,6 @@
   }
 }
 
-blink::WebReferrerPolicy NetReferrerPolicyToBlinkReferrerPolicy(
-    net::URLRequest::ReferrerPolicy net_policy) {
-  switch (net_policy) {
-    case net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
-      return blink::kWebReferrerPolicyNoReferrerWhenDowngrade;
-    case net::URLRequest::
-        REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
-      return blink::
-          kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin;
-    case net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
-      return blink::kWebReferrerPolicyOriginWhenCrossOrigin;
-    case net::URLRequest::NEVER_CLEAR_REFERRER:
-      return blink::kWebReferrerPolicyAlways;
-    case net::URLRequest::ORIGIN:
-      return blink::kWebReferrerPolicyOrigin;
-    case net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN:
-      return blink::kWebReferrerPolicySameOrigin;
-    case net::URLRequest::ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
-      return blink::kWebReferrerPolicyStrictOrigin;
-    case net::URLRequest::NO_REFERRER:
-      return blink::kWebReferrerPolicyNever;
-    case net::URLRequest::MAX_REFERRER_POLICY:
-      NOTREACHED();
-      return blink::kWebReferrerPolicyDefault;
-  }
-  NOTREACHED();
-  return blink::kWebReferrerPolicyDefault;
-}
-
 // Extracts info from a data scheme URL |url| into |info| and |data|. Returns
 // net::OK if successful. Returns a net error code otherwise.
 int GetInfoFromDataURL(const GURL& url,
@@ -724,7 +696,8 @@
   return client_->WillFollowRedirect(
       url_, redirect_info.new_site_for_cookies,
       WebString::FromUTF8(redirect_info.new_referrer),
-      NetReferrerPolicyToBlinkReferrerPolicy(redirect_info.new_referrer_policy),
+      Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
+          redirect_info.new_referrer_policy),
       WebString::FromUTF8(redirect_info.new_method), response,
       report_raw_headers_);
 }
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 2ac43ec..fa847e8 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -195,9 +195,12 @@
     "java/src/org/chromium/content/browser/input/SelectPopupDialog.java",
     "java/src/org/chromium/content/browser/input/SelectPopupDropdown.java",
     "java/src/org/chromium/content/browser/input/SelectPopupItem.java",
+    "java/src/org/chromium/content/browser/input/SpellCheckPopupWindow.java",
+    "java/src/org/chromium/content/browser/input/SuggestionInfo.java",
     "java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java",
     "java/src/org/chromium/content/browser/input/TextInputState.java",
     "java/src/org/chromium/content/browser/input/TextSuggestionHost.java",
+    "java/src/org/chromium/content/browser/input/TextSuggestionsPopupWindow.java",
     "java/src/org/chromium/content/browser/input/ThreadedInputConnection.java",
     "java/src/org/chromium/content/browser/input/ThreadedInputConnectionFactory.java",
     "java/src/org/chromium/content/browser/input/ThreadedInputConnectionProxyView.java",
@@ -366,6 +369,7 @@
     "java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java",
     "java/src/org/chromium/content/browser/input/HandleViewResources.java",
     "java/src/org/chromium/content/browser/input/ImeAdapter.java",
+    "java/src/org/chromium/content/browser/input/SuggestionInfo.java",
     "java/src/org/chromium/content/browser/input/TextSuggestionHost.java",
     "java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java",
     "java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java",
@@ -474,6 +478,7 @@
     "javatests/src/org/chromium/content/browser/input/ImeTestUtils.java",
     "javatests/src/org/chromium/content/browser/input/InputDialogContainerTest.java",
     "javatests/src/org/chromium/content/browser/input/SelectPopupTest.java",
+    "javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java",
     "javatests/src/org/chromium/content/browser/picker/DateTimePickerDialogTest.java",
     "javatests/src/org/chromium/content/browser/webcontents/AccessibilitySnapshotTest.java",
     "javatests/src/org/chromium/content/browser/webcontents/WebContentsTest.java",
diff --git a/content/public/android/java/res/values-v17/styles.xml b/content/public/android/java/res/values-v17/styles.xml
index 5d0be61..fd2e68e 100644
--- a/content/public/android/java/res/values-v17/styles.xml
+++ b/content/public/android/java/res/values-v17/styles.xml
@@ -16,6 +16,9 @@
     <style name="SelectActionMenuWebSearch">
         <item name="android:icon">@drawable/ic_search</item>
     </style>
+    <style name="SuggestionPrefixOrSuffix">
+      <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
     <style name="TextSuggestionButton" parent="RobotoMediumStyle">
         <item name="android:drawablePadding">8dp</item>
         <!-- v21 uses sans-serif-medium -->
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
index 5370d225..7c61c5f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -6,6 +6,7 @@
 
 import android.annotation.SuppressLint;
 import android.content.res.Configuration;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
@@ -16,6 +17,7 @@
 import android.text.TextUtils;
 import android.text.style.BackgroundColorSpan;
 import android.text.style.CharacterStyle;
+import android.text.style.SuggestionSpan;
 import android.text.style.UnderlineSpan;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -42,6 +44,8 @@
 import org.chromium.ui.base.ime.TextInputType;
 
 import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -71,9 +75,14 @@
     private static final String TAG = "cr_Ime";
     private static final boolean DEBUG_LOGS = false;
 
+    private static final float SUGGESTION_HIGHLIGHT_BACKGROUND_TRANSPARENCY = 0.4f;
+
     public static final int COMPOSITION_KEY_CODE = 229;
     private static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000;
 
+    // Color used by AOSP Android for a SuggestionSpan with FLAG_EASY_CORRECT set
+    private static final int DEFAULT_SUGGESTION_SPAN_COLOR = 0x88C8C8C8;
+
     private long mNativeImeAdapterAndroid;
     private InputMethodManagerWrapper mInputMethodManagerWrapper;
     private ChromiumBaseInputConnection mInputConnection;
@@ -871,6 +880,15 @@
                 insertionMarkerTop, insertionMarkerBottom, mContainerView);
     }
 
+    private int getUnderlineColorForSuggestionSpan(SuggestionSpan suggestionSpan) {
+        try {
+            Method getUnderlineColorMethod = SuggestionSpan.class.getMethod("getUnderlineColor");
+            return (int) getUnderlineColorMethod.invoke(suggestionSpan);
+        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+            return DEFAULT_SUGGESTION_SPAN_COLOR;
+        }
+    }
+
     @CalledByNative
     private void populateImeTextSpansFromJava(CharSequence text, long imeTextSpans) {
         if (DEBUG_LOGS) {
@@ -890,6 +908,37 @@
             } else if (span instanceof UnderlineSpan) {
                 nativeAppendUnderlineSpan(imeTextSpans, spannableString.getSpanStart(span),
                         spannableString.getSpanEnd(span));
+            } else if (span instanceof SuggestionSpan) {
+                final SuggestionSpan suggestionSpan = (SuggestionSpan) span;
+
+                // We currently only support FLAG_EASY_CORRECT SuggestionSpans.
+                // TODO(rlanday): support FLAG_MISSPELLED SuggestionSpans.
+
+                // Other types:
+                // - FLAG_AUTO_CORRECTION is used e.g. by Samsung's IME to flash a blue background
+                //   on a word being replaced by an autocorrect suggestion. We don't currently
+                //   support this.
+                //
+                // - Some IMEs (e.g. the AOSP keyboard on Jelly Bean) add SuggestionSpans with no
+                //   flags set and no underline color to add suggestions to words marked as
+                //   misspelled (instead of having the spell checker return the suggestions when
+                //   called). We don't support these either.
+                if (suggestionSpan.getFlags() != SuggestionSpan.FLAG_EASY_CORRECT) {
+                    continue;
+                }
+
+                // Copied from Android's Editor.java so we use the same colors
+                // as the native Android text widget.
+                final int underlineColor = getUnderlineColorForSuggestionSpan(suggestionSpan);
+                final int newAlpha = (int) (Color.alpha(underlineColor)
+                        * SUGGESTION_HIGHLIGHT_BACKGROUND_TRANSPARENCY);
+                final int suggestionHighlightColor =
+                        (underlineColor & 0x00FFFFFF) + (newAlpha << 24);
+
+                nativeAppendSuggestionSpan(imeTextSpans,
+                        spannableString.getSpanStart(suggestionSpan),
+                        spannableString.getSpanEnd(suggestionSpan), underlineColor,
+                        suggestionHighlightColor, suggestionSpan.getSuggestions());
             }
         }
     }
@@ -921,6 +970,8 @@
     private static native void nativeAppendUnderlineSpan(long spanPtr, int start, int end);
     private static native void nativeAppendBackgroundColorSpan(
             long spanPtr, int start, int end, int backgroundColor);
+    private static native void nativeAppendSuggestionSpan(long spanPtr, int start, int end,
+            int underlineColor, int suggestionHighlightColor, String[] suggestions);
     private native void nativeSetComposingText(long nativeImeAdapterAndroid, CharSequence text,
             String textStr, int newCursorPosition);
     private native void nativeCommitText(
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SpellCheckPopupWindow.java b/content/public/android/java/src/org/chromium/content/browser/input/SpellCheckPopupWindow.java
new file mode 100644
index 0000000..ed3ef95
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SpellCheckPopupWindow.java
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser.input;
+
+import android.content.Context;
+import android.text.SpannableString;
+import android.view.View;
+
+import org.chromium.content.browser.WindowAndroidProvider;
+
+/**
+ * A subclass of SuggestionsPopupWindow to be used for showing suggestions from a spell check
+ * marker.
+ */
+public class SpellCheckPopupWindow extends SuggestionsPopupWindow {
+    private String[] mSuggestions = new String[0];
+
+    /**
+     * @param context Android context to use.
+     * @param textSuggestionHost TextSuggestionHost instance (used to communicate with Blink).
+     * @param parentView The view used to attach the PopupWindow.
+     * @param windowAndroidProvider A WindowAndroidProvider instance used to get the window size.
+     */
+    public SpellCheckPopupWindow(Context context, TextSuggestionHost textSuggestionHost,
+            View parentView, WindowAndroidProvider windowAndroidProvider) {
+        super(context, textSuggestionHost, parentView, windowAndroidProvider);
+    }
+
+    /**
+     * Shows the spell check menu at the specified coordinates (relative to the viewport).
+     */
+    public void show(double caretX, double caretY, String highlightedText, String[] suggestions) {
+        mSuggestions = suggestions.clone();
+        setAddToDictionaryEnabled(true);
+        super.show(caretX, caretY, highlightedText);
+    }
+
+    @Override
+    protected int getSuggestionsCount() {
+        return mSuggestions.length;
+    }
+
+    @Override
+    protected Object getSuggestionItem(int position) {
+        return mSuggestions[position];
+    }
+
+    @Override
+    protected SpannableString getSuggestionText(int position) {
+        return new SpannableString(mSuggestions[position]);
+    }
+
+    @Override
+    protected void applySuggestion(int position) {
+        mTextSuggestionHost.applySpellCheckSuggestion(mSuggestions[position]);
+    }
+}
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionInfo.java b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionInfo.java
new file mode 100644
index 0000000..90b3fe6
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionInfo.java
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser.input;
+
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * Represents an entry in a text suggestion popup menu. Contains the information
+ * necessary to display the menu entry and the information necessary to apply
+ * the suggestion.
+ */
+public class SuggestionInfo {
+    private final int mMarkerTag;
+    private final int mSuggestionIndex;
+    private final String mPrefix;
+    private final String mSuggestion;
+    private final String mSuffix;
+
+    SuggestionInfo(
+            int markerTag, int suggestionIndex, String prefix, String suggestion, String suffix) {
+        mMarkerTag = markerTag;
+        mSuggestionIndex = suggestionIndex;
+        mPrefix = prefix;
+        mSuggestion = suggestion;
+        mSuffix = suffix;
+    }
+
+    /**
+     * Used as an opaque identifier to tell Blink which suggestion was picked.
+     */
+    public int getMarkerTag() {
+        return mMarkerTag;
+    }
+
+    /**
+     * Used as an opaque identifier to tell Blink which suggestion was picked.
+     */
+    public int getSuggestionIndex() {
+        return mSuggestionIndex;
+    }
+
+    /**
+     * Text at the beginning of the highlighted suggestion region that will not be changed by
+     * applying the suggestion.
+     */
+    public String getPrefix() {
+        return mPrefix;
+    }
+
+    /**
+     * Text that will replace the text between the prefix and suffix strings if the suggestion is
+     * applied.
+     */
+    public String getSuggestion() {
+        return mSuggestion;
+    }
+
+    /**
+     * Text at the end of the highlighted suggestion region that will not be changed by
+     * applying the suggestion.
+     */
+    public String getSuffix() {
+        return mSuffix;
+    }
+
+    @CalledByNative
+    private static SuggestionInfo[] createArray(int length) {
+        return new SuggestionInfo[length];
+    }
+
+    @CalledByNative
+    private static void createSuggestionInfoAndPutInArray(SuggestionInfo[] suggestionInfos,
+            int index, int markerTag, int suggestionIndex, String prefix, String suggestion,
+            String suffix) {
+        SuggestionInfo suggestionInfo =
+                new SuggestionInfo(markerTag, suggestionIndex, prefix, suggestion, suffix);
+        suggestionInfos[index] = suggestionInfo;
+    }
+}
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
index 3cc1578..c2e6876 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
@@ -11,6 +11,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
+import android.text.SpannableString;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -34,7 +35,7 @@
 /**
  * Popup window that displays a menu for viewing and applying text replacement suggestions.
  */
-public class SuggestionsPopupWindow
+public abstract class SuggestionsPopupWindow
         implements OnItemClickListener, OnDismissListener, View.OnClickListener {
     private static final String ACTION_USER_DICTIONARY_INSERT =
             "com.android.settings.USER_DICTIONARY_INSERT";
@@ -44,7 +45,7 @@
     private static final int ADD_TO_DICTIONARY_MAX_LENGTH_ON_JELLY_BEAN = 48;
 
     private final Context mContext;
-    private final TextSuggestionHost mTextSuggestionHost;
+    protected final TextSuggestionHost mTextSuggestionHost;
     private final View mParentView;
     private final WindowAndroidProvider mWindowAndroidProvider;
 
@@ -53,9 +54,7 @@
     private PopupWindow mPopupWindow;
     private LinearLayout mContentView;
 
-    private SuggestionAdapter mSuggestionsAdapter;
     private String mHighlightedText;
-    private String[] mSpellCheckSuggestions = new String[0];
     private int mNumberOfSuggestionsToUse;
     private TextView mAddToDictionaryButton;
     private TextView mDeleteButton;
@@ -65,7 +64,6 @@
     private int mPopupVerticalMargin;
 
     private boolean mDismissedByItemTap;
-
     /**
      * @param context Android context to use.
      * @param textSuggestionHost TextSuggestionHost instance (used to communicate with Blink).
@@ -85,6 +83,36 @@
         mPopupWindow.setContentView(mContentView);
     }
 
+    /**
+     * Method to be implemented by subclasses that returns how mnay suggestions are available (some
+     * of them may not be displayed if there's not enough room in the window).
+     */
+    protected abstract int getSuggestionsCount();
+
+    /**
+     * Method to be implemented by subclasses to return an object representing the suggestion at
+     * the specified position.
+     */
+    protected abstract Object getSuggestionItem(int position);
+
+    /**
+     * Method to be implemented by subclasses to return a SpannableString representing text,
+     * possibly with formatting added, to display for the suggestion at the specified position.
+     */
+    protected abstract SpannableString getSuggestionText(int position);
+
+    /**
+     * Method to be implemented by subclasses to apply the suggestion at the specified position.
+     */
+    protected abstract void applySuggestion(int position);
+
+    /**
+     * Hides or shows the "Add to dictionary" button in the suggestion menu footer.
+     */
+    protected void setAddToDictionaryEnabled(boolean isEnabled) {
+        mAddToDictionaryButton.setVisibility(isEnabled ? View.VISIBLE : View.GONE);
+    }
+
     private void createPopupWindow() {
         mPopupWindow = new PopupWindow();
         mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -139,8 +167,7 @@
                 (LinearLayout) inflater.inflate(R.layout.text_edit_suggestion_list_footer, null);
         mSuggestionListView.addFooterView(mListFooter, null, false);
 
-        mSuggestionsAdapter = new SuggestionAdapter();
-        mSuggestionListView.setAdapter(mSuggestionsAdapter);
+        mSuggestionListView.setAdapter(new SuggestionAdapter());
         mSuggestionListView.setOnItemClickListener(this);
 
         mDivider = mContentView.findViewById(R.id.divider);
@@ -201,7 +228,7 @@
 
         @Override
         public Object getItem(int position) {
-            return mSpellCheckSuggestions[position];
+            return getSuggestionItem(position);
         }
 
         @Override
@@ -216,8 +243,8 @@
                 textView = (TextView) mInflater.inflate(
                         R.layout.text_edit_suggestion_item, parent, false);
             }
-            final String suggestion = mSpellCheckSuggestions[position];
-            textView.setText(suggestion);
+
+            textView.setText(getSuggestionText(position));
             return textView;
         }
     }
@@ -248,24 +275,9 @@
      * Called by TextSuggestionHost to tell this class what text is currently highlighted (so it can
      * be added to the dictionary if requested).
      */
-    public void setHighlightedText(String text) {
-        mHighlightedText = text;
-    }
-
-    /**
-     * Called by TextSuggestionHost to set the list of spell check suggestions to show in the
-     * suggestion menu.
-     */
-    public void setSpellCheckSuggestions(String[] suggestions) {
-        mSpellCheckSuggestions = suggestions.clone();
-        mNumberOfSuggestionsToUse = mSpellCheckSuggestions.length;
-    }
-
-    /**
-     * Shows the text suggestion menu at the specified coordinates (relative to the viewport).
-     */
-    public void show(double caretX, double caretY) {
-        mSuggestionsAdapter.notifyDataSetChanged();
+    protected void show(double caretXPx, double caretYPx, String highlightedText) {
+        mNumberOfSuggestionsToUse = getSuggestionsCount();
+        mHighlightedText = highlightedText;
 
         mActivity = mWindowAndroidProvider.getWindowAndroid().getActivity().get();
         // Note: the Activity can be null here if we're in a WebView that was created without
@@ -327,8 +339,8 @@
 
         // Horizontally center the menu on the caret location, and vertically position the menu
         // under the caret.
-        int positionX = (int) Math.round(caretX - width / 2.0f);
-        int positionY = (int) Math.round(caretY);
+        int positionX = (int) Math.round(caretXPx - width / 2.0f);
+        int positionY = (int) Math.round(caretYPx);
 
         // We get the insertion point coords relative to the viewport.
         // We need to render the popup relative to the window.
@@ -364,7 +376,7 @@
     public void onClick(View v) {
         if (v == mAddToDictionaryButton) {
             addToDictionary();
-            mTextSuggestionHost.newWordAddedToDictionary(mHighlightedText);
+            mTextSuggestionHost.onNewWordAddedToDictionary(mHighlightedText);
             mDismissedByItemTap = true;
             mPopupWindow.dismiss();
         } else if (v == mDeleteButton) {
@@ -382,15 +394,14 @@
             return;
         }
 
-        String suggestion = mSpellCheckSuggestions[position];
-        mTextSuggestionHost.applySpellCheckSuggestion(suggestion);
+        applySuggestion(position);
         mDismissedByItemTap = true;
         mPopupWindow.dismiss();
     }
 
     @Override
     public void onDismiss() {
-        mTextSuggestionHost.suggestionMenuClosed(mDismissedByItemTap);
+        mTextSuggestionHost.onSuggestionMenuClosed(mDismissedByItemTap);
         mDismissedByItemTap = false;
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
index bfaf188..6ad989f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
@@ -20,7 +20,8 @@
     private long mNativeTextSuggestionHost;
     private final ContentViewCore mContentViewCore;
 
-    private SuggestionsPopupWindow mSuggestionsPopupWindow;
+    private SpellCheckPopupWindow mSpellCheckPopupWindow;
+    private TextSuggestionsPopupWindow mTextSuggestionsPopupWindow;
 
     public TextSuggestionHost(ContentViewCore contentViewCore) {
         mContentViewCore = contentViewCore;
@@ -29,25 +30,42 @@
 
     @CalledByNative
     private void showSpellCheckSuggestionMenu(
-            double caretX, double caretY, String markedText, String[] suggestions) {
+            double caretXDp, double caretY, String markedText, String[] suggestions) {
         if (!mContentViewCore.isAttachedToWindow()) {
             // This can happen if a new browser window is opened immediately after tapping a spell
             // check underline, before the timer to open the menu fires.
-            suggestionMenuClosed(false);
+            onSuggestionMenuClosed(false);
             return;
         }
 
-        if (mSuggestionsPopupWindow == null) {
-            mSuggestionsPopupWindow = new SuggestionsPopupWindow(mContentViewCore.getContext(),
-                    this, mContentViewCore.getContainerView(), mContentViewCore);
-        }
-
-        mSuggestionsPopupWindow.setHighlightedText(markedText);
-        mSuggestionsPopupWindow.setSpellCheckSuggestions(suggestions);
+        hidePopups();
+        mSpellCheckPopupWindow = new SpellCheckPopupWindow(mContentViewCore.getContext(), this,
+                mContentViewCore.getContainerView(), mContentViewCore);
 
         float density = mContentViewCore.getRenderCoordinates().getDeviceScaleFactor();
-        mSuggestionsPopupWindow.show(density * caretX,
-                density * caretY + mContentViewCore.getRenderCoordinates().getContentOffsetYPix());
+        mSpellCheckPopupWindow.show(density * caretXDp,
+                density * caretY + mContentViewCore.getRenderCoordinates().getContentOffsetYPix(),
+                markedText, suggestions);
+    }
+
+    @CalledByNative
+    private void showTextSuggestionMenu(
+            double caretXDp, double caretYDp, String markedText, SuggestionInfo[] suggestions) {
+        if (!mContentViewCore.isAttachedToWindow()) {
+            // This can happen if a new browser window is opened immediately after tapping a spell
+            // check underline, before the timer to open the menu fires.
+            onSuggestionMenuClosed(false);
+            return;
+        }
+
+        hidePopups();
+        mTextSuggestionsPopupWindow = new TextSuggestionsPopupWindow(mContentViewCore.getContext(),
+                this, mContentViewCore.getContainerView(), mContentViewCore);
+
+        float density = mContentViewCore.getRenderCoordinates().getDeviceScaleFactor();
+        mTextSuggestionsPopupWindow.show(density * caretXDp,
+                density * caretYDp + mContentViewCore.getRenderCoordinates().getContentOffsetYPix(),
+                markedText, suggestions);
     }
 
     /**
@@ -55,9 +73,14 @@
      */
     @CalledByNative
     public void hidePopups() {
-        if (mSuggestionsPopupWindow != null && mSuggestionsPopupWindow.isShowing()) {
-            mSuggestionsPopupWindow.dismiss();
-            mSuggestionsPopupWindow = null;
+        if (mTextSuggestionsPopupWindow != null && mTextSuggestionsPopupWindow.isShowing()) {
+            mTextSuggestionsPopupWindow.dismiss();
+            mTextSuggestionsPopupWindow = null;
+        }
+
+        if (mSpellCheckPopupWindow != null && mSpellCheckPopupWindow.isShowing()) {
+            mSpellCheckPopupWindow.dismiss();
+            mSpellCheckPopupWindow = null;
         }
     }
 
@@ -69,6 +92,14 @@
     }
 
     /**
+     * Tells Blink to replace the active suggestion range with the specified suggestion on the
+     * specified marker.
+     */
+    public void applyTextSuggestion(int markerTag, int suggestionIndex) {
+        nativeApplyTextSuggestion(mNativeTextSuggestionHost, markerTag, suggestionIndex);
+    }
+
+    /**
      * Tells Blink to delete the active suggestion range.
      */
     public void deleteActiveSuggestionRange() {
@@ -78,39 +109,51 @@
     /**
      * Tells Blink to remove spelling markers under all instances of the specified word.
      */
-    public void newWordAddedToDictionary(String word) {
-        nativeNewWordAddedToDictionary(mNativeTextSuggestionHost, word);
+    public void onNewWordAddedToDictionary(String word) {
+        nativeOnNewWordAddedToDictionary(mNativeTextSuggestionHost, word);
     }
 
     /**
      * Tells Blink the suggestion menu was closed (and also clears the reference to the
      * SuggestionsPopupWindow instance so it can be garbage collected).
      */
-    public void suggestionMenuClosed(boolean dismissedByItemTap) {
+    public void onSuggestionMenuClosed(boolean dismissedByItemTap) {
         if (!dismissedByItemTap) {
-            nativeSuggestionMenuClosed(mNativeTextSuggestionHost);
+            nativeOnSuggestionMenuClosed(mNativeTextSuggestionHost);
         }
-        mSuggestionsPopupWindow = null;
+        mSpellCheckPopupWindow = null;
+        mTextSuggestionsPopupWindow = null;
     }
 
     @CalledByNative
     private void destroy() {
+        hidePopups();
         mNativeTextSuggestionHost = 0;
     }
 
     /**
-     * @return The SuggestionsPopupWindow, if one exists.
+     * @return The TextSuggestionsPopupWindow, if one exists.
      */
     @VisibleForTesting
-    public SuggestionsPopupWindow getSuggestionsPopupWindowForTesting() {
-        return mSuggestionsPopupWindow;
+    public SuggestionsPopupWindow getTextSuggestionsPopupWindowForTesting() {
+        return mTextSuggestionsPopupWindow;
+    }
+
+    /**
+     * @return The SpellCheckPopupWindow, if one exists.
+     */
+    @VisibleForTesting
+    public SuggestionsPopupWindow getSpellCheckPopupWindowForTesting() {
+        return mSpellCheckPopupWindow;
     }
 
     private native long nativeInit(WebContents webContents);
     private native void nativeApplySpellCheckSuggestion(
             long nativeTextSuggestionHostAndroid, String suggestion);
+    private native void nativeApplyTextSuggestion(
+            long nativeTextSuggestionHostAndroid, int markerTag, int suggestionIndex);
     private native void nativeDeleteActiveSuggestionRange(long nativeTextSuggestionHostAndroid);
-    private native void nativeNewWordAddedToDictionary(
+    private native void nativeOnNewWordAddedToDictionary(
             long nativeTextSuggestionHostAndroid, String word);
-    private native void nativeSuggestionMenuClosed(long nativeTextSuggestionHostAndroid);
+    private native void nativeOnSuggestionMenuClosed(long nativeTextSuggestionHostAndroid);
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionsPopupWindow.java b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionsPopupWindow.java
new file mode 100644
index 0000000..e463d8f
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionsPopupWindow.java
@@ -0,0 +1,94 @@
+// 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.content.browser.input;
+
+import android.content.Context;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.TextAppearanceSpan;
+import android.view.View;
+
+import org.chromium.content.R;
+import org.chromium.content.browser.WindowAndroidProvider;
+
+/**
+ * A subclass of SuggestionsPopupWindow to be used for showing suggestions from one or more
+ * SuggestionSpans.
+ */
+public class TextSuggestionsPopupWindow extends SuggestionsPopupWindow {
+    private SuggestionInfo[] mSuggestionInfos;
+    private TextAppearanceSpan mPrefixSpan;
+    private TextAppearanceSpan mSuffixSpan;
+
+    /**
+     * @param context Android context to use.
+     * @param textSuggestionHost TextSuggestionHost instance (used to communicate with Blink).
+     * @param parentView The view used to attach the PopupWindow.
+     * @param windowAndroidProvider A WindowAndroidProvider instance used to get the window size.
+     */
+    public TextSuggestionsPopupWindow(Context context, TextSuggestionHost textSuggestionHost,
+            View parentView, WindowAndroidProvider windowAndroidProvider) {
+        super(context, textSuggestionHost, parentView, windowAndroidProvider);
+
+        mPrefixSpan = new TextAppearanceSpan(context, R.style.SuggestionPrefixOrSuffix);
+        mSuffixSpan = new TextAppearanceSpan(context, R.style.SuggestionPrefixOrSuffix);
+    }
+
+    /**
+     * Shows the text suggestion menu at the specified coordinates (relative to the viewport).
+     */
+    public void show(double caretX, double caretY, String highlightedText,
+            SuggestionInfo[] suggestionInfos) {
+        mSuggestionInfos = suggestionInfos.clone();
+
+        // Android's Editor.java shows the "Add to dictonary" button if and only if there's a
+        // SuggestionSpan with FLAG_MISSPELLED set. However, some OEMs (e.g. Samsung) appear to
+        // change the behavior on their devices to never show this button, since their IMEs don't go
+        // through the normal spell-checking API and instead add SuggestionSpans directly. Since
+        // it's difficult to determine how the OEM has set up the native menu, we instead only show
+        // the "Add to dictionary" button for spelling markers added by Chrome from running the
+        // system spell checker. SuggestionSpans with FLAG_MISSPELLED set (i.e., a spelling
+        // underline added directly by the IME) do not show this button.
+        setAddToDictionaryEnabled(false);
+        super.show(caretX, caretY, highlightedText);
+    }
+
+    @Override
+    protected int getSuggestionsCount() {
+        return mSuggestionInfos.length;
+    }
+
+    @Override
+    protected Object getSuggestionItem(int position) {
+        return mSuggestionInfos[position];
+    }
+
+    @Override
+    protected SpannableString getSuggestionText(int position) {
+        final SuggestionInfo suggestionInfo = mSuggestionInfos[position];
+
+        SpannableString suggestionText = new SpannableString(suggestionInfo.getPrefix()
+                + suggestionInfo.getSuggestion() + suggestionInfo.getSuffix());
+
+        // Gray out prefix text (if any).
+        suggestionText.setSpan(mPrefixSpan, 0, suggestionInfo.getPrefix().length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        // Gray out suffix text (if any).
+        suggestionText.setSpan(mSuffixSpan,
+                suggestionInfo.getPrefix().length() + suggestionInfo.getSuggestion().length(),
+                suggestionInfo.getPrefix().length() + suggestionInfo.getSuggestion().length()
+                        + suggestionInfo.getSuffix().length(),
+                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        return suggestionText;
+    }
+
+    @Override
+    protected void applySuggestion(int position) {
+        SuggestionInfo info = mSuggestionInfos[position];
+        mTextSuggestionHost.applyTextSuggestion(info.getMarkerTag(), info.getSuggestionIndex());
+    }
+}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java
new file mode 100644
index 0000000..f060462
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/TextSuggestionMenuTest.java
@@ -0,0 +1,228 @@
+// 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.content.browser.input;
+
+import android.support.test.filters.LargeTest;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.SuggestionSpan;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.content.R;
+import org.chromium.content.browser.ContentViewCore;
+import org.chromium.content.browser.test.ContentJUnit4ClassRunner;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.DOMUtils;
+import org.chromium.content.browser.test.util.TouchCommon;
+import org.chromium.content_public.browser.WebContents;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Integration tests for the text suggestion menu.
+ */
+@RunWith(ContentJUnit4ClassRunner.class)
+public class TextSuggestionMenuTest {
+    private static final String URL =
+            "data:text/html, <div contenteditable id=\"div\" /><span id=\"span\" />";
+
+    @Rule
+    public ImeActivityTestRule mRule = new ImeActivityTestRule();
+
+    @Before
+    public void setUp() throws Throwable {
+        mRule.setUp();
+        mRule.fullyLoadUrl(URL);
+    }
+
+    @Test
+    @LargeTest
+    public void testDeleteMarkedWord() throws InterruptedException, Throwable, TimeoutException {
+        final ContentViewCore cvc = mRule.getContentViewCore();
+        WebContents webContents = cvc.getWebContents();
+
+        DOMUtils.focusNode(webContents, "div");
+
+        SpannableString textToCommit = new SpannableString("hello");
+        SuggestionSpan suggestionSpan = new SuggestionSpan(mRule.getContentViewCore().getContext(),
+                new String[] {"goodbye"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        textToCommit.setSpan(suggestionSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        mRule.commitText(textToCommit, 1);
+
+        DOMUtils.clickNode(cvc, "div");
+        waitForMenuToShow(cvc);
+
+        TouchCommon.singleClickView(getDeleteButton(cvc));
+
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return DOMUtils.getNodeContents(cvc.getWebContents(), "div").equals("");
+                } catch (InterruptedException | TimeoutException e) {
+                    return false;
+                }
+            }
+        });
+
+        waitForMenuToHide(cvc);
+    }
+
+    @Test
+    @LargeTest
+    public void testApplySuggestion() throws InterruptedException, Throwable, TimeoutException {
+        final ContentViewCore cvc = mRule.getContentViewCore();
+        WebContents webContents = cvc.getWebContents();
+
+        DOMUtils.focusNode(webContents, "div");
+
+        // We have a string of length 11 and we set three SuggestionSpans on it
+        // to test that the menu shows the right suggestions in the right order:
+        //
+        // - One span on the word "hello"
+        // - One span on the whole string "hello world"
+        // - One span on the word "world"
+        //
+        // We simulate a tap at the end of the string. We should get the
+        // suggestions from "world", then the suggestions from "hello world",
+        // and not get any suggestions from "hello".
+
+        SpannableString textToCommit = new SpannableString("hello world");
+
+        SuggestionSpan suggestionSpan1 = new SuggestionSpan(mRule.getContentViewCore().getContext(),
+                new String[] {"invalid_suggestion"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        textToCommit.setSpan(suggestionSpan1, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        SuggestionSpan suggestionSpan2 = new SuggestionSpan(mRule.getContentViewCore().getContext(),
+                new String[] {"suggestion3", "suggestion4"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        textToCommit.setSpan(suggestionSpan2, 0, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        SuggestionSpan suggestionSpan3 = new SuggestionSpan(mRule.getContentViewCore().getContext(),
+                new String[] {"suggestion1", "suggestion2"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        textToCommit.setSpan(suggestionSpan3, 6, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        mRule.commitText(textToCommit, 1);
+
+        DOMUtils.clickNode(cvc, "span");
+        waitForMenuToShow(cvc);
+
+        // There should be 5 child views: 4 suggestions plus the list footer.
+        Assert.assertEquals(5, getSuggestionList(cvc).getChildCount());
+
+        Assert.assertEquals(
+                "hello suggestion1", ((TextView) getSuggestionButton(cvc, 0)).getText().toString());
+        Assert.assertEquals(
+                "hello suggestion2", ((TextView) getSuggestionButton(cvc, 1)).getText().toString());
+        Assert.assertEquals(
+                "suggestion3", ((TextView) getSuggestionButton(cvc, 2)).getText().toString());
+        Assert.assertEquals(
+                "suggestion4", ((TextView) getSuggestionButton(cvc, 3)).getText().toString());
+
+        TouchCommon.singleClickView(getSuggestionButton(cvc, 2));
+
+        CriteriaHelper.pollInstrumentationThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return DOMUtils.getNodeContents(cvc.getWebContents(), "div")
+                            .equals("suggestion3");
+                } catch (InterruptedException | TimeoutException e) {
+                    return false;
+                }
+            }
+        });
+
+        waitForMenuToHide(cvc);
+    }
+
+    @Test
+    @LargeTest
+    public void menuDismissal() throws InterruptedException, Throwable, TimeoutException {
+        final ContentViewCore cvc = mRule.getContentViewCore();
+        WebContents webContents = cvc.getWebContents();
+
+        DOMUtils.focusNode(webContents, "div");
+
+        SpannableString textToCommit = new SpannableString("hello");
+        SuggestionSpan suggestionSpan = new SuggestionSpan(mRule.getContentViewCore().getContext(),
+                new String[] {"goodbye"}, SuggestionSpan.FLAG_EASY_CORRECT);
+        textToCommit.setSpan(suggestionSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        mRule.commitText(textToCommit, 1);
+
+        DOMUtils.clickNode(cvc, "div");
+        waitForMenuToShow(cvc);
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                cvc.getTextSuggestionHostForTesting()
+                        .getTextSuggestionsPopupWindowForTesting()
+                        .dismiss();
+            }
+        });
+        waitForMenuToHide(cvc);
+    }
+
+    private void waitForMenuToShow(ContentViewCore cvc) {
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                SuggestionsPopupWindow suggestionsPopupWindow =
+                        cvc.getTextSuggestionHostForTesting()
+                                .getTextSuggestionsPopupWindowForTesting();
+                if (suggestionsPopupWindow == null) {
+                    return false;
+                }
+
+                // On some test runs, even when suggestionsPopupWindow is non-null and
+                // suggestionsPopupWindow.isShowing() returns true, the delete button hasn't been
+                // measured yet and getWidth()/getHeight() return 0. This causes the menu button
+                // click to instead fall on the "Add to dictionary" button. So we have to check that
+                // this isn't happening.
+                return getDeleteButton(cvc).getWidth() != 0;
+            }
+        });
+    }
+
+    private void waitForMenuToHide(ContentViewCore cvc) {
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                SuggestionsPopupWindow suggestionsPopupWindow =
+                        cvc.getTextSuggestionHostForTesting()
+                                .getTextSuggestionsPopupWindowForTesting();
+                return suggestionsPopupWindow == null;
+            }
+        });
+    }
+
+    private ListView getSuggestionList(ContentViewCore cvc) {
+        View contentView = cvc.getTextSuggestionHostForTesting()
+                                   .getTextSuggestionsPopupWindowForTesting()
+                                   .getContentViewForTesting();
+        return (ListView) contentView.findViewById(R.id.suggestionContainer);
+    }
+
+    private View getSuggestionButton(ContentViewCore cvc, int suggestionIndex) {
+        return getSuggestionList(cvc).getChildAt(suggestionIndex);
+    }
+
+    private View getDeleteButton(ContentViewCore cvc) {
+        View contentView = cvc.getTextSuggestionHostForTesting()
+                                   .getTextSuggestionsPopupWindowForTesting()
+                                   .getContentViewForTesting();
+        return contentView.findViewById(R.id.deleteButton);
+    }
+}
diff --git a/content/public/browser/devtools_manager_delegate.h b/content/public/browser/devtools_manager_delegate.h
index 1ab9489..d494775 100644
--- a/content/public/browser/devtools_manager_delegate.h
+++ b/content/public/browser/devtools_manager_delegate.h
@@ -59,8 +59,13 @@
   // Returns frontend resource data by |path|.
   virtual std::string GetFrontendResource(const std::string& path);
 
-  // Returns true for browsers running in the controlled environment that allow
-  // remote debugging.
+  // Makes browser target easily discoverable for remote debugging.
+  // This should only return true when remote debugging endpoint is not
+  // accessible by the web (for example in Chrome for Android where it is
+  // exposed via UNIX named socket) or when content/ embedder is built for
+  // running in the controlled environment (for example a special build for
+  // the Lab testing). If you want to return true here, please get security
+  // clearance from the devtools owners.
   virtual bool IsBrowserTargetDiscoverable();
 
   virtual ~DevToolsManagerDelegate();
diff --git a/content/public/common/referrer.cc b/content/public/common/referrer.cc
index 3543e43..af1b7fa 100644
--- a/content/public/common/referrer.cc
+++ b/content/public/common/referrer.cc
@@ -132,4 +132,34 @@
   return net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
 }
 
+// static
+blink::WebReferrerPolicy Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
+    net::URLRequest::ReferrerPolicy net_policy) {
+  switch (net_policy) {
+    case net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
+      return blink::kWebReferrerPolicyNoReferrerWhenDowngrade;
+    case net::URLRequest::
+        REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
+      return blink::
+          kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin;
+    case net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
+      return blink::kWebReferrerPolicyOriginWhenCrossOrigin;
+    case net::URLRequest::NEVER_CLEAR_REFERRER:
+      return blink::kWebReferrerPolicyAlways;
+    case net::URLRequest::ORIGIN:
+      return blink::kWebReferrerPolicyOrigin;
+    case net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN:
+      return blink::kWebReferrerPolicySameOrigin;
+    case net::URLRequest::ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
+      return blink::kWebReferrerPolicyStrictOrigin;
+    case net::URLRequest::NO_REFERRER:
+      return blink::kWebReferrerPolicyNever;
+    case net::URLRequest::MAX_REFERRER_POLICY:
+      NOTREACHED();
+      return blink::kWebReferrerPolicyDefault;
+  }
+  NOTREACHED();
+  return blink::kWebReferrerPolicyDefault;
+}
+
 }  // namespace content
diff --git a/content/public/common/referrer.h b/content/public/common/referrer.h
index 6e53c6b..9352725 100644
--- a/content/public/common/referrer.h
+++ b/content/public/common/referrer.h
@@ -32,6 +32,9 @@
 
   static net::URLRequest::ReferrerPolicy ReferrerPolicyForUrlRequest(
       const Referrer& referrer);
+
+  static blink::WebReferrerPolicy NetReferrerPolicyToBlinkReferrerPolicy(
+      net::URLRequest::ReferrerPolicy net_policy);
 };
 
 }  // namespace content
diff --git a/content/public/test/referrer_unittest.cc b/content/public/test/referrer_unittest.cc
index 3c3bf7b9..51146691 100644
--- a/content/public/test/referrer_unittest.cc
+++ b/content/public/test/referrer_unittest.cc
@@ -23,4 +23,24 @@
       Referrer(GURL("http://b"), static_cast<blink::WebReferrerPolicy>(200)))));
 }
 
+TEST(ReferrerTest, BlinkNetRoundTripConversion) {
+  const net::URLRequest::ReferrerPolicy policies[] = {
+      net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      net::URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      net::URLRequest::NEVER_CLEAR_REFERRER,
+      net::URLRequest::ORIGIN,
+      net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN,
+      net::URLRequest::ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      net::URLRequest::NO_REFERRER,
+  };
+
+  for (auto policy : policies) {
+    EXPECT_EQ(
+        Referrer::ReferrerPolicyForUrlRequest(Referrer(
+            GURL(), Referrer::NetReferrerPolicyToBlinkReferrerPolicy(policy))),
+        policy);
+  }
+}
+
 }  // namespace content
diff --git a/content/renderer/media/video_track_adapter.cc b/content/renderer/media/video_track_adapter.cc
index 8cfc6fb..cdc5498 100644
--- a/content/renderer/media/video_track_adapter.cc
+++ b/content/renderer/media/video_track_adapter.cc
@@ -5,6 +5,7 @@
 #include "content/renderer/media/video_track_adapter.h"
 
 #include <algorithm>
+#include <cmath>
 #include <limits>
 #include <memory>
 #include <string>
@@ -21,6 +22,7 @@
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/bind_to_current_loop.h"
+#include "media/base/limits.h"
 #include "media/base/video_util.h"
 
 namespace content {
@@ -51,6 +53,11 @@
   // |callback| will be deleted when this exits.
 }
 
+int ClampToValidDimension(int dimension) {
+  return std::min(static_cast<int>(media::limits::kMaxDimension),
+                  std::max(0, dimension));
+}
+
 }  // anonymous namespace
 
 // VideoFrameResolutionAdapter is created on and lives on the IO-thread. It does
@@ -444,46 +451,49 @@
     double min_aspect_ratio,
     double max_aspect_ratio,
     gfx::Size* desired_size) {
-  const gfx::Size& input_size =
-      is_rotated
-          ? gfx::Size(original_input_size.height(), original_input_size.width())
-          : original_input_size;
+  DCHECK(!std::isnan(min_aspect_ratio));
+  DCHECK(!std::isnan(max_aspect_ratio));
 
-  // If |frame| has larger width or height than requested, or the aspect ratio
-  // does not match the requested, we want to create a wrapped version of this
-  // frame with a size that fulfills the constraints.
-  const double input_ratio =
-      static_cast<double>(input_size.width()) / input_size.height();
+  // Perform all the cropping computations as if the device was never rotated.
+  int width =
+      is_rotated ? original_input_size.height() : original_input_size.width();
+  int height =
+      is_rotated ? original_input_size.width() : original_input_size.height();
 
-  if (input_size.width() > max_frame_size.width() ||
-      input_size.height() > max_frame_size.height() ||
-      input_ratio > max_aspect_ratio || input_ratio < min_aspect_ratio) {
-    int desired_width = std::min(max_frame_size.width(), input_size.width());
-    int desired_height = std::min(max_frame_size.height(), input_size.height());
+  // Adjust the size of the frame to the maximum allowed size.
+  width = ClampToValidDimension(std::min(width, max_frame_size.width()));
+  height = ClampToValidDimension(std::min(height, max_frame_size.height()));
 
-    const double resulting_ratio =
-        static_cast<double>(desired_width) / desired_height;
-    // Make sure |min_aspect_ratio| < |requested_ratio| < |max_aspect_ratio|.
-    const double requested_ratio =
-        std::max(std::min(resulting_ratio, max_aspect_ratio), min_aspect_ratio);
+  // If the area of the frame is zero, ignore aspect-ratio correction.
+  if (width * height > 0) {
+    double ratio = static_cast<double>(width) / height;
+    DCHECK(std::isfinite(ratio));
+    if (ratio > max_aspect_ratio || ratio < min_aspect_ratio) {
+      // Make sure |min_aspect_ratio| <= |desired_ratio| <= |max_aspect_ratio|.
+      double desired_ratio =
+          std::max(std::min(ratio, max_aspect_ratio), min_aspect_ratio);
+      DCHECK(std::isfinite(desired_ratio));
+      DCHECK_NE(desired_ratio, 0.0);
 
-    if (resulting_ratio < requested_ratio) {
-      desired_height = static_cast<int>((desired_height * resulting_ratio) /
-                                        requested_ratio);
-      // Make sure we scale to an even height to avoid rounding errors
-      desired_height = (desired_height + 1) & ~1;
-    } else if (resulting_ratio > requested_ratio) {
-      desired_width =
-          static_cast<int>((desired_width * requested_ratio) / resulting_ratio);
-      // Make sure we scale to an even width to avoid rounding errors.
-      desired_width = (desired_width + 1) & ~1;
+      if (ratio < desired_ratio) {
+        double desired_height_fp = (height * ratio) / desired_ratio;
+        DCHECK(std::isfinite(desired_height_fp));
+        height = static_cast<int>(desired_height_fp);
+        // Make sure we scale to an even height to avoid rounding errors
+        height = (height + 1) & ~1;
+      } else if (ratio > desired_ratio) {
+        double desired_width_fp = (width * desired_ratio) / ratio;
+        DCHECK(std::isfinite(desired_width_fp));
+        width = static_cast<int>(desired_width_fp);
+        // Make sure we scale to an even width to avoid rounding errors.
+        width = (width + 1) & ~1;
+      }
     }
-
-    *desired_size = is_rotated ? gfx::Size(desired_height, desired_width)
-                               : gfx::Size(desired_width, desired_height);
-  } else {
-    *desired_size = original_input_size;
   }
+
+  // Output back taking device rotation into account.
+  *desired_size =
+      is_rotated ? gfx::Size(height, width) : gfx::Size(width, height);
 }
 
 void VideoTrackAdapter::StartFrameMonitoringOnIO(
diff --git a/content/renderer/media/video_track_adapter.h b/content/renderer/media/video_track_adapter.h
index c899f9d9..b190c77 100644
--- a/content/renderer/media/video_track_adapter.h
+++ b/content/renderer/media/video_track_adapter.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "base/time/time.h"
+#include "content/common/content_export.h"
 #include "content/renderer/media/media_stream_video_track.h"
 #include "media/base/video_frame.h"
 #include "ui/gfx/geometry/size.h"
@@ -85,12 +86,14 @@
 
   void SetSourceFrameSize(const gfx::Size& source_frame_size);
 
-  static void CalculateTargetSize(bool is_rotated,
-                                  const gfx::Size& input_size,
-                                  const gfx::Size& max_frame_size,
-                                  double min_aspect_ratio,
-                                  double max_aspect_ratio,
-                                  gfx::Size* desired_size);
+  // Exported for testing.
+  CONTENT_EXPORT static void CalculateTargetSize(
+      bool is_rotated,
+      const gfx::Size& input_size,
+      const gfx::Size& max_frame_size,
+      double min_aspect_ratio,
+      double max_aspect_ratio,
+      gfx::Size* desired_size);
 
  private:
   virtual ~VideoTrackAdapter();
diff --git a/content/renderer/media/video_track_adapter_unittest.cc b/content/renderer/media/video_track_adapter_unittest.cc
new file mode 100644
index 0000000..e4d8fa29
--- /dev/null
+++ b/content/renderer/media/video_track_adapter_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/video_track_adapter.h"
+
+#include <limits>
+
+#include "media/base/limits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+// Most VideoTrackAdapter functionality is tested in MediaStreamVideoSourceTest.
+// These tests focus on the computation of cropped frame sizes in edge cases
+// that cannot be easily reproduced by a mocked video source, such as tests
+// involving frames of zero size.
+// Such frames can be produced by sources in the wild (e.g., element capture).
+
+// Test that cropped sizes with zero-area input frames are correctly computed.
+// Aspect ratio limits should be ignored.
+TEST(VideoTrackAdapterTest, ZeroInputArea) {
+  const double kMinAspectRatio = 0.1;
+  const double kMaxAspectRatio = 2.0;
+  const int kMaxWidth = 640;
+  const int kMaxHeight = 480;
+  const bool kIsRotatedValues[] = {true, false};
+
+  for (bool is_rotated : kIsRotatedValues) {
+    gfx::Size desired_size;
+
+    VideoTrackAdapter::CalculateTargetSize(
+        is_rotated, gfx::Size(0, 0), gfx::Size(kMaxWidth, kMaxHeight),
+        kMinAspectRatio, kMaxAspectRatio, &desired_size);
+    EXPECT_EQ(desired_size.width(), 0);
+    EXPECT_EQ(desired_size.height(), 0);
+
+    // Zero width.
+    VideoTrackAdapter::CalculateTargetSize(
+        is_rotated, gfx::Size(0, 300), gfx::Size(kMaxWidth, kMaxHeight),
+        kMinAspectRatio, kMaxAspectRatio, &desired_size);
+    EXPECT_EQ(desired_size.width(), 0);
+    EXPECT_EQ(desired_size.height(), 300);
+
+    // Zero height.
+    VideoTrackAdapter::CalculateTargetSize(
+        is_rotated, gfx::Size(300, 0), gfx::Size(kMaxWidth, kMaxHeight),
+        kMinAspectRatio, kMaxAspectRatio, &desired_size);
+    EXPECT_EQ(desired_size.width(), 300);
+    EXPECT_EQ(desired_size.height(), 0);
+
+    // Requires "cropping" of height.
+    VideoTrackAdapter::CalculateTargetSize(
+        is_rotated, gfx::Size(0, 1000), gfx::Size(kMaxWidth, kMaxHeight),
+        kMinAspectRatio, kMaxAspectRatio, &desired_size);
+    EXPECT_EQ(desired_size.width(), 0);
+    EXPECT_EQ(desired_size.height(), is_rotated ? kMaxWidth : kMaxHeight);
+
+    // Requires "cropping" of width.
+    VideoTrackAdapter::CalculateTargetSize(
+        is_rotated, gfx::Size(1000, 0), gfx::Size(kMaxWidth, kMaxHeight),
+        kMinAspectRatio, kMaxAspectRatio, &desired_size);
+    EXPECT_EQ(desired_size.width(), is_rotated ? kMaxHeight : kMaxWidth);
+    EXPECT_EQ(desired_size.height(), 0);
+  }
+}
+
+// Test that zero-size cropped areas are correctly computed. Aspect ratio
+// limits should be ignored.
+TEST(VideoTrackAdapterTest, ZeroOutputArea) {
+  const double kMinAspectRatio = 0.1;
+  const double kMaxAspectRatio = 2.0;
+  const int kInputWidth = 640;
+  const int kInputHeight = 480;
+
+  gfx::Size desired_size;
+
+  VideoTrackAdapter::CalculateTargetSize(
+      false /* is_rotated */, gfx::Size(kInputWidth, kInputHeight),
+      gfx::Size(0, 0), kMinAspectRatio, kMaxAspectRatio, &desired_size);
+  EXPECT_EQ(desired_size.width(), 0);
+  EXPECT_EQ(desired_size.height(), 0);
+
+  // Width is cropped to zero.
+  VideoTrackAdapter::CalculateTargetSize(
+      false /* is_rotated */, gfx::Size(kInputWidth, kInputHeight),
+      gfx::Size(0, 1000), kMinAspectRatio, kMaxAspectRatio, &desired_size);
+  EXPECT_EQ(desired_size.width(), 0);
+  EXPECT_EQ(desired_size.height(), kInputHeight);
+
+  // Requires "cropping" of width and height.
+  VideoTrackAdapter::CalculateTargetSize(
+      false /* is_rotated */, gfx::Size(kInputWidth, kInputHeight),
+      gfx::Size(0, 300), kMinAspectRatio, kMaxAspectRatio, &desired_size);
+  EXPECT_EQ(desired_size.width(), 0);
+  EXPECT_EQ(desired_size.height(), 300);
+
+  // Height is cropped to zero.
+  VideoTrackAdapter::CalculateTargetSize(
+      false /* is_rotated */, gfx::Size(kInputWidth, kInputHeight),
+      gfx::Size(1000, 0), kMinAspectRatio, kMaxAspectRatio, &desired_size);
+  EXPECT_EQ(desired_size.width(), kInputWidth);
+  EXPECT_EQ(desired_size.height(), 0);
+
+  // Requires "cropping" of width and height.
+  VideoTrackAdapter::CalculateTargetSize(
+      false /* is_rotated */, gfx::Size(kInputWidth, kInputHeight),
+      gfx::Size(300, 0), kMinAspectRatio, kMaxAspectRatio, &desired_size);
+  EXPECT_EQ(desired_size.width(), 300);
+  EXPECT_EQ(desired_size.height(), 0);
+}
+
+// Test that large frame sizes are clamped to the maximum supported dimension.
+TEST(VideoTrackAdapterTest, ClampToMaxDimension) {
+  const double kMinAspectRatio = 0.0;
+  const double kMaxAspectRatio = HUGE_VAL;
+  const int kInputWidth = std::numeric_limits<int>::max();
+  const int kInputHeight = std::numeric_limits<int>::max();
+  const int kMaxWidth = std::numeric_limits<int>::max();
+  const int kMaxHeight = std::numeric_limits<int>::max();
+
+  gfx::Size desired_size;
+
+  VideoTrackAdapter::CalculateTargetSize(
+      false /* is_rotated */, gfx::Size(kInputWidth, kInputHeight),
+      gfx::Size(kMaxWidth, kMaxHeight), kMinAspectRatio, kMaxAspectRatio,
+      &desired_size);
+  EXPECT_EQ(desired_size.width(), media::limits::kMaxDimension);
+  EXPECT_EQ(desired_size.height(), media::limits::kMaxDimension);
+}
+
+}  // namespace content
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 358ec4b..3272333 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -2010,7 +2010,14 @@
   WebWidget* web_widget = GetWebWidget();
   if (web_widget && web_widget->IsWebFrameWidget()) {
     WebFrameWidget* web_frame_widget = static_cast<WebFrameWidget*>(web_widget);
-    web_frame_widget->LocalRoot()->SendOrientationChangeEvent();
+    // LocalRoot() might return null for provisional main frames. In this case,
+    // the frame hasn't committed a navigation and is not swapped into the tree
+    // yet, so it doesn't make sense to send orientation change events to it.
+    //
+    // TODO(https://crbug.com/578349): This check should be cleaned up
+    // once provisional frames are gone.
+    if (web_frame_widget->LocalRoot())
+      web_frame_widget->LocalRoot()->SendOrientationChangeEvent();
   }
 }
 
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index ad76d63..b629409 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -102,8 +102,6 @@
     "browser/renderer_host/shell_render_widget_host_view_mac_delegate.mm",
     "browser/shell.cc",
     "browser/shell.h",
-    "browser/shell_access_token_store.cc",
-    "browser/shell_access_token_store.h",
     "browser/shell_android.cc",
     "browser/shell_application_mac.h",
     "browser/shell_application_mac.mm",
diff --git a/content/shell/browser/shell_access_token_store.cc b/content/shell/browser/shell_access_token_store.cc
deleted file mode 100644
index 2766617..0000000
--- a/content/shell/browser/shell_access_token_store.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/shell/browser/shell_access_token_store.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/shell/browser/shell_browser_context.h"
-
-namespace content {
-
-ShellAccessTokenStore::ShellAccessTokenStore(
-    content::ShellBrowserContext* shell_browser_context)
-    : shell_browser_context_(shell_browser_context),
-      system_request_context_(NULL) {
-}
-
-ShellAccessTokenStore::~ShellAccessTokenStore() {
-}
-
-void ShellAccessTokenStore::LoadAccessTokens(
-    const LoadAccessTokensCallback& callback) {
-  BrowserThread::PostTaskAndReply(
-      BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&ShellAccessTokenStore::GetRequestContextOnUIThread, this,
-                     shell_browser_context_),
-      base::BindOnce(&ShellAccessTokenStore::RespondOnOriginatingThread, this,
-                     callback));
-}
-
-void ShellAccessTokenStore::GetRequestContextOnUIThread(
-    content::ShellBrowserContext* shell_browser_context) {
-  system_request_context_ =
-      BrowserContext::GetDefaultStoragePartition(shell_browser_context)->
-          GetURLRequestContext();
-}
-
-void ShellAccessTokenStore::RespondOnOriginatingThread(
-    const LoadAccessTokensCallback& callback) {
-  callback.Run(AccessTokenMap(), system_request_context_);
-  system_request_context_ = NULL;
-}
-
-void ShellAccessTokenStore::SaveAccessToken(
-    const GURL& server_url, const base::string16& access_token) {
-}
-
-}  // namespace content
diff --git a/content/shell/browser/shell_access_token_store.h b/content/shell/browser/shell_access_token_store.h
deleted file mode 100644
index 2a7aedb..0000000
--- a/content/shell/browser/shell_access_token_store.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SHELL_BROWSER_SHELL_ACCESS_TOKEN_STORE_H_
-#define CONTENT_SHELL_BROWSER_SHELL_ACCESS_TOKEN_STORE_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "device/geolocation/access_token_store.h"
-#include "net/url_request/url_request_context_getter.h"
-
-namespace content {
-class ShellBrowserContext;
-
-// Dummy access token store used to initialise the network location provider.
-class ShellAccessTokenStore : public device::AccessTokenStore {
- public:
-  explicit ShellAccessTokenStore(
-      content::ShellBrowserContext* shell_browser_context);
-
- private:
-  ~ShellAccessTokenStore() override;
-
-  void GetRequestContextOnUIThread(
-      content::ShellBrowserContext* shell_browser_context);
-  void RespondOnOriginatingThread(const LoadAccessTokensCallback& callback);
-
-  // AccessTokenStore
-  void LoadAccessTokens(const LoadAccessTokensCallback& callback) override;
-
-  void SaveAccessToken(const GURL& server_url,
-                       const base::string16& access_token) override;
-
-  content::ShellBrowserContext* shell_browser_context_;
-  scoped_refptr<net::URLRequestContextGetter> system_request_context_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellAccessTokenStore);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_BROWSER_SHELL_ACCESS_TOKEN_STORE_H_
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
index 9dc6adb..e739a42 100644
--- a/content/shell/browser/shell_browser_main_parts.cc
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -20,12 +20,12 @@
 #include "content/public/common/url_constants.h"
 #include "content/shell/android/shell_descriptors.h"
 #include "content/shell/browser/shell.h"
-#include "content/shell/browser/shell_access_token_store.h"
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_devtools_manager_delegate.h"
 #include "content/shell/browser/shell_net_log.h"
 #include "content/shell/common/shell_switches.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/geolocation/access_token_store.h"
 #include "device/geolocation/geolocation_delegate.h"
 #include "device/geolocation/geolocation_provider.h"
 #include "net/base/filename_util.h"
@@ -66,19 +66,18 @@
 // A provider of services for Geolocation.
 class ShellGeolocationDelegate : public device::GeolocationDelegate {
  public:
-  explicit ShellGeolocationDelegate(ShellBrowserContext* context)
-      : context_(context) {}
+  ShellGeolocationDelegate() = default;
 
   // Since content shell is a test executable, rather than an end-user program,
   // don't make calls to the network geolocation API.
   bool UseNetworkLocationProviders() override { return false; }
 
   scoped_refptr<device::AccessTokenStore> CreateAccessTokenStore() final {
-    return new ShellAccessTokenStore(context_);
+    NOTREACHED() << "No network geolocation for content shell";
+    return nullptr;
   }
 
  private:
-  ShellBrowserContext* context_;
   DISALLOW_COPY_AND_ASSIGN(ShellGeolocationDelegate);
 };
 
@@ -196,7 +195,7 @@
   net_log_.reset(new ShellNetLog("content_shell"));
   InitializeBrowserContexts();
   device::GeolocationProvider::SetGeolocationDelegate(
-      new ShellGeolocationDelegate(browser_context()));
+      new ShellGeolocationDelegate());
   Shell::Initialize();
   net::NetModule::SetResourceProvider(PlatformResourceProvider);
   ShellDevToolsManagerDelegate::StartHttpHandler(browser_context_.get());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index fb64334..2f661c7 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1726,6 +1726,7 @@
       "../renderer/media/rtc_peer_connection_handler_unittest.cc",
       "../renderer/media/speech_recognition_audio_sink_unittest.cc",
       "../renderer/media/user_media_client_impl_unittest.cc",
+      "../renderer/media/video_track_adapter_unittest.cc",
       "../renderer/media/webmediaplayer_ms_unittest.cc",
       "../renderer/media/webrtc/media_stream_remote_video_source_unittest.cc",
       "../renderer/media/webrtc/media_stream_track_metrics_unittest.cc",
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index cd7fb77..450e6239 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1211,14 +1211,11 @@
             'gpu': '10de:104a',
             'os': 'Windows-2008ServerR2-SP1'
           },
-          # Temporarily disable AMD deqp ES3 tests due to issues with the log
-          # size causing out-of-memory errors in the recipe engine.
-          # crbug.com/713196
           # AMD Win 7
-          #{
-          #  'gpu': '1002:6613',
-          #  'os': 'Windows-2008ServerR2-SP1'
-          #}
+          {
+            'gpu': '1002:6613',
+            'os': 'Windows-2008ServerR2-SP1'
+          },
         ],
       }
     ],
diff --git a/device/geolocation/geolocation_delegate.h b/device/geolocation/geolocation_delegate.h
index a3f621bd..6ae260f 100644
--- a/device/geolocation/geolocation_delegate.h
+++ b/device/geolocation/geolocation_delegate.h
@@ -25,6 +25,7 @@
   virtual bool UseNetworkLocationProviders();
 
   // Creates a new AccessTokenStore for geolocation. May return nullptr.
+  // Won't be called unless UseNetworkLocationProviders() is true.
   virtual scoped_refptr<AccessTokenStore> CreateAccessTokenStore();
 
   // Allows an embedder to return its own LocationProvider implementation.
diff --git a/device/geolocation/location_arbitrator.cc b/device/geolocation/location_arbitrator.cc
index bf747c2..872b111 100644
--- a/device/geolocation/location_arbitrator.cc
+++ b/device/geolocation/location_arbitrator.cc
@@ -60,15 +60,17 @@
   if (providers_.empty()) {
     RegisterSystemProvider();
 
-    const scoped_refptr<AccessTokenStore> access_token_store =
-        GetAccessTokenStore();
-    if (access_token_store && delegate_->UseNetworkLocationProviders()) {
-      DCHECK(DefaultNetworkProviderURL().is_valid());
-      token_store_callback_.Reset(
-          base::Bind(&LocationArbitrator::OnAccessTokenStoresLoaded,
-                     base::Unretained(this)));
-      access_token_store->LoadAccessTokens(token_store_callback_.callback());
-      return true;
+    if (delegate_->UseNetworkLocationProviders()) {
+      const scoped_refptr<AccessTokenStore> access_token_store =
+          GetAccessTokenStore();
+      if (access_token_store) {
+        DCHECK(DefaultNetworkProviderURL().is_valid());
+        token_store_callback_.Reset(
+            base::Bind(&LocationArbitrator::OnAccessTokenStoresLoaded,
+                       base::Unretained(this)));
+        access_token_store->LoadAccessTokens(token_store_callback_.callback());
+        return true;
+      }
     }
   }
   return DoStartProviders();
diff --git a/extensions/browser/api/networking_private/networking_private_api.cc b/extensions/browser/api/networking_private/networking_private_api.cc
index f9fa173..72ab2397 100644
--- a/extensions/browser/api/networking_private/networking_private_api.cc
+++ b/extensions/browser/api/networking_private/networking_private_api.cc
@@ -1041,6 +1041,47 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// NetworkingPrivateSelectCellularMobileNetworkFunction
+
+NetworkingPrivateSelectCellularMobileNetworkFunction::
+    ~NetworkingPrivateSelectCellularMobileNetworkFunction() {}
+
+ExtensionFunction::ResponseAction
+NetworkingPrivateSelectCellularMobileNetworkFunction::Run() {
+  if (!HasPrivateNetworkingAccess(extension(), source_context_type(),
+                                  source_url())) {
+    return RespondNow(Error(kPrivateOnlyError));
+  }
+
+  std::unique_ptr<private_api::SelectCellularMobileNetwork::Params> params =
+      private_api::SelectCellularMobileNetwork::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  GetDelegate(browser_context())
+      ->SelectCellularMobileNetwork(
+          params->network_guid, params->network_id,
+          base::Bind(
+              &NetworkingPrivateSelectCellularMobileNetworkFunction::Success,
+              this),
+          base::Bind(
+              &NetworkingPrivateSelectCellularMobileNetworkFunction::Failure,
+              this));
+  // Success() or Failure() might have been called synchronously at this point.
+  // In that case this function has already called Respond(). Return
+  // AlreadyResponded() in that case.
+  return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void NetworkingPrivateSelectCellularMobileNetworkFunction::Success() {
+  Respond(NoArguments());
+}
+
+void NetworkingPrivateSelectCellularMobileNetworkFunction::Failure(
+    const std::string& error) {
+  Respond(Error(error));
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // NetworkingPrivateGetGlobalPolicyFunction
 
 NetworkingPrivateGetGlobalPolicyFunction::
diff --git a/extensions/browser/api/networking_private/networking_private_api.h b/extensions/browser/api/networking_private/networking_private_api.h
index dc9ff8f9..bf886519 100644
--- a/extensions/browser/api/networking_private/networking_private_api.h
+++ b/extensions/browser/api/networking_private/networking_private_api.h
@@ -512,6 +512,27 @@
   DISALLOW_COPY_AND_ASSIGN(NetworkingPrivateSetCellularSimStateFunction);
 };
 
+class NetworkingPrivateSelectCellularMobileNetworkFunction
+    : public UIThreadExtensionFunction {
+ public:
+  NetworkingPrivateSelectCellularMobileNetworkFunction() {}
+  DECLARE_EXTENSION_FUNCTION("networkingPrivate.selectCellularMobileNetwork",
+                             NETWORKINGPRIVATE_SELECTCELLULARMOBILENETWORK);
+
+  // ExtensionFunction:
+  ResponseAction Run() override;
+
+ protected:
+  ~NetworkingPrivateSelectCellularMobileNetworkFunction() override;
+
+ private:
+  void Success();
+  void Failure(const std::string& error);
+
+  DISALLOW_COPY_AND_ASSIGN(
+      NetworkingPrivateSelectCellularMobileNetworkFunction);
+};
+
 class NetworkingPrivateGetGlobalPolicyFunction
     : public UIThreadExtensionFunction {
  public:
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos.cc b/extensions/browser/api/networking_private/networking_private_chromeos.cc
index 8e85486..0eb841e 100644
--- a/extensions/browser/api/networking_private/networking_private_chromeos.cc
+++ b/extensions/browser/api/networking_private/networking_private_chromeos.cc
@@ -710,6 +710,21 @@
       base::Bind(&NetworkHandlerFailureCallback, failure_callback));
 }
 
+void NetworkingPrivateChromeOS::SelectCellularMobileNetwork(
+    const std::string& guid,
+    const std::string& network_id,
+    const VoidCallback& success_callback,
+    const FailureCallback& failure_callback) {
+  const chromeos::DeviceState* device_state = GetCellularDeviceState(guid);
+  if (!device_state) {
+    failure_callback.Run(networking_private::kErrorNetworkUnavailable);
+    return;
+  }
+  NetworkHandler::Get()->network_device_handler()->RegisterCellularNetwork(
+      device_state->path(), network_id, success_callback,
+      base::Bind(&NetworkHandlerFailureCallback, failure_callback));
+}
+
 std::unique_ptr<base::ListValue>
 NetworkingPrivateChromeOS::GetEnabledNetworkTypes() {
   chromeos::NetworkStateHandler* state_handler = GetStateHandler();
diff --git a/extensions/browser/api/networking_private/networking_private_chromeos.h b/extensions/browser/api/networking_private/networking_private_chromeos.h
index cf66941..9750a604 100644
--- a/extensions/browser/api/networking_private/networking_private_chromeos.h
+++ b/extensions/browser/api/networking_private/networking_private_chromeos.h
@@ -91,6 +91,11 @@
                            const std::string& new_pin,
                            const VoidCallback& success_callback,
                            const FailureCallback& failure_callback) override;
+  void SelectCellularMobileNetwork(
+      const std::string& guid,
+      const std::string& network_id,
+      const VoidCallback& success_callback,
+      const FailureCallback& failure_callback) override;
   std::unique_ptr<base::ListValue> GetEnabledNetworkTypes() override;
   std::unique_ptr<DeviceStateList> GetDeviceStateList() override;
   std::unique_ptr<base::DictionaryValue> GetGlobalPolicy() override;
diff --git a/extensions/browser/api/networking_private/networking_private_delegate.h b/extensions/browser/api/networking_private/networking_private_delegate.h
index 9cd7c90..1d1fe42 100644
--- a/extensions/browser/api/networking_private/networking_private_delegate.h
+++ b/extensions/browser/api/networking_private/networking_private_delegate.h
@@ -126,6 +126,11 @@
                                    const std::string& new_pin,
                                    const VoidCallback& success_callback,
                                    const FailureCallback& failure_callback) = 0;
+  virtual void SelectCellularMobileNetwork(
+      const std::string& guid,
+      const std::string& network_id,
+      const VoidCallback& success_callback,
+      const FailureCallback& failure_callback) = 0;
 
   // Synchronous methods
 
diff --git a/extensions/browser/api/networking_private/networking_private_linux.cc b/extensions/browser/api/networking_private/networking_private_linux.cc
index 03e8f0f..e519812 100644
--- a/extensions/browser/api/networking_private/networking_private_linux.cc
+++ b/extensions/browser/api/networking_private/networking_private_linux.cc
@@ -571,6 +571,14 @@
   ReportNotSupported("SetCellularSimState", failure_callback);
 }
 
+void NetworkingPrivateLinux::SelectCellularMobileNetwork(
+    const std::string& guid,
+    const std::string& network_id,
+    const VoidCallback& success_callback,
+    const FailureCallback& failure_callback) {
+  ReportNotSupported("SelectCellularMobileNetwork", failure_callback);
+}
+
 std::unique_ptr<base::ListValue>
 NetworkingPrivateLinux::GetEnabledNetworkTypes() {
   std::unique_ptr<base::ListValue> network_list(new base::ListValue);
diff --git a/extensions/browser/api/networking_private/networking_private_linux.h b/extensions/browser/api/networking_private/networking_private_linux.h
index 8f7b83bc..2a15c26 100644
--- a/extensions/browser/api/networking_private/networking_private_linux.h
+++ b/extensions/browser/api/networking_private/networking_private_linux.h
@@ -92,6 +92,11 @@
                            const std::string& new_pin,
                            const VoidCallback& success_callback,
                            const FailureCallback& failure_callback) override;
+  void SelectCellularMobileNetwork(
+      const std::string& guid,
+      const std::string& network_id,
+      const VoidCallback& success_callback,
+      const FailureCallback& failure_callback) override;
   std::unique_ptr<base::ListValue> GetEnabledNetworkTypes() override;
   std::unique_ptr<DeviceStateList> GetDeviceStateList() override;
   std::unique_ptr<base::DictionaryValue> GetGlobalPolicy() override;
diff --git a/extensions/browser/api/networking_private/networking_private_service_client.cc b/extensions/browser/api/networking_private/networking_private_service_client.cc
index 511baa1..63c04257 100644
--- a/extensions/browser/api/networking_private/networking_private_service_client.cc
+++ b/extensions/browser/api/networking_private/networking_private_service_client.cc
@@ -337,6 +337,14 @@
   failure_callback.Run(networking_private::kErrorNotSupported);
 }
 
+void NetworkingPrivateServiceClient::SelectCellularMobileNetwork(
+    const std::string& guid,
+    const std::string& network_id,
+    const VoidCallback& success_callback,
+    const FailureCallback& failure_callback) {
+  failure_callback.Run(networking_private::kErrorNotSupported);
+}
+
 std::unique_ptr<base::ListValue>
 NetworkingPrivateServiceClient::GetEnabledNetworkTypes() {
   std::unique_ptr<base::ListValue> network_list;
diff --git a/extensions/browser/api/networking_private/networking_private_service_client.h b/extensions/browser/api/networking_private/networking_private_service_client.h
index a67490c..f6fe82fb 100644
--- a/extensions/browser/api/networking_private/networking_private_service_client.h
+++ b/extensions/browser/api/networking_private/networking_private_service_client.h
@@ -105,6 +105,11 @@
                            const std::string& new_pin,
                            const VoidCallback& success_callback,
                            const FailureCallback& failure_callback) override;
+  void SelectCellularMobileNetwork(
+      const std::string& guid,
+      const std::string& network_id,
+      const VoidCallback& success_callback,
+      const FailureCallback& failure_callback) override;
   std::unique_ptr<base::ListValue> GetEnabledNetworkTypes() override;
   std::unique_ptr<DeviceStateList> GetDeviceStateList() override;
   std::unique_ptr<base::DictionaryValue> GetGlobalPolicy() override;
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index cbdda27..22ba41f 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1253,6 +1253,7 @@
   FILEMANAGERPRIVATE_RENAMEVOLUME,
   AUTOTESTPRIVATE_SETMOUSEREVERSESCROLL,
   METRICSPRIVATE_RECORDSPARSEHASHABLE,
+  NETWORKINGPRIVATE_SELECTCELLULARMOBILENETWORK,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/common/api/networking_private.idl b/extensions/common/api/networking_private.idl
index c029d340..3ceeab8 100644
--- a/extensions/common/api/networking_private.idl
+++ b/extensions/common/api/networking_private.idl
@@ -1102,6 +1102,17 @@
                                     CellularSimState simState,
                                     optional VoidCallback callback);
 
+    // Selects which Cellular Mobile Network to use. |networkId| must be the
+    // NetworkId property of a member of Cellular.FoundNetworks from the
+    // network properties for the specified Cellular network.
+    // |networkGuid|: The GUID of the cellular network to select the network
+    //     for. If empty, the default cellular device will be used.
+    // |networkId|: The networkId to select.
+    // |callback|: Called when the operation has completed.
+    static void selectCellularMobileNetwork(DOMString networkGuid,
+                                            DOMString networkId,
+                                            optional VoidCallback callback);
+
     // Gets the global policy properties. These properties are not expected to
     // change during a session.
     static void getGlobalPolicy(GetGlobalPolicyCallback callback);
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index ce6f2424..83a86d9 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -66,7 +66,8 @@
   DOLBYVISION_PROFILE4,
   DOLBYVISION_PROFILE5,
   DOLBYVISION_PROFILE7,
-  VIDEO_CODEC_PROFILE_MAX = DOLBYVISION_PROFILE7,
+  THEORAPROFILE_ANY,
+  VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY,
 };
 
 // Specification of a decoding profile supported by a hardware decoder.
diff --git a/gpu/ipc/common/gpu_info.mojom b/gpu/ipc/common/gpu_info.mojom
index 7d8feda..f4d3364 100644
--- a/gpu/ipc/common/gpu_info.mojom
+++ b/gpu/ipc/common/gpu_info.mojom
@@ -53,6 +53,7 @@
   DOLBYVISION_PROFILE4,
   DOLBYVISION_PROFILE5,
   DOLBYVISION_PROFILE7,
+  THEORAPROFILE_ANY,
 };
 
 // gpu::VideoDecodeAcceleratorSupportedProfile
diff --git a/gpu/ipc/common/gpu_info_struct_traits.cc b/gpu/ipc/common/gpu_info_struct_traits.cc
index 0b38785f..6504fced 100644
--- a/gpu/ipc/common/gpu_info_struct_traits.cc
+++ b/gpu/ipc/common/gpu_info_struct_traits.cc
@@ -114,6 +114,8 @@
       return gpu::mojom::VideoCodecProfile::DOLBYVISION_PROFILE5;
     case gpu::VideoCodecProfile::DOLBYVISION_PROFILE7:
       return gpu::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7;
+    case gpu::VideoCodecProfile::THEORAPROFILE_ANY:
+      return gpu::mojom::VideoCodecProfile::THEORAPROFILE_ANY;
   }
   NOTREACHED() << "Invalid VideoCodecProfile:" << video_codec_profile;
   return gpu::mojom::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN;
@@ -196,6 +198,9 @@
     case gpu::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7:
       *out = gpu::VideoCodecProfile::DOLBYVISION_PROFILE7;
       return true;
+    case gpu::mojom::VideoCodecProfile::THEORAPROFILE_ANY:
+      *out = gpu::VideoCodecProfile::THEORAPROFILE_ANY;
+      return true;
   }
   NOTREACHED() << "Invalid VideoCodecProfile: " << input;
   return false;
diff --git a/ios/build/bots/chromium.mac/ios-device-xcode-clang.json b/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
index 0a1be74..7b4a376 100644
--- a/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
+++ b/ios/build/bots/chromium.mac/ios-device-xcode-clang.json
@@ -15,6 +15,9 @@
     "use_goma=true",
     "use_xcode_clang=true"
   ],
+  "env": {
+    "IOS_TOOLCHAIN_REVISION": "9M214v-1"
+  },
   "additional_compile_targets": [
     "all"
   ],
diff --git a/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json b/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
index f45aaac7..b7ce7429 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-xcode-clang.json
@@ -15,6 +15,9 @@
     "use_goma=true",
     "use_xcode_clang=true"
   ],
+   "env": {
+    "IOS_TOOLCHAIN_REVISION": "9M214v-1"
+  },
   "additional_compile_targets": [
     "all"
   ],
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index 583e421..e5bdf51 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -738,6 +738,21 @@
       GetStringToCodecMap().find(codec_id);
   if (itr != GetStringToCodecMap().end()) {
     out_result->codec = itr->second;
+
+    // Even "simple" video codecs should have an associated profile.
+    if (MimeUtilToVideoCodec(out_result->codec) != kUnknownVideoCodec) {
+      switch (out_result->codec) {
+        case Codec::VP8:
+          out_result->video_profile = VP8PROFILE_ANY;
+          break;
+        case Codec::THEORA:
+          out_result->video_profile = THEORAPROFILE_ANY;
+          break;
+        default:
+          NOTREACHED();
+      }
+    }
+
     return true;
   }
 
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
index 3c2cca4..503afd2 100644
--- a/media/base/mime_util_unittest.cc
+++ b/media/base/mime_util_unittest.cc
@@ -370,6 +370,43 @@
                                      &out_codec));
 }
 
+// These codecs really only have one profile. Ensure that |out_profile| is
+// correctly mapped.
+TEST(MimeUtilTest, ParseVideoCodecString_SimpleCodecsHaveProfiles) {
+  bool out_is_ambiguous;
+  VideoCodec out_codec;
+  VideoCodecProfile out_profile;
+  uint8_t out_level;
+  VideoColorSpace out_colorspace;
+
+  // Valid VP8 string.
+  EXPECT_TRUE(ParseVideoCodecString("video/webm", "vp8", &out_is_ambiguous,
+                                    &out_codec, &out_profile, &out_level,
+                                    &out_colorspace));
+  EXPECT_FALSE(out_is_ambiguous);
+  EXPECT_EQ(kCodecVP8, out_codec);
+  EXPECT_EQ(VP8PROFILE_ANY, out_profile);
+  EXPECT_EQ(0, out_level);
+  EXPECT_EQ(VideoColorSpace::REC709(), out_colorspace);
+
+// Valid Theora string.
+#if defined(OS_ANDROID)
+  // Theora not supported on Android.
+  EXPECT_FALSE(ParseVideoCodecString("video/ogg", "theora", &out_is_ambiguous,
+                                     &out_codec, &out_profile, &out_level,
+                                     &out_colorspace));
+#else
+  EXPECT_TRUE(ParseVideoCodecString("video/ogg", "theora", &out_is_ambiguous,
+                                    &out_codec, &out_profile, &out_level,
+                                    &out_colorspace));
+  EXPECT_FALSE(out_is_ambiguous);
+  EXPECT_EQ(kCodecTheora, out_codec);
+  EXPECT_EQ(THEORAPROFILE_ANY, out_profile);
+  EXPECT_EQ(0, out_level);
+  EXPECT_EQ(VideoColorSpace::REC709(), out_colorspace);
+#endif
+}
+
 TEST(IsCodecSupportedOnAndroidTest, EncryptedCodecsFailWithoutPlatformSupport) {
   // Vary all parameters except |has_platform_decoders|.
   MimeUtil::PlatformInfo states_to_vary = VaryAllFields();
diff --git a/media/base/video_codecs.cc b/media/base/video_codecs.cc
index 6edf163..854f489 100644
--- a/media/base/video_codecs.cc
+++ b/media/base/video_codecs.cc
@@ -90,6 +90,8 @@
       return "dolby vision profile 5";
     case DOLBYVISION_PROFILE7:
       return "dolby vision profile 7";
+    case THEORAPROFILE_ANY:
+      return "theora";
   }
   NOTREACHED();
   return "";
diff --git a/media/base/video_codecs.h b/media/base/video_codecs.h
index 8d9c25f..ea90e340 100644
--- a/media/base/video_codecs.h
+++ b/media/base/video_codecs.h
@@ -85,7 +85,10 @@
   DOLBYVISION_PROFILE5 = 21,
   DOLBYVISION_PROFILE7 = 22,
   DOLBYVISION_MAX = DOLBYVISION_PROFILE7,
-  VIDEO_CODEC_PROFILE_MAX = DOLBYVISION_MAX,
+  THEORAPROFILE_MIN = 23,
+  THEORAPROFILE_ANY = THEORAPROFILE_MIN,
+  THEORAPROFILE_MAX = THEORAPROFILE_ANY,
+  VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY,
 };
 
 struct CodecProfileLevel {
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index 845c37a..ba4dd9b 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -45,6 +45,8 @@
     case DOLBYVISION_PROFILE5:
     case DOLBYVISION_PROFILE7:
       return kCodecDolbyVision;
+    case THEORAPROFILE_ANY:
+      return kCodecTheora;
   }
   NOTREACHED();
   return kUnknownVideoCodec;
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 1849729..cb18b36 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -471,6 +471,8 @@
     // TODO(servolk): Find a way to obtain actual VP9 profile from FFmpeg.
     // crbug.com/592074
     profile = VP9PROFILE_PROFILE0;
+  else if (codec == kCodecTheora)
+    profile = THEORAPROFILE_ANY;
   else
     profile = ProfileIDToVideoCodecProfile(codec_context->profile);
 
diff --git a/media/remoting/proto_enum_utils.cc b/media/remoting/proto_enum_utils.cc
index eaea1a2..5613ea25 100644
--- a/media/remoting/proto_enum_utils.cc
+++ b/media/remoting/proto_enum_utils.cc
@@ -276,6 +276,7 @@
     CASE_RETURN_OTHER(DOLBYVISION_PROFILE4);
     CASE_RETURN_OTHER(DOLBYVISION_PROFILE5);
     CASE_RETURN_OTHER(DOLBYVISION_PROFILE7);
+    CASE_RETURN_OTHER(THEORAPROFILE_ANY);
   }
   return base::nullopt;  // Not a 'default' to ensure compile-time checks.
 }
@@ -309,6 +310,7 @@
     CASE_RETURN_OTHER(DOLBYVISION_PROFILE4);
     CASE_RETURN_OTHER(DOLBYVISION_PROFILE5);
     CASE_RETURN_OTHER(DOLBYVISION_PROFILE7);
+    CASE_RETURN_OTHER(THEORAPROFILE_ANY);
   }
   return base::nullopt;  // Not a 'default' to ensure compile-time checks.
 }
diff --git a/media/remoting/rpc.proto b/media/remoting/rpc.proto
index 7d21923..0811b7fe 100644
--- a/media/remoting/rpc.proto
+++ b/media/remoting/rpc.proto
@@ -181,6 +181,7 @@
     DOLBYVISION_PROFILE4 = 20;
     DOLBYVISION_PROFILE5 = 21;
     DOLBYVISION_PROFILE7 = 22;
+    THEORAPROFILE_ANY = 23;
   };
 
   // Proto version of media::VideoPixelFormat.
diff --git a/mojo/edk/system/watcher_set.h b/mojo/edk/system/watcher_set.h
index 2b7ef2c..77ddd88 100644
--- a/mojo/edk/system/watcher_set.h
+++ b/mojo/edk/system/watcher_set.h
@@ -5,8 +5,7 @@
 #ifndef MOJO_EDK_SYSTEM_WATCHER_SET_H_
 #define MOJO_EDK_SYSTEM_WATCHER_SET_H_
 
-#include <map>
-
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
@@ -59,7 +58,7 @@
   };
 
   Dispatcher* const owner_;
-  std::map<WatcherDispatcher*, Entry> watchers_;
+  base::flat_map<WatcherDispatcher*, Entry> watchers_;
   base::Optional<HandleSignalsState> last_known_state_;
 
   DISALLOW_COPY_AND_ASSIGN(WatcherSet);
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 7cdd373..15ba3e0 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -38,6 +38,9 @@
 enable_built_in_dns = !is_ios && !is_proto_quic
 enable_net_mojo = !is_ios && !is_proto_quic
 
+# Unix sockets are not supported on iOS, Fuchsia or NaCl.
+enable_unix_sockets = is_posix && !is_ios && !is_fuchsia && !is_nacl
+
 # True if certificates are represented with DER byte buffers. This can be true
 # in addition to use_nss_certs, in that case byte certs are used internally but
 # NSS is used for certificate verification.
@@ -1520,10 +1523,6 @@
       "socket/udp_socket_posix.h",
       "socket/udp_socket_win.cc",
       "socket/udp_socket_win.h",
-      "socket/unix_domain_client_socket_posix.cc",
-      "socket/unix_domain_client_socket_posix.h",
-      "socket/unix_domain_server_socket_posix.cc",
-      "socket/unix_domain_server_socket_posix.h",
       "socket/websocket_endpoint_lock_manager.cc",
       "socket/websocket_endpoint_lock_manager.h",
       "socket/websocket_transport_client_socket_pool.cc",
@@ -1985,6 +1984,15 @@
     public_deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
   }
 
+  if (enable_unix_sockets) {
+    sources += [
+      "socket/unix_domain_client_socket_posix.cc",
+      "socket/unix_domain_client_socket_posix.h",
+      "socket/unix_domain_server_socket_posix.cc",
+      "socket/unix_domain_server_socket_posix.h",
+    ]
+  }
+
   # Add back some sources that were otherwise filtered out.
   set_sources_assignment_filter([])
   sources += net_unfiltered_sources
@@ -5084,8 +5092,6 @@
     "socket/transport_client_socket_pool_unittest.cc",
     "socket/transport_client_socket_unittest.cc",
     "socket/udp_socket_unittest.cc",
-    "socket/unix_domain_client_socket_posix_unittest.cc",
-    "socket/unix_domain_server_socket_posix_unittest.cc",
     "socket/websocket_endpoint_lock_manager_unittest.cc",
     "socket/websocket_transport_client_socket_pool_unittest.cc",
     "spdy/chromium/bidirectional_stream_spdy_impl_unittest.cc",
@@ -5506,18 +5512,19 @@
 
       # Needs GetAppOutput().
       "test/python_utils_unittest.cc",
-
-      # The following tests are disabled because they don't apply to
-      # iOS.
-      # OS is not "linux" or "freebsd" or "openbsd".
-      "socket/unix_domain_client_socket_posix_unittest.cc",
-      "socket/unix_domain_server_socket_posix_unittest.cc",
     ]
     net_unfiltered_sources += [ "cert/x509_util_ios_and_mac_unittest.cc" ]
 
     bundle_deps = [ ":net_unittests_bundle_data" ]
   }
 
+  if (enable_unix_sockets) {
+    sources += [
+      "socket/unix_domain_client_socket_posix_unittest.cc",
+      "socket/unix_domain_server_socket_posix_unittest.cc",
+    ]
+  }
+
   # Use getifaddrs() on POSIX platforms, except Linux and Android.
   if (!is_posix || is_linux || is_android) {
     sources -= [ "base/network_interfaces_getifaddrs_unittest.cc" ]
diff --git a/services/ui/public/interfaces/ime/ime.mojom b/services/ui/public/interfaces/ime/ime.mojom
index 61089e4e..b8167bfd 100644
--- a/services/ui/public/interfaces/ime/ime.mojom
+++ b/services/ui/public/interfaces/ime/ime.mojom
@@ -56,14 +56,23 @@
   string description_body;
 };
 
+// See comments for ui::ImeTextSpan::Type for more details.
+enum ImeTextSpanType {
+  kComposition,
+  kSuggestion,
+};
+
 // Represents an underlined segment of text currently composed by IME.
 // Corresponds to ui::ImeTextSpan.
 struct ImeTextSpan {
+  ImeTextSpanType type;
   uint32 start_offset;
   uint32 end_offset;
-  bool thick;
   uint32 underline_color;
+  bool thick;
   uint32 background_color;
+  uint32 suggestion_highlight_color;
+  array<string> suggestions;
 };
 
 // Represents a text currently being composed by IME. Corresponds to
diff --git a/services/ui/public/interfaces/ime/ime_struct_traits.cc b/services/ui/public/interfaces/ime/ime_struct_traits.cc
index 2f873c2f..925a001 100644
--- a/services/ui/public/interfaces/ime/ime_struct_traits.cc
+++ b/services/ui/public/interfaces/ime/ime_struct_traits.cc
@@ -45,11 +45,16 @@
     ui::ImeTextSpan* out) {
   if (data.is_null())
     return false;
+  if (!data.ReadType(&out->type))
+    return false;
   out->start_offset = data.start_offset();
   out->end_offset = data.end_offset();
   out->underline_color = data.underline_color();
   out->thick = data.thick();
   out->background_color = data.background_color();
+  out->suggestion_highlight_color = data.suggestion_highlight_color();
+  if (!data.ReadSuggestions(&out->suggestions))
+    return false;
   return true;
 }
 
@@ -62,6 +67,38 @@
 }
 
 // static
+ui::mojom::ImeTextSpanType
+EnumTraits<ui::mojom::ImeTextSpanType, ui::ImeTextSpan::Type>::ToMojom(
+    ui::ImeTextSpan::Type ime_text_span_type) {
+  switch (ime_text_span_type) {
+    case ui::ImeTextSpan::Type::kComposition:
+      return ui::mojom::ImeTextSpanType::kComposition;
+    case ui::ImeTextSpan::Type::kSuggestion:
+      return ui::mojom::ImeTextSpanType::kSuggestion;
+  }
+
+  NOTREACHED();
+  return ui::mojom::ImeTextSpanType::kComposition;
+}
+
+// static
+bool EnumTraits<ui::mojom::ImeTextSpanType, ui::ImeTextSpan::Type>::FromMojom(
+    ui::mojom::ImeTextSpanType type,
+    ui::ImeTextSpan::Type* out) {
+  switch (type) {
+    case ui::mojom::ImeTextSpanType::kComposition:
+      *out = ui::ImeTextSpan::Type::kComposition;
+      return true;
+    case ui::mojom::ImeTextSpanType::kSuggestion:
+      *out = ui::ImeTextSpan::Type::kSuggestion;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+// static
 ui::mojom::TextInputMode
 EnumTraits<ui::mojom::TextInputMode, ui::TextInputMode>::ToMojom(
     ui::TextInputMode text_input_mode) {
diff --git a/services/ui/public/interfaces/ime/ime_struct_traits.h b/services/ui/public/interfaces/ime/ime_struct_traits.h
index 5ec8dcf2..42214de 100644
--- a/services/ui/public/interfaces/ime/ime_struct_traits.h
+++ b/services/ui/public/interfaces/ime/ime_struct_traits.h
@@ -90,6 +90,7 @@
 
 template <>
 struct StructTraits<ui::mojom::ImeTextSpanDataView, ui::ImeTextSpan> {
+  static ui::ImeTextSpan::Type type(const ui::ImeTextSpan& c) { return c.type; }
   static uint32_t start_offset(const ui::ImeTextSpan& c) {
     return c.start_offset;
   }
@@ -101,10 +102,24 @@
   static uint32_t background_color(const ui::ImeTextSpan& c) {
     return c.background_color;
   }
+  static uint32_t suggestion_highlight_color(const ui::ImeTextSpan& c) {
+    return c.suggestion_highlight_color;
+  }
+  static std::vector<std::string> suggestions(const ui::ImeTextSpan& c) {
+    return c.suggestions;
+  }
   static bool Read(ui::mojom::ImeTextSpanDataView data, ui::ImeTextSpan* out);
 };
 
 template <>
+struct EnumTraits<ui::mojom::ImeTextSpanType, ui::ImeTextSpan::Type> {
+  static ui::mojom::ImeTextSpanType ToMojom(
+      ui::ImeTextSpan::Type ime_text_span_type);
+  static bool FromMojom(ui::mojom::ImeTextSpanType input,
+                        ui::ImeTextSpan::Type* out);
+};
+
+template <>
 struct EnumTraits<ui::mojom::TextInputMode, ui::TextInputMode> {
   static ui::mojom::TextInputMode ToMojom(ui::TextInputMode text_input_mode);
   static bool FromMojom(ui::mojom::TextInputMode input, ui::TextInputMode* out);
diff --git a/sql/connection_unittest.cc b/sql/connection_unittest.cc
index 4ee8b028..80f0474 100644
--- a/sql/connection_unittest.cc
+++ b/sql/connection_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/test/histogram_tester.h"
 #include "base/trace_event/process_memory_dump.h"
+#include "build/build_config.h"
 #include "sql/connection.h"
 #include "sql/connection_memory_dump_provider.h"
 #include "sql/correct_sql_test_base.h"
@@ -837,8 +838,8 @@
   // Close normally to reset the poisoned flag.
   db().Close();
 
-  // DEATH tests not supported on Android or iOS.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  // DEATH tests not supported on Android, iOS, or Fuchsia.
+#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
   // Once the real Close() has been called, various calls enforce API
   // usage by becoming fatal in debug mode.  Since DEATH tests are
   // expensive, just test one of them.
@@ -919,8 +920,8 @@
 }
 
 // This test manually sets on disk permissions; this doesn't apply to the mojo
-// fork.
-#if defined(OS_POSIX) && !defined(MOJO_APPTEST_IMPL)
+// fork or Fuchsia.
+#if defined(OS_POSIX) && !defined(MOJO_APPTEST_IMPL) && !defined(OS_FUCHSIA)
 // Test that set_restrict_to_user() trims database permissions so that
 // only the owner (and root) can read.
 TEST_F(SQLConnectionTest, UserPermission) {
@@ -984,7 +985,8 @@
   EXPECT_TRUE(base::GetPosixFilePermissions(journal, &mode));
   ASSERT_EQ((mode & base::FILE_PERMISSION_USER_MASK), mode);
 }
-#endif  // defined(OS_POSIX)
+#endif  // defined(OS_POSIX) && !defined(MOJO_APPTEST_IMPL) &&
+        // !defined(OS_FUCHSIA)
 
 // Test that errors start happening once Poison() is called.
 TEST_F(SQLConnectionTest, Poison) {
@@ -1657,8 +1659,8 @@
 // statements which fail to compile with SQLITE_ERROR call DLOG(FATAL).  This
 // case cannot be suppressed with an error callback.
 TEST_F(SQLConnectionTest, CompileError) {
-  // DEATH tests not supported on Android or iOS.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+  // DEATH tests not supported on Android, iOS, or Fuchsia.
+#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
   if (DLOG_IS_ON(FATAL)) {
     db().set_error_callback(base::Bind(&IgnoreErrorCallback));
     ASSERT_DEATH({
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index a97f6b7..96dc4b8 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -426,7 +426,8 @@
           "dimension_sets": [
             {
               "gpu": "10de:104a",
-              "os": "Ubuntu"
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
             }
           ]
         },
@@ -820,7 +821,8 @@
           "dimension_sets": [
             {
               "gpu": "10de:104a",
-              "os": "Ubuntu"
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
             }
           ]
         },
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 9e909a63..dae26b6 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -17402,6 +17402,26 @@
         },
         "test": "angle_deqp_gles2_tests",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--test-launcher-batch-limit=400",
+          "--deqp-egl-display-type=angle-d3d11"
+        ],
+        "name": "angle_deqp_gles3_d3d11_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6613",
+              "os": "Windows-2008ServerR2-SP1",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "shards": 12
+        },
+        "test": "angle_deqp_gles3_tests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": []
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index b708ca22..addcec6 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -476,7 +476,8 @@
           "dimension_sets": [
             {
               "gpu": "10de:104a",
-              "os": "Ubuntu"
+              "os": "Ubuntu",
+              "pool": "Chrome-GPU"
             }
           ]
         },
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 8b4daf4..bf83a334 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -2292,7 +2292,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -3470,7 +3470,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -3532,7 +3532,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -4297,7 +4297,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -4451,7 +4451,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -6685,7 +6685,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -7863,7 +7863,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -7925,7 +7925,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -8669,7 +8669,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -8823,7 +8823,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 09a46e2..5db84f7 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -2183,7 +2183,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -3733,7 +3733,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -3795,7 +3795,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -4994,7 +4994,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -5148,7 +5148,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -7403,7 +7403,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -8953,7 +8953,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -9015,7 +9015,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -10214,7 +10214,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -10368,7 +10368,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -11489,7 +11489,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -12264,7 +12264,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -12295,7 +12295,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -12853,7 +12853,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -12946,7 +12946,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -15159,7 +15159,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -16709,7 +16709,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -16771,7 +16771,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -17970,7 +17970,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -18124,7 +18124,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -19245,7 +19245,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -20020,7 +20020,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -20051,7 +20051,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -20609,7 +20609,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -20702,7 +20702,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -22915,7 +22915,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -24465,7 +24465,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -24527,7 +24527,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -25726,7 +25726,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -25880,7 +25880,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -28135,7 +28135,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -29685,7 +29685,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -29747,7 +29747,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -30946,7 +30946,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -31100,7 +31100,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -33402,7 +33402,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -34580,7 +34580,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -34642,7 +34642,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -35469,7 +35469,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -35623,7 +35623,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -38126,7 +38126,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -39242,7 +39242,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -39304,7 +39304,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -40048,7 +40048,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -40202,7 +40202,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -42705,7 +42705,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -43821,7 +43821,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -43883,7 +43883,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -44627,7 +44627,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -44781,7 +44781,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -47284,7 +47284,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -48400,7 +48400,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -48462,7 +48462,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -49206,7 +49206,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -49360,7 +49360,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -51842,7 +51842,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -52958,7 +52958,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -53020,7 +53020,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -53764,7 +53764,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -53918,7 +53918,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -56421,7 +56421,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -57537,7 +57537,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -57599,7 +57599,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -58343,7 +58343,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -58497,7 +58497,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -61000,7 +61000,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -62116,7 +62116,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -62178,7 +62178,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -62922,7 +62922,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -63076,7 +63076,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -65310,7 +65310,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -66488,7 +66488,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -66550,7 +66550,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -67294,7 +67294,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -67448,7 +67448,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -69703,7 +69703,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -70881,7 +70881,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -70943,7 +70943,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -71687,7 +71687,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -71841,7 +71841,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -74159,7 +74159,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -75337,7 +75337,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -75399,7 +75399,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -76143,7 +76143,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -76297,7 +76297,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -78594,7 +78594,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -79772,7 +79772,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -79834,7 +79834,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -80578,7 +80578,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -80732,7 +80732,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -83029,7 +83029,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -84207,7 +84207,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -84269,7 +84269,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -85013,7 +85013,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -85167,7 +85167,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -87443,7 +87443,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -88621,7 +88621,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -88683,7 +88683,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -89427,7 +89427,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -89581,7 +89581,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -91857,7 +91857,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -93035,7 +93035,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -93097,7 +93097,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -93841,7 +93841,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -93995,7 +93995,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -96292,7 +96292,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -97470,7 +97470,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -97532,7 +97532,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -98276,7 +98276,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
@@ -98430,7 +98430,7 @@
           "hard_timeout": 10800,
           "ignore_task_failure": false,
           "io_timeout": 600,
-          "upload_test_results": false
+          "upload_test_results": true
         }
       },
       {
diff --git a/testing/buildbot/filters/fuchsia.net_unittests.filter b/testing/buildbot/filters/fuchsia.net_unittests.filter
index d05667e..4f14556 100644
--- a/testing/buildbot/filters/fuchsia.net_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.net_unittests.filter
@@ -4,7 +4,6 @@
 -ProxyScriptFetcherImplTest.Priority
 -PythonUtils*
 -UDPSocketTest.PartialRecv
--UnixDomain*Socket*
 -URLRequest*FTP*
 -URLRequestQuic*
 
@@ -13,10 +12,6 @@
 -DiskCacheBackendTest.SimpleCacheDeleteQuickly
 -URLRequestTestHTTP.GetTest_ManyCookies
 
-# https://crbug.com/755552
--HttpCache.RangeGET_ParallelValidationDifferentRanges
--HttpCache.RangeGET_ParallelValidationOverlappingRanges
-
 # base::MakeFileUnreadable() doesn't work. https://crbug.com/759853
 -HttpNetworkTransactionTest.UploadUnreadableFile
 -SpdyNetworkTransactionTest.UnreadableFilePost
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 3e8dd77..ebe7243 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -126,7 +126,6 @@
 Bug(none) fast/xsl/xslt-nested-stylesheets.xml [ Skip ]
 Bug(none) fast/xsl/xslt-second-level-import.xml [ Skip ]
 Bug(none) fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html [ Failure ]
-Bug(754827) http/tests/appcache/main-resource-redirect.html [ Timeout ]
 Bug(none) http/tests/background_fetch/background-fetch-click-event.https.html [ Crash Timeout ]
 Bug(none) http/tests/background_fetch/background-fetch-event.https.html [ Crash Timeout ]
 Bug(none) http/tests/background_fetch/background-fetch-fail-event.https.html [ Crash Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/OWNERS
index 17478fb..d9e8048 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/OWNERS
@@ -1 +1,2 @@
-blink-network-dev@chromium.org
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network>XHR
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-async-not-supported.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-async-not-supported.htm
new file mode 100644
index 0000000..e1607d4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/access-control-preflight-async-not-supported.htm
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Async PUT request denied at preflight</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/common/utils.js"></script>
+  </head>
+  <body>
+    <script type="text/javascript">
+const uuid = token();
+const url = get_host_info().HTTP_REMOTE_ORIGIN +
+      "/XMLHttpRequest/resources/access-control-preflight-denied.py?token=" + uuid;
+
+async_test((test) => {
+  let xhr = new XMLHttpRequest;
+  xhr.open("GET", url + "&command=reset", false);
+  xhr.send();
+
+  xhr = new XMLHttpRequest;
+  xhr.open("PUT", url, true);
+
+  xhr.onload = test.unreached_func("Cross-domain access allowed unexpectedly.");
+
+  xhr.onerror = test.step_func_done(() => {
+    xhr = new XMLHttpRequest;
+    xhr.open("GET", url + "&command=complete", false);
+    xhr.send();
+    assert_equals(xhr.responseText, "Request successfully blocked.");
+  });
+
+  xhr.send();
+});
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cors/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/cors/OWNERS
index 17478fb..6c7157d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cors/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/cors/OWNERS
@@ -1 +1,2 @@
-blink-network-dev@chromium.org
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>SecurityFeature>CORS
diff --git a/third_party/WebKit/LayoutTests/external/wpt/eventsource/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/eventsource/OWNERS
index 17478fb..8263c35 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/eventsource/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/eventsource/OWNERS
@@ -1 +1,2 @@
-blink-network-dev@chromium.org
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/fetch/OWNERS
index 7476f67d..ec4e34a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/OWNERS
@@ -1,3 +1,5 @@
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network>FetchAPI
 tyoshino@chromium.org
 yhirano@chromium.org
 mkwst@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/http/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/http/OWNERS
index d05d8de..1d011a7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/http/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/http/OWNERS
@@ -1 +1 @@
-loading-dev@chromium.org
+# TEAM: loading-dev@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/progress-events/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/progress-events/OWNERS
index 17478fb..d9e8048 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/progress-events/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/progress-events/OWNERS
@@ -1 +1,2 @@
-blink-network-dev@chromium.org
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network>XHR
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS
index 1077b09..3c0bff5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/OWNERS
@@ -1,3 +1,5 @@
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network>StreamsAPI
 domenic@chromium.org
 ricea@chromium.org
 tyoshino@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/url/OWNERS
index 17478fb..8263c35 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/OWNERS
@@ -1 +1,2 @@
-blink-network-dev@chromium.org
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network
diff --git a/third_party/WebKit/LayoutTests/external/wpt/websockets/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/websockets/OWNERS
index 17478fb..09bdfc47 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/websockets/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/websockets/OWNERS
@@ -1 +1,2 @@
-blink-network-dev@chromium.org
+# TEAM: blink-network-dev@chromium.org
+# COMPONENT: Blink>Network>WebSockets
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/module-script.html b/third_party/WebKit/LayoutTests/http/tests/preload/module-script.html
new file mode 100644
index 0000000..09a9a46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/module-script.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script id="target" type="module" src="resources/empty.js"></script>
+<script>
+var t = async_test('Makes sure that <script type="module"> preload resources');
+
+target.onload = t.step_func(function() {
+    if (window.internals === undefined) {
+        throw new Error('This test requires internals.isPreloaded function.');
+    }
+
+    assert_true(internals.isPreloaded(target.src));
+
+    var absoluteUrl = new URL(target.src, location.href).href;
+    assert_equals(performance.getEntriesByName(absoluteUrl).length, 1,
+                  'empty.js should load only once');
+    t.done();
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/resources/empty.js b/third_party/WebKit/LayoutTests/http/tests/preload/resources/empty.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/resources/empty.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-not-supported-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-not-supported-expected.txt
deleted file mode 100644
index 0635351e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-not-supported-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 19: 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/.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-PASS: Request successfully blocked.
-
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-not-supported.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-not-supported.html
deleted file mode 100644
index 621e947..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-preflight-async-not-supported.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<html>
-<body>
-<pre id='console'></pre>
-<script type="text/javascript">
-function log(message)
-{
-    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
-}
-
-if (window.testRunner) {
-    testRunner.dumpAsText();
-    testRunner.waitUntilDone();
-}
-
-(function() {
-    var xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=reset", false);
-        xhr.send(null);
-    } catch(e) {
-        log("FAIL: Unable to reset server state: [" + e.message + "].");
-        return;
-    }
-
-    xhr = new XMLHttpRequest();
-
-    try {
-        xhr.open("PUT", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php", true);
-    } catch(e) {
-        log("FAIL: Exception thrown. Cross-domain access is not allowed in first 'open'. [" + e.message + "].");
-        return;
-    }
-
-    xhr.onerror = function() {
-        xhr = new XMLHttpRequest();
-
-        try {
-            xhr.open("GET", "http://localhost:8000/xmlhttprequest/resources/access-control-preflight-denied-xsrf.php?state=complete", false);
-            try {
-                xhr.send(null);
-            } catch(e) {
-                log("FAIL: Exception thrown. Cross-domain access is not allowed in second 'send'. [" + e.message + "].");
-            }
-        } catch(e) {
-            log("FAIL: Exception thrown. Cross-domain access is not allowed in second 'open'. [" + e.message + "].");
-        }
-
-        log(xhr.responseText);
-        if (window.testRunner)
-            testRunner.notifyDone();
-    }
-
-    xhr.onreadystatechange = function() {
-        if (xhr.readyState == 4 && xhr.status == 200)
-            log("FAIL: Cross-domain access allowed in first send without throwing an exception");
-    }
-
-    xhr.send("");
-})();
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/readable-streams/bad-underlying-sources-expected.txt b/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/readable-streams/bad-underlying-sources-expected.txt
deleted file mode 100644
index 25c61f1..0000000
--- a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/readable-streams/bad-underlying-sources-expected.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = 21 duplicate test names: "Underlying source start: throwing getter", "Underlying source start: throwing method", "Underlying source: throwing pull getter (initial pull)", "Underlying source: throwing pull method (initial pull)", "Underlying source pull: throwing getter (second pull)", "Underlying source pull: throwing method (second pull)", "Underlying source cancel: throwing getter", "Underlying source cancel: throwing method", "Underlying source: calling enqueue on an empty canceled stream should throw", "Underlying source: calling enqueue on a non-empty canceled stream should throw", "Underlying source: calling enqueue on a closed stream should throw", "Underlying source: calling enqueue on an errored stream should throw", "Underlying source: calling close twice on an empty stream should throw the second time", "Underlying source: calling close twice on a non-empty stream should throw the second time", "Underlying source: calling close on an empty canceled stream should throw", "Underlying source: calling close on a non-empty canceled stream should throw", "Underlying source: calling close after error should throw", "Underlying source: calling error twice should throw the second time", "Underlying source: calling error after close should throw", "Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error", "Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error"
-PASS Underlying source start: throwing getter
-PASS Underlying source start: throwing method
-PASS Underlying source: throwing pull getter (initial pull)
-PASS Underlying source: throwing pull method (initial pull)
-PASS Underlying source pull: throwing getter (second pull)
-PASS Underlying source pull: throwing method (second pull)
-PASS Underlying source cancel: throwing getter
-PASS Underlying source cancel: throwing method
-PASS Underlying source: calling enqueue on an empty canceled stream should throw
-PASS Underlying source: calling enqueue on a non-empty canceled stream should throw
-PASS Underlying source: calling enqueue on a closed stream should throw
-PASS Underlying source: calling enqueue on an errored stream should throw
-PASS Underlying source: calling close twice on an empty stream should throw the second time
-PASS Underlying source: calling close twice on a non-empty stream should throw the second time
-PASS Underlying source: calling close on an empty canceled stream should throw
-PASS Underlying source: calling close on a non-empty canceled stream should throw
-PASS Underlying source: calling close after error should throw
-PASS Underlying source: calling error twice should throw the second time
-PASS Underlying source: calling error after close should throw
-PASS Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error
-PASS Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error
-PASS Untitled
-PASS Underlying source start: throwing getter
-PASS Underlying source start: throwing method
-PASS Underlying source: throwing pull getter (initial pull)
-PASS Underlying source: throwing pull method (initial pull)
-PASS Underlying source pull: throwing getter (second pull)
-PASS Underlying source pull: throwing method (second pull)
-PASS Underlying source cancel: throwing getter
-PASS Underlying source cancel: throwing method
-PASS Underlying source: calling enqueue on an empty canceled stream should throw
-PASS Underlying source: calling enqueue on a non-empty canceled stream should throw
-PASS Underlying source: calling enqueue on a closed stream should throw
-PASS Underlying source: calling enqueue on an errored stream should throw
-PASS Underlying source: calling close twice on an empty stream should throw the second time
-PASS Underlying source: calling close twice on a non-empty stream should throw the second time
-PASS Underlying source: calling close on an empty canceled stream should throw
-PASS Underlying source: calling close on a non-empty canceled stream should throw
-PASS Underlying source: calling close after error should throw
-PASS Underlying source: calling error twice should throw the second time
-PASS Underlying source: calling error after close should throw
-PASS Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error
-PASS Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error
-PASS Underlying source start: throwing getter
-PASS Underlying source start: throwing method
-PASS Underlying source: throwing pull getter (initial pull)
-PASS Underlying source: throwing pull method (initial pull)
-PASS Underlying source pull: throwing getter (second pull)
-PASS Underlying source pull: throwing method (second pull)
-PASS Underlying source cancel: throwing getter
-PASS Underlying source cancel: throwing method
-PASS Underlying source: calling enqueue on an empty canceled stream should throw
-PASS Underlying source: calling enqueue on a non-empty canceled stream should throw
-PASS Underlying source: calling enqueue on a closed stream should throw
-PASS Underlying source: calling enqueue on an errored stream should throw
-PASS Underlying source: calling close twice on an empty stream should throw the second time
-PASS Underlying source: calling close twice on a non-empty stream should throw the second time
-PASS Underlying source: calling close on an empty canceled stream should throw
-PASS Underlying source: calling close on a non-empty canceled stream should throw
-PASS Underlying source: calling close after error should throw
-PASS Underlying source: calling error twice should throw the second time
-PASS Underlying source: calling error after close should throw
-PASS Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error
-PASS Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error
-PASS Underlying source start: throwing getter
-PASS Underlying source start: throwing method
-PASS Underlying source: throwing pull getter (initial pull)
-PASS Underlying source: throwing pull method (initial pull)
-PASS Underlying source pull: throwing getter (second pull)
-PASS Underlying source pull: throwing method (second pull)
-PASS Underlying source cancel: throwing getter
-PASS Underlying source cancel: throwing method
-PASS Underlying source: calling enqueue on an empty canceled stream should throw
-PASS Underlying source: calling enqueue on a non-empty canceled stream should throw
-PASS Underlying source: calling enqueue on a closed stream should throw
-PASS Underlying source: calling enqueue on an errored stream should throw
-PASS Underlying source: calling close twice on an empty stream should throw the second time
-PASS Underlying source: calling close twice on a non-empty stream should throw the second time
-PASS Underlying source: calling close on an empty canceled stream should throw
-PASS Underlying source: calling close on a non-empty canceled stream should throw
-PASS Underlying source: calling close after error should throw
-PASS Underlying source: calling error twice should throw the second time
-PASS Underlying source: calling error after close should throw
-PASS Underlying source: calling error and returning a rejected promise from start should cause the stream to error with the first error
-PASS Underlying source: calling error and returning a rejected promise from pull should cause the stream to error with the first error
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/readable-streams/readable-stream-reader-expected.txt b/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/readable-streams/readable-stream-reader-expected.txt
deleted file mode 100644
index 4d4de8b..0000000
--- a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/readable-streams/readable-stream-reader-expected.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = 26 duplicate test names: "Can get the ReadableStreamReader constructor indirectly", "ReadableStreamReader constructor should get a ReadableStream object as argument", "ReadableStreamReader instances should have the correct list of properties", "ReadableStreamReader closed should always return the same promise object", "Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)", "Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)", "Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)", "Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)", "Constructing a ReadableStreamReader directly should be OK if the stream is closed", "Constructing a ReadableStreamReader directly should be OK if the stream is errored", "Reading from a reader for an empty stream will wait until a chunk is available", "cancel() on a reader does not release the reader", "closed should be fulfilled after stream is closed (.closed access before acquiring)", "closed should be rejected after reader releases its lock (multiple stream locks)", "Multiple readers can access the stream in sequence", "Cannot use an already-released reader to unlock a stream again", "cancel() on a released reader is a no-op and does not pass through", "Getting a second reader after erroring the stream and releasing the reader should succeed", "ReadableStreamReader closed promise should be rejected with undefined if that is the error", "ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error", "Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise", "Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise", "Reading twice on a stream that gets closed", "Reading twice on a closed stream", "Reading twice on an errored stream", "Reading twice on a stream that gets errored"
-PASS Can get the ReadableStreamReader constructor indirectly
-PASS ReadableStreamReader constructor should get a ReadableStream object as argument
-PASS ReadableStreamReader instances should have the correct list of properties
-PASS ReadableStreamReader closed should always return the same promise object
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is closed
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored
-PASS Reading from a reader for an empty stream will wait until a chunk is available
-PASS cancel() on a reader does not release the reader
-PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
-PASS closed should be rejected after reader releases its lock (multiple stream locks)
-PASS Multiple readers can access the stream in sequence
-PASS Cannot use an already-released reader to unlock a stream again
-PASS cancel() on a released reader is a no-op and does not pass through
-PASS Getting a second reader after erroring the stream and releasing the reader should succeed
-PASS ReadableStreamReader closed promise should be rejected with undefined if that is the error
-PASS ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error
-PASS Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise
-PASS Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise
-PASS Reading twice on a stream that gets closed
-PASS Reading twice on a closed stream
-PASS Reading twice on an errored stream
-PASS Reading twice on a stream that gets errored
-PASS Untitled
-PASS Can get the ReadableStreamReader constructor indirectly
-PASS ReadableStreamReader constructor should get a ReadableStream object as argument
-PASS ReadableStreamReader instances should have the correct list of properties
-PASS ReadableStreamReader closed should always return the same promise object
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is closed
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored
-PASS Reading from a reader for an empty stream will wait until a chunk is available
-PASS cancel() on a reader does not release the reader
-PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
-PASS closed should be rejected after reader releases its lock (multiple stream locks)
-PASS Multiple readers can access the stream in sequence
-PASS Cannot use an already-released reader to unlock a stream again
-PASS cancel() on a released reader is a no-op and does not pass through
-PASS Getting a second reader after erroring the stream and releasing the reader should succeed
-PASS ReadableStreamReader closed promise should be rejected with undefined if that is the error
-PASS ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error
-PASS Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise
-PASS Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise
-PASS Reading twice on a stream that gets closed
-PASS Reading twice on a closed stream
-PASS Reading twice on an errored stream
-PASS Reading twice on a stream that gets errored
-PASS Can get the ReadableStreamReader constructor indirectly
-PASS ReadableStreamReader constructor should get a ReadableStream object as argument
-PASS ReadableStreamReader instances should have the correct list of properties
-PASS ReadableStreamReader closed should always return the same promise object
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is closed
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored
-PASS Reading from a reader for an empty stream will wait until a chunk is available
-PASS cancel() on a reader does not release the reader
-PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
-PASS closed should be rejected after reader releases its lock (multiple stream locks)
-PASS Multiple readers can access the stream in sequence
-PASS Cannot use an already-released reader to unlock a stream again
-PASS cancel() on a released reader is a no-op and does not pass through
-PASS Getting a second reader after erroring the stream and releasing the reader should succeed
-PASS ReadableStreamReader closed promise should be rejected with undefined if that is the error
-PASS ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error
-PASS Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise
-PASS Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise
-PASS Reading twice on a stream that gets closed
-PASS Reading twice on a closed stream
-PASS Reading twice on an errored stream
-PASS Reading twice on a stream that gets errored
-PASS Can get the ReadableStreamReader constructor indirectly
-PASS ReadableStreamReader constructor should get a ReadableStream object as argument
-PASS ReadableStreamReader instances should have the correct list of properties
-PASS ReadableStreamReader closed should always return the same promise object
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via direct construction)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via direct construction)
-PASS Constructing a ReadableStreamReader directly should fail if the stream is already locked (via getReader)
-PASS Getting a ReadableStreamReader via getReader should fail if the stream is already locked (via getReader)
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is closed
-PASS Constructing a ReadableStreamReader directly should be OK if the stream is errored
-PASS Reading from a reader for an empty stream will wait until a chunk is available
-PASS cancel() on a reader does not release the reader
-PASS closed should be fulfilled after stream is closed (.closed access before acquiring)
-PASS closed should be rejected after reader releases its lock (multiple stream locks)
-PASS Multiple readers can access the stream in sequence
-PASS Cannot use an already-released reader to unlock a stream again
-PASS cancel() on a released reader is a no-op and does not pass through
-PASS Getting a second reader after erroring the stream and releasing the reader should succeed
-PASS ReadableStreamReader closed promise should be rejected with undefined if that is the error
-PASS ReadableStreamReader: if start rejects with no parameter, it should error the stream with an undefined error
-PASS Erroring a ReadableStream after checking closed should reject ReadableStreamReader closed promise
-PASS Erroring a ReadableStream before checking closed should reject ReadableStreamReader closed promise
-PASS Reading twice on a stream that gets closed
-PASS Reading twice on a closed stream
-PASS Reading twice on an errored stream
-PASS Reading twice on a stream that gets errored
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/writable-streams/brand-checks.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/writable-streams/brand-checks.https-expected.txt
deleted file mode 100644
index c7b615f1..0000000
--- a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/writable-streams/brand-checks.https-expected.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = 6 duplicate test names: "WritableStreamDefaultWriter.prototype.desiredSize enforces a brand check", "WritableStreamDefaultWriter.prototype.closed enforces a brand check", "WritableStreamDefaultWriter.prototype.ready enforces a brand check", "WritableStreamDefaultWriter.prototype.abort enforces a brand check", "WritableStreamDefaultWriter.prototype.write enforces a brand check", "WritableStreamDefaultWriter.prototype.close enforces a brand check"
-PASS WritableStreamDefaultWriter.prototype.desiredSize enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.closed enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.ready enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.abort enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.write enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.close enforces a brand check
-PASS Untitled
-PASS WritableStreamDefaultWriter.prototype.desiredSize enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.closed enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.ready enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.abort enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.write enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.close enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.desiredSize enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.closed enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.ready enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.abort enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.write enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.close enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.desiredSize enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.closed enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.ready enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.abort enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.write enforces a brand check
-PASS WritableStreamDefaultWriter.prototype.close enforces a brand check
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/writable-streams/constructor.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/writable-streams/constructor.https-expected.txt
deleted file mode 100644
index 1e857de..0000000
--- a/third_party/WebKit/LayoutTests/virtual/mojo-loading/http/tests/streams/writable-streams/constructor.https-expected.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = 12 duplicate test names: "controller argument should be passed to start method", "controller argument should be passed to write method", "controller argument should be passed to close method", "highWaterMark should be reflected to desiredSize", "WritableStream should be writable and ready should fulfill immediately if the strategy does not apply backpressure", "WritableStream should be constructible with no arguments", "WritableStream instances should have standard methods and properties", "private constructors should not be exported", "WritableStreamDefaultController constructor should throw unless passed a WritableStream", "WritableStreamDefaultController constructor should throw when passed an initialised WritableStream", "WritableStreamDefaultWriter should throw unless passed a WritableStream", "WritableStreamDefaultWriter constructor should throw when stream argument is locked"
-PASS controller argument should be passed to start method
-PASS controller argument should be passed to write method
-PASS controller argument should be passed to close method
-PASS highWaterMark should be reflected to desiredSize
-PASS WritableStream should be writable and ready should fulfill immediately if the strategy does not apply backpressure
-PASS WritableStream should be constructible with no arguments
-PASS WritableStream instances should have standard methods and properties
-PASS private constructors should not be exported
-PASS WritableStreamDefaultController constructor should throw unless passed a WritableStream
-PASS WritableStreamDefaultController constructor should throw when passed an initialised WritableStream
-PASS WritableStreamDefaultWriter should throw unless passed a WritableStream
-PASS WritableStreamDefaultWriter constructor should throw when stream argument is locked
-PASS Untitled
-PASS controller argument should be passed to start method
-PASS controller argument should be passed to write method
-PASS controller argument should be passed to close method
-PASS highWaterMark should be reflected to desiredSize
-PASS WritableStream should be writable and ready should fulfill immediately if the strategy does not apply backpressure
-PASS WritableStream should be constructible with no arguments
-PASS WritableStream instances should have standard methods and properties
-PASS private constructors should not be exported
-PASS WritableStreamDefaultController constructor should throw unless passed a WritableStream
-PASS WritableStreamDefaultController constructor should throw when passed an initialised WritableStream
-PASS WritableStreamDefaultWriter should throw unless passed a WritableStream
-PASS WritableStreamDefaultWriter constructor should throw when stream argument is locked
-PASS controller argument should be passed to start method
-PASS controller argument should be passed to write method
-PASS controller argument should be passed to close method
-PASS highWaterMark should be reflected to desiredSize
-PASS WritableStream should be writable and ready should fulfill immediately if the strategy does not apply backpressure
-PASS WritableStream should be constructible with no arguments
-PASS WritableStream instances should have standard methods and properties
-PASS private constructors should not be exported
-PASS WritableStreamDefaultController constructor should throw unless passed a WritableStream
-PASS WritableStreamDefaultController constructor should throw when passed an initialised WritableStream
-PASS WritableStreamDefaultWriter should throw unless passed a WritableStream
-PASS WritableStreamDefaultWriter constructor should throw when stream argument is locked
-PASS controller argument should be passed to start method
-PASS controller argument should be passed to write method
-PASS controller argument should be passed to close method
-PASS highWaterMark should be reflected to desiredSize
-PASS WritableStream should be writable and ready should fulfill immediately if the strategy does not apply backpressure
-PASS WritableStream should be constructible with no arguments
-PASS WritableStream instances should have standard methods and properties
-PASS private constructors should not be exported
-PASS WritableStreamDefaultController constructor should throw unless passed a WritableStream
-PASS WritableStreamDefaultController constructor should throw when passed an initialised WritableStream
-PASS WritableStreamDefaultWriter should throw unless passed a WritableStream
-PASS WritableStreamDefaultWriter constructor should throw when stream argument is locked
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator.py b/third_party/WebKit/Source/bindings/scripts/code_generator.py
index c57ac4a..1acce6b 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator.py
@@ -19,7 +19,8 @@
 import v8_utilities
 from v8_utilities import capitalize
 from utilities import (idl_filename_to_component, is_valid_component_dependency,
-                       format_remove_duplicates, format_blink_cpp_source_code)
+                       format_remove_duplicates, format_blink_cpp_source_code,
+                       to_snake_case)
 
 # Path handling for libraries and templates
 # Paths have to be normalized because Jinja uses the exact template path to
@@ -96,12 +97,18 @@
     return jinja_env
 
 
-def normalize_and_sort_includes(include_paths):
+def normalize_and_sort_includes(include_paths, snake_case):
     normalized_include_paths = []
     for include_path in include_paths:
         match = re.search(r'/gen/blink/(.*)$', posixpath.abspath(include_path))
         if match:
             include_path = match.group(1)
+        if snake_case:
+            match = re.search(r'/([^/]+)\.h$', include_path)
+            if match:
+                name = match.group(1)
+                if name.lower() != name and name != 'RuntimeEnabledFeatures' and name != 'OriginTrials':
+                    include_path = include_path[0:match.start(1)] + to_snake_case(name) + '.h'
         normalized_include_paths.append(include_path)
     return sorted(normalized_include_paths)
 
@@ -116,11 +123,12 @@
 class CodeGeneratorBase(object):
     """Base class for jinja-powered jinja template generation.
     """
-    def __init__(self, generator_name, info_provider, cache_dir, output_dir):
+    def __init__(self, generator_name, info_provider, cache_dir, output_dir, snake_case):
         self.generator_name = generator_name
         self.info_provider = info_provider
         self.jinja_env = initialize_jinja_env(cache_dir)
         self.output_dir = output_dir
+        self.snake_case_generated_files = snake_case
         self.set_global_type_info()
 
     def should_generate_code(self, definitions):
@@ -143,7 +151,7 @@
 
         # Add includes for any dependencies
         template_context['header_includes'] = normalize_and_sort_includes(
-            template_context['header_includes'])
+            template_context['header_includes'], self.snake_case_generated_files)
 
         for include_path in include_paths:
             if component:
@@ -151,7 +159,7 @@
                 assert is_valid_component_dependency(component, dependency)
             includes.add(include_path)
 
-        template_context['cpp_includes'] = normalize_and_sort_includes(includes)
+        template_context['cpp_includes'] = normalize_and_sort_includes(includes, self.snake_case_generated_files)
 
         header_text = render_template(header_template, template_context)
         cpp_text = render_template(cpp_template, template_context)
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py b/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
index 28233f8a..efc1bba1 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator_v8.py
@@ -135,9 +135,8 @@
     """Base class for v8 bindings generator and IDL dictionary impl generator"""
 
     def __init__(self, info_provider, cache_dir, output_dir, snake_case):
-        CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir)
+        CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir, snake_case)
         self.typedef_resolver = TypedefResolver(info_provider)
-        self.snake_case_generated_files = snake_case
 
     def generate_code(self, definitions, definition_name):
         """Returns .h/.cpp code as ((path, content)...)."""
@@ -305,8 +304,8 @@
     CodeGeneratorDictionaryImpl. It assumes that all union types are already
     collected. It doesn't process idl files directly.
     """
-    def __init__(self, info_provider, cache_dir, output_dir, target_component):
-        CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir)
+    def __init__(self, info_provider, cache_dir, output_dir, snake_case, target_component):
+        CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir, snake_case)
         self.target_component = target_component
         # The code below duplicates parts of TypedefResolver. We do not use it
         # directly because IdlUnionType is not a type defined in
@@ -325,7 +324,7 @@
         template_context['header_includes'].append(
             self.info_provider.include_path_for_export)
         template_context['header_includes'] = normalize_and_sort_includes(
-            template_context['header_includes'])
+            template_context['header_includes'], self.snake_case_generated_files)
         template_context['code_generator'] = self.generator_name
         template_context['exported'] = self.info_provider.specifier_for_export
         snake_base_name = to_snake_case(shorten_union_name(union_type))
@@ -367,8 +366,8 @@
 
 
 class CodeGeneratorCallbackFunction(CodeGeneratorBase):
-    def __init__(self, info_provider, cache_dir, output_dir, target_component):
-        CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir)
+    def __init__(self, info_provider, cache_dir, output_dir, snake_case, target_component):
+        CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider, cache_dir, output_dir, snake_case)
         self.target_component = target_component
         self.typedef_resolver = TypedefResolver(info_provider)
 
@@ -383,7 +382,7 @@
             template_context['header_includes'].append(
                 self.info_provider.include_path_for_export)
         template_context['header_includes'] = normalize_and_sort_includes(
-            template_context['header_includes'])
+            template_context['header_includes'], self.snake_case_generated_files)
         template_context['code_generator'] = MODULE_PYNAME
         header_text = render_template(header_template, template_context)
         cpp_text = render_template(cpp_template, template_context)
diff --git a/third_party/WebKit/Source/bindings/scripts/code_generator_web_agent_api.py b/third_party/WebKit/Source/bindings/scripts/code_generator_web_agent_api.py
index 5c07883..69d4aff0 100644
--- a/third_party/WebKit/Source/bindings/scripts/code_generator_web_agent_api.py
+++ b/third_party/WebKit/Source/bindings/scripts/code_generator_web_agent_api.py
@@ -239,9 +239,9 @@
 
 
 class CodeGeneratorWebAgentAPI(CodeGeneratorBase):
-    def __init__(self, info_provider, cache_dir, output_dir, _):
+    def __init__(self, info_provider, cache_dir, output_dir, snake_case):
         CodeGeneratorBase.__init__(self, MODULE_PYNAME, info_provider,
-                                   cache_dir, output_dir)
+                                   cache_dir, output_dir, snake_case)
         self.type_resolver = TypeResolver(info_provider.interfaces_info)
         self.typedef_resolver = TypedefResolver(info_provider)
 
diff --git a/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py b/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py
index 6bf87af..0b7e1325 100755
--- a/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py
+++ b/third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py
@@ -142,7 +142,7 @@
     return features_for_type, types_for_feature, includes
 
 
-def conditional_features_context(generator_name, feature_info):
+def conditional_features_context(generator_name, feature_info, snake_case):
     context = {'code_generator': generator_name}
 
     # Unpack the feature info tuple.
@@ -160,7 +160,7 @@
         # here because the ContextFeatureSettings code needs it.
         'bindings/core/v8/V8Window.h',
     ])
-    context['includes'] = normalize_and_sort_includes(includes)
+    context['includes'] = normalize_and_sort_includes(includes, snake_case)
 
     # For each interface, collect a list of bindings installation functions to
     # call, organized by conditional feature.
@@ -218,7 +218,7 @@
 
     # Convert that mapping into the context required for the Jinja2 templates.
     template_context = conditional_features_context(
-        MODULE_PYNAME, feature_info)
+        MODULE_PYNAME, feature_info, options.snake_case_generated_files)
 
     # Generate and write out the header file
     header_text = render_template(jinja_env.get_template(
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_compiler.py b/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
index accd4570..d876a0c 100755
--- a/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
+++ b/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
@@ -159,6 +159,7 @@
         info_provider,
         options.cache_directory,
         options.output_directory,
+        options.snake_case_generated_files,
         options.target_component)
     output_code_list = generator.generate_code()
     for output_path, output_code in output_code_list:
@@ -171,6 +172,7 @@
         info_provider,
         options.cache_directory,
         options.output_directory,
+        options.snake_case_generated_files,
         options.target_component)
     output_code_list = generator.generate_code()
     for output_path, output_code in output_code_list:
diff --git a/third_party/WebKit/Source/build/scripts/core/css/properties/templates/CSSPropertyAPI.h.tmpl b/third_party/WebKit/Source/build/scripts/core/css/properties/templates/CSSPropertyAPI.h.tmpl
index 397d6ab3..f2e85283 100644
--- a/third_party/WebKit/Source/build/scripts/core/css/properties/templates/CSSPropertyAPI.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/core/css/properties/templates/CSSPropertyAPI.h.tmpl
@@ -30,10 +30,13 @@
 
   // Parses and consumes a longhand property value from the token range.
   // Returns nullptr if the input is invalid.
+  // TODO(bugsnash): remove CSSPropertyID arg from this and ParseShorthand
   virtual const CSSValue* ParseSingleValue(CSSPropertyID,
                                            CSSParserTokenRange&,
                                            const CSSParserContext&,
-                                           const CSSParserLocalContext&) const;
+                                           const CSSParserLocalContext&) const {
+    return nullptr;
+  }
   // Parses and consumes entire shorthand value from the token range and adds
   // all constituent parsed longhand properties to the 'properties' set.
   // Returns false if the input is invalid.
@@ -42,7 +45,9 @@
                               CSSParserTokenRange&,
                               const CSSParserContext&,
                               const CSSParserLocalContext&,
-                              HeapVector<CSSProperty, 256>& properties) const;
+                              HeapVector<CSSProperty, 256>& properties) const {
+    return false;
+  }
 
   virtual bool IsInterpolable() const { return false; }
   virtual bool IsInherited() const { return false; }
diff --git a/third_party/WebKit/Source/build/scripts/make_event_factory.py b/third_party/WebKit/Source/build/scripts/make_event_factory.py
index f9da6e337..2288cec 100755
--- a/third_party/WebKit/Source/build/scripts/make_event_factory.py
+++ b/third_party/WebKit/Source/build/scripts/make_event_factory.py
@@ -38,12 +38,12 @@
 
 HEADER_TEMPLATE = """%(license)s
 
-#ifndef %(namespace)s%(suffix)sHeaders_h
-#define %(namespace)s%(suffix)sHeaders_h
+#ifndef Event%(suffix)sHeaders_h
+#define Event%(suffix)sHeaders_h
 %(base_header_for_suffix)s
 %(includes)s
 
-#endif // %(namespace)s%(suffix)sHeaders_h
+#endif // Event%(suffix)sHeaders_h
 """
 
 
@@ -121,9 +121,10 @@
     def __init__(self, json5_file_path):
         super(EventFactoryWriter, self).__init__(json5_file_path)
         self.namespace = self.json5_file.metadata['namespace'].strip('"')
+        assert self.namespace == 'Event', 'namespace field should be "Event".'
         self.suffix = self.json5_file.metadata['suffix'].strip('"')
-        self._outputs = {(self.namespace + self.suffix + "Headers.h"): self.generate_headers_header,
-                         (self.namespace + self.suffix + ".cpp"): self.generate_implementation,
+        self._outputs = {('Event%sHeaders.h' % self.suffix): self.generate_headers_header,
+                         ('Event%s.cpp' % self.suffix): self.generate_implementation,
                         }
 
     def _fatal(self, message):
@@ -171,11 +172,10 @@
     def generate_headers_header(self):
         base_header_for_suffix = ''
         if self.suffix:
-            base_header_for_suffix = '\n#include "core/%(namespace)sHeaders.h"\n' % {'namespace': self.namespace}
+            base_header_for_suffix = '\n#include "core/EventHeaders.h"\n'
         return HEADER_TEMPLATE % {
             'input_files': self._input_files,
             'license': license.license_for_generated_cpp(),
-            'namespace': self.namespace,
             'suffix': self.suffix,
             'base_header_for_suffix': base_header_for_suffix,
             'includes': '\n'.join(self._headers_header_includes(self.json5_file.name_dictionaries)),
@@ -185,7 +185,6 @@
     def generate_implementation(self):
         return {
             'input_files': self._input_files,
-            'namespace': self.namespace,
             'suffix': self.suffix,
             'events': self.json5_file.name_dictionaries,
         }
diff --git a/third_party/WebKit/Source/build/scripts/make_runtime_features.py b/third_party/WebKit/Source/build/scripts/make_runtime_features.py
index 2952faa2..64d489e 100755
--- a/third_party/WebKit/Source/build/scripts/make_runtime_features.py
+++ b/third_party/WebKit/Source/build/scripts/make_runtime_features.py
@@ -31,6 +31,7 @@
 
 import json5_generator
 import name_utilities
+from name_utilities import class_member_name
 from name_utilities import lower_first
 import template_expander
 
@@ -48,14 +49,15 @@
         # Make sure the resulting dictionaries have all the keys we expect.
         for feature in self._features:
             feature['first_lowered_name'] = lower_first(feature['name'])
+            feature['class_member_name'] = class_member_name(feature['name'])
             # Most features just check their isFooEnabled bool
             # but some depend on or are implied by other bools.
-            enabled_condition = 'is%sEnabled' % feature['name']
+            enabled_condition = 'is_%senabled_' % feature['class_member_name']
             assert not feature['implied_by'] or not feature['depends_on'], 'Only one of implied_by and depends_on is allowed'
             for implied_by_name in feature['implied_by']:
-                enabled_condition += ' || is%sEnabled' % implied_by_name
+                enabled_condition += ' || is_%senabled_' % class_member_name(implied_by_name)
             for dependant_name in feature['depends_on']:
-                enabled_condition += ' && is%sEnabled' % dependant_name
+                enabled_condition += ' && is_%senabled_' % class_member_name(dependant_name)
             feature['enabled_condition'] = enabled_condition
         self._standard_features = [feature for feature in self._features if not feature['custom']]
         self._origin_trial_features = [feature for feature in self._features if feature['origin_trial_feature_name']]
diff --git a/third_party/WebKit/Source/build/scripts/name_utilities.py b/third_party/WebKit/Source/build/scripts/name_utilities.py
index 07a8ef0..ad25bf6 100644
--- a/third_party/WebKit/Source/build/scripts/name_utilities.py
+++ b/third_party/WebKit/Source/build/scripts/name_utilities.py
@@ -32,21 +32,41 @@
 
 # Acronyms are kept as all caps.
 ACRONYMS = [
+    '2D',
+    '2G',
     '3D',
-    'CSSOM',
+    '3G',
+    'API',
+    'CORS',
+    'CSP',
     'CSS',
+    'CSSOM',
     'DNS',
+    'DOM',
     'FE',
     'FTP',
+    'GL',
     'HTML',
+    'IDB',
+    'IFrame',
     'JS',
+    'NFC',
+    'NG',
+    'OM',
+    'RFC',
+    'RTCRtp',
     'SMIL',
     'SVG',
+    'UI',
     'URL',
+    'USB',
+    'VR',
+    'VTT',
     'WOFF',
     'XML',
     'XSLT',
     'XSS',
+    'YUV',
 ]
 
 
diff --git a/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
index 349fd5e5..0f3827f5 100644
--- a/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/EventFactory.cpp.tmpl
@@ -4,18 +4,18 @@
 {{source_files_for_generated_file(template_file, input_files)}}
 
 {% if suffix == 'Modules' %}
-#include "modules/{{namespace}}{{suffix}}Factory.h"
+#include "modules/EventModulesFactory.h"
 {% else %}
-#include "core/events/{{namespace}}Factory.h"
+#include "core/events/EventFactory.h"
 {% endif %}
 
-#include "{{namespace}}{{suffix}}Headers.h"
+#include "Event{{suffix}}Headers.h"
 #include "core/frame/Deprecation.h"
 #include "platform/RuntimeEnabledFeatures.h"
 
 namespace blink {
 
-{{namespace}}* {{namespace}}{{suffix}}Factory::Create(ExecutionContext* executionContext, const String& type) {
+Event* Event{{suffix}}Factory::Create(ExecutionContext* executionContext, const String& type) {
   {% for event in events if event|script_name|create_event_whitelist or event|script_name|create_event_measure_whitelist %}
   {% if event|script_name|create_event_whitelist or event|script_name|create_event_measure_whitelist %}
   if (DeprecatedEqualIgnoringCase(type, "{{event|script_name}}"){% if event.RuntimeEnabled %} && RuntimeEnabledFeatures::{{event.RuntimeEnabled}}(){% endif %}) {
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
index 766cfb5..9e73298 100644
--- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.cpp.tmpl
@@ -12,14 +12,14 @@
 
 RuntimeEnabledFeatures::Backup::Backup()
   : {% for feature in standard_features -%}
-    {{feature.first_lowered_name}}_(RuntimeEnabledFeatures::{{feature.name}}Enabled())
+    {{feature.class_member_name}}(RuntimeEnabledFeatures::{{feature.name}}Enabled())
     {%- if not loop.last %},
     {%+ endif -%}
     {% endfor %} {}
 
 void RuntimeEnabledFeatures::Backup::Restore() {
   {% for feature in standard_features %}
-  RuntimeEnabledFeatures::Set{{feature.name}}Enabled({{feature.first_lowered_name}}_);
+  RuntimeEnabledFeatures::Set{{feature.name}}Enabled({{feature.class_member_name}});
   {% endfor %}
 }
 
@@ -45,7 +45,7 @@
     bool* setting;
   } kFeatures[] = {
   {% for feature in standard_features %}
-    {"{{feature.name}}", &is{{feature.name}}Enabled},
+    {"{{feature.name}}", &is_{{feature.class_member_name}}enabled_},
   {% endfor %}
   };
   for (const auto& feature : kFeatures) {
@@ -58,7 +58,7 @@
 }
 
 {% for feature in standard_features %}
-bool RuntimeEnabledFeatures::is{{feature.name}}Enabled = {{'true' if feature.status == 'stable' else 'false'}};
+bool RuntimeEnabledFeatures::is_{{feature.class_member_name}}enabled_ = {{'true' if feature.status == 'stable' else 'false'}};
 {% endfor %}
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
index 221c151b..9e095da 100644
--- a/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/RuntimeEnabledFeatures.h.tmpl
@@ -26,7 +26,7 @@
 
    private:
     {% for feature in standard_features %}
-    bool {{feature.first_lowered_name}}_;
+    bool {{feature.class_member_name}};
     {% endfor %}
   };
 
@@ -35,13 +35,13 @@
   {% endfor %}
   static void SetOriginTrialControlledFeaturesEnabled(bool);
 
-  static void SetFeatureEnabledFromString(const std::string& name, bool isEnabled);
+  static void SetFeatureEnabledFromString(const std::string& name, bool enabled);
 
   {% for feature in features %}
   {% if feature.custom %}
   static bool {{feature.name}}Enabled();
   {% else %}
-  static void Set{{feature.name}}Enabled(bool isEnabled) { is{{feature.name}}Enabled = isEnabled; }
+  static void Set{{feature.name}}Enabled(bool enabled) { is_{{feature.class_member_name}}enabled_ = enabled; }
   static bool {{feature.name}}Enabled() { return {{feature.enabled_condition}}; }
 
   {% endif %}
@@ -49,7 +49,7 @@
 
  private:
   {% for feature in standard_features %}
-  static bool is{{feature.name}}Enabled;
+  static bool is_{{feature.class_member_name}}enabled_;
   {% endfor %}
 };
 
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 038db2d..63b26d9 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -421,7 +421,6 @@
     "properties/CSSPropertyAPIBackgroundColor.cpp",
     "properties/CSSPropertyAPIBackgroundOrMaskImage.cpp",
     "properties/CSSPropertyAPIBackgroundOrMaskSize.cpp",
-    "properties/CSSPropertyAPIBaseCustom.cpp",
     "properties/CSSPropertyAPIBaselineShift.cpp",
     "properties/CSSPropertyAPIBorderColor.cpp",
     "properties/CSSPropertyAPIBorderImageOutset.cpp",
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 6d86b5b..c476e1cb 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -4,35 +4,27 @@
 
 #include "core/css/parser/CSSPropertyParser.h"
 
-#include <memory>
 #include "core/StylePropertyShorthand.h"
 #include "core/css/CSSFontFaceSrcValue.h"
-#include "core/css/CSSIdentifierValue.h"
 #include "core/css/CSSInheritedValue.h"
 #include "core/css/CSSInitialValue.h"
 #include "core/css/CSSPendingSubstitutionValue.h"
-#include "core/css/CSSPrimitiveValueMappings.h"
 #include "core/css/CSSUnicodeRangeValue.h"
 #include "core/css/CSSUnsetValue.h"
 #include "core/css/CSSVariableReferenceValue.h"
 #include "core/css/HashTools.h"
-#include "core/css/parser/CSSParserFastPaths.h"
-#include "core/css/parser/CSSParserIdioms.h"
 #include "core/css/parser/CSSParserLocalContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/parser/CSSVariableParser.h"
 #include "core/css/properties/CSSPropertyAPI.h"
-#include "core/css/properties/CSSPropertyAlignmentUtils.h"
-#include "core/css/properties/CSSPropertyBackgroundUtils.h"
 #include "core/css/properties/CSSPropertyFontUtils.h"
-#include "core/frame/UseCounter.h"
-#include "core/layout/LayoutTheme.h"
-#include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
 
 using namespace CSSPropertyParserHelpers;
 
+class CSSIdentifierValue;
+
 CSSPropertyParser::CSSPropertyParser(
     const CSSParserTokenRange& range,
     const CSSParserContext* context,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaseCustom.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaseCustom.cpp
deleted file mode 100644
index 3653e7d..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaseCustom.cpp
+++ /dev/null
@@ -1,49 +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.
-
-#include "core/css/properties/CSSPropertyAPI.h"
-
-#include "core/CSSPropertyNames.h"
-#include "core/StylePropertyShorthand.h"
-#include "core/css/CSSValue.h"
-#include "core/css/parser/CSSParserContext.h"
-#include "core/css/parser/CSSParserLocalContext.h"
-#include "core/css/parser/CSSPropertyParserHelpers.h"
-#include "core/css/properties/CSSPropertyAnimationTimingFunctionUtils.h"
-#include "core/css/properties/CSSPropertyBackgroundUtils.h"
-#include "core/css/properties/CSSPropertyBorderImageUtils.h"
-#include "core/css/properties/CSSPropertyBoxShadowUtils.h"
-#include "core/css/properties/CSSPropertyGridUtils.h"
-#include "core/css/properties/CSSPropertyLengthUtils.h"
-#include "core/css/properties/CSSPropertyMarginUtils.h"
-#include "core/css/properties/CSSPropertyPositionUtils.h"
-#include "core/css/properties/CSSPropertyTextDecorationLineUtils.h"
-#include "core/css/properties/CSSPropertyTransitionPropertyUtils.h"
-#include "platform/RuntimeEnabledFeatures.h"
-
-namespace blink {
-
-using namespace CSSPropertyParserHelpers;
-
-const CSSValue* CSSPropertyAPI::ParseSingleValue(
-    CSSPropertyID property,
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext& local_context) const {
-  // This is the legacy ParseSingleValue code.
-  // TODO(bugsnash): Move all of this to individual CSSPropertyAPI subclasses.
-  return nullptr;
-}
-
-bool CSSPropertyAPI::ParseShorthand(
-    CSSPropertyID property,
-    bool important,
-    CSSParserTokenRange& range,
-    const CSSParserContext& context,
-    const CSSParserLocalContext& local_context,
-    HeapVector<CSSProperty, 256>& properties) const {
-  return false;
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index daba8c8..81dde9a 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -297,6 +297,7 @@
     "suggestion/TextSuggestionBackendImpl.h",
     "suggestion/TextSuggestionController.cpp",
     "suggestion/TextSuggestionController.h",
+    "suggestion/TextSuggestionInfo.h",
   ]
 
   if (is_mac) {
diff --git a/third_party/WebKit/Source/core/editing/EditingTestBase.cpp b/third_party/WebKit/Source/core/editing/EditingTestBase.cpp
index bf7368cb..df93571 100644
--- a/third_party/WebKit/Source/core/editing/EditingTestBase.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingTestBase.cpp
@@ -9,11 +9,26 @@
 #include "core/dom/Text.h"
 #include "core/editing/testing/SelectionSample.h"
 #include "core/frame/LocalFrameView.h"
+#include "core/html/HTMLCollection.h"
 #include "core/html/HTMLElement.h"
 #include "core/testing/DummyPageHolder.h"
 
 namespace blink {
 
+namespace {
+
+Element* GetOrCreateElement(ContainerNode* parent,
+                            const HTMLQualifiedName& tag_name) {
+  HTMLCollection* elements = parent->getElementsByTagNameNS(
+      tag_name.NamespaceURI(), tag_name.LocalName());
+  if (!elements->IsEmpty())
+    return elements->item(0);
+  return parent->ownerDocument()->createElement(tag_name,
+                                                kCreatedByCreateElement);
+}
+
+}  // namespace
+
 EditingTestBase::EditingTestBase() {}
 
 EditingTestBase::~EditingTestBase() {}
@@ -30,6 +45,15 @@
   return GetFrame().Selection();
 }
 
+void EditingTestBase::InsertStyleElement(const std::string& style_rules) {
+  Element* const head = GetOrCreateElement(&GetDocument(), HTMLNames::headTag);
+  DCHECK_EQ(head, GetOrCreateElement(&GetDocument(), HTMLNames::headTag));
+  Element* const style =
+      GetDocument().createElement(HTMLNames::styleTag, kCreatedByCreateElement);
+  style->setTextContent(String(style_rules.data(), style_rules.size()));
+  head->appendChild(style);
+}
+
 Position EditingTestBase::SetCaretTextToBody(
     const std::string& selection_text) {
   const SelectionInDOMTree selection = SetSelectionTextToBody(selection_text);
diff --git a/third_party/WebKit/Source/core/editing/EditingTestBase.h b/third_party/WebKit/Source/core/editing/EditingTestBase.h
index 5d7ec4b..a72fa17 100644
--- a/third_party/WebKit/Source/core/editing/EditingTestBase.h
+++ b/third_party/WebKit/Source/core/editing/EditingTestBase.h
@@ -31,6 +31,10 @@
   EditingTestBase();
   ~EditingTestBase() override;
 
+  // Insert STYLE element with |style_rules|, no need to have "<style>", into
+  // HEAD.
+  void InsertStyleElement(const std::string& style_rules);
+
   // Returns |Position| for specified |caret_text|, which is HTML markup with
   // caret marker "|".
   Position SetCaretTextToBody(const std::string& caret_text);
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index 1735ea05..0858ad29 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -496,11 +496,21 @@
     if (ephemeral_line_range.IsNull())
       continue;
 
-    GetDocument().Markers().AddCompositionMarker(
-        ephemeral_line_range, ime_text_span.UnderlineColor(),
-        ime_text_span.Thick() ? StyleableMarker::Thickness::kThick
-                              : StyleableMarker::Thickness::kThin,
-        ime_text_span.BackgroundColor());
+    if (ime_text_span.GetType() == ImeTextSpan::Type::kComposition) {
+      GetDocument().Markers().AddCompositionMarker(
+          ephemeral_line_range, ime_text_span.UnderlineColor(),
+          ime_text_span.Thick() ? StyleableMarker::Thickness::kThick
+                                : StyleableMarker::Thickness::kThin,
+          ime_text_span.BackgroundColor());
+    } else if (ime_text_span.GetType() == ImeTextSpan::Type::kSuggestion) {
+      GetDocument().Markers().AddSuggestionMarker(
+          ephemeral_line_range, ime_text_span.Suggestions(),
+          ime_text_span.SuggestionHighlightColor(),
+          ime_text_span.UnderlineColor(),
+          ime_text_span.Thick() ? StyleableMarker::Thickness::kThick
+                                : StyleableMarker::Thickness::kThin,
+          ime_text_span.BackgroundColor());
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index 39ada6fc..dfe85f87 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -400,7 +400,7 @@
   // makes the IsValidFor() check fail.
   if (has_editable_style && event.Event().FromTouch() &&
       position_to_use.IsValidFor(*frame_->GetDocument())) {
-    frame_->GetTextSuggestionController().HandlePotentialMisspelledWordTap(
+    frame_->GetTextSuggestionController().HandlePotentialSuggestionTap(
         position_to_use.GetPosition());
   }
 
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp
index a14f8b6..751075e 100644
--- a/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleUnitsWordTest.cpp
@@ -18,13 +18,6 @@
                 StartOfWord(CreateVisiblePosition(position)).DeepEquivalent())
             .Build());
   }
-
-  void InsertStyleElement(const std::string& style_rules) {
-    Element* const style = GetDocument().createElement("style");
-    style->setTextContent(String(style_rules.data(), style_rules.size()));
-    GetDocument().body()->parentNode()->InsertBefore(style,
-                                                     GetDocument().body());
-  }
 };
 
 TEST_F(VisibleUnitsWordTest, StartOfWordBasic) {
diff --git a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.cpp b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.cpp
index f92957e..fb607bb 100644
--- a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.cpp
+++ b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.cpp
@@ -28,25 +28,36 @@
     frame_->GetTextSuggestionController().ApplySpellCheckSuggestion(suggestion);
 }
 
+void TextSuggestionBackendImpl::ApplyTextSuggestion(int32_t marker_tag,
+                                                    int32_t suggestion_index) {
+  if (frame_) {
+    frame_->GetTextSuggestionController().ApplyTextSuggestion(marker_tag,
+                                                              suggestion_index);
+  }
+}
+
 void TextSuggestionBackendImpl::DeleteActiveSuggestionRange() {
   if (frame_)
     frame_->GetTextSuggestionController().DeleteActiveSuggestionRange();
 }
 
-void TextSuggestionBackendImpl::NewWordAddedToDictionary(
+void TextSuggestionBackendImpl::OnNewWordAddedToDictionary(
     const WTF::String& word) {
   if (frame_)
-    frame_->GetTextSuggestionController().NewWordAddedToDictionary(word);
+    frame_->GetTextSuggestionController().OnNewWordAddedToDictionary(word);
 }
 
-void TextSuggestionBackendImpl::SpellCheckMenuTimeoutCallback() {
+void TextSuggestionBackendImpl::OnSuggestionMenuClosed() {
   if (frame_)
-    frame_->GetTextSuggestionController().SpellCheckMenuTimeoutCallback();
+    frame_->GetTextSuggestionController().OnSuggestionMenuClosed();
 }
 
-void TextSuggestionBackendImpl::SuggestionMenuClosed() {
-  if (frame_)
-    frame_->GetTextSuggestionController().SuggestionMenuClosed();
+void TextSuggestionBackendImpl::SuggestionMenuTimeoutCallback(
+    int32_t max_number_of_suggestions) {
+  if (frame_) {
+    frame_->GetTextSuggestionController().SuggestionMenuTimeoutCallback(
+        max_number_of_suggestions);
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.h b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.h
index 4b9164c8..194356a 100644
--- a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.h
+++ b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionBackendImpl.h
@@ -20,10 +20,11 @@
   static void Create(LocalFrame*, mojom::blink::TextSuggestionBackendRequest);
 
   void ApplySpellCheckSuggestion(const String& suggestion) final;
+  void ApplyTextSuggestion(int32_t marker_tag, int32_t suggestion_index) final;
   void DeleteActiveSuggestionRange() final;
-  void NewWordAddedToDictionary(const String& word) final;
-  void SpellCheckMenuTimeoutCallback() final;
-  void SuggestionMenuClosed() final;
+  void OnNewWordAddedToDictionary(const String& word) final;
+  void OnSuggestionMenuClosed() final;
+  void SuggestionMenuTimeoutCallback(int32_t max_number_of_suggestions) final;
 
  private:
   explicit TextSuggestionBackendImpl(LocalFrame&);
diff --git a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.cpp b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.cpp
index a696bac..850ad6a 100644
--- a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.cpp
+++ b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.cpp
@@ -11,7 +11,10 @@
 #include "core/editing/Position.h"
 #include "core/editing/markers/DocumentMarkerController.h"
 #include "core/editing/markers/SpellCheckMarker.h"
+#include "core/editing/markers/SuggestionMarker.h"
+#include "core/editing/markers/SuggestionMarkerReplacementScope.h"
 #include "core/editing/spellcheck/SpellChecker.h"
+#include "core/editing/suggestion/TextSuggestionInfo.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/layout/LayoutTheme.h"
@@ -92,6 +95,99 @@
       next_position.IsNull() ? caret_position : next_position);
 }
 
+struct SuggestionInfosWithNodeAndHighlightColor {
+  STACK_ALLOCATED();
+
+  Persistent<Node> text_node;
+  Color highlight_color;
+  Vector<TextSuggestionInfo> suggestion_infos;
+};
+
+SuggestionInfosWithNodeAndHighlightColor ComputeSuggestionInfos(
+    const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
+        node_suggestion_marker_pairs,
+    size_t max_number_of_suggestions) {
+  // We look at all suggestion markers touching or overlapping the touched
+  // location to pull suggestions from. We preferentially draw suggestions from
+  // shorter markers first (since we assume they're more specific to the tapped
+  // location) until we hit our limit.
+  HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>
+      node_suggestion_marker_pairs_sorted_by_length =
+          node_suggestion_marker_pairs;
+  std::sort(node_suggestion_marker_pairs_sorted_by_length.begin(),
+            node_suggestion_marker_pairs_sorted_by_length.end(),
+            [](const std::pair<Node*, DocumentMarker*>& pair1,
+               const std::pair<Node*, DocumentMarker*>& pair2) {
+              const int length1 =
+                  pair1.second->EndOffset() - pair1.second->StartOffset();
+              const int length2 =
+                  pair2.second->EndOffset() - pair2.second->StartOffset();
+              return length1 < length2;
+            });
+
+  SuggestionInfosWithNodeAndHighlightColor
+      suggestion_infos_with_node_and_highlight_color;
+  // In theory, a user could tap right before/after the start of a node and we'd
+  // want to pull in suggestions from either side of the tap. However, this is
+  // an edge case that's unlikely to matter in practice (the user will most
+  // likely just tap in the node where they want to apply the suggestions) and
+  // it complicates implementation, so we require that all suggestions come
+  // from the same text node.
+  suggestion_infos_with_node_and_highlight_color.text_node =
+      node_suggestion_marker_pairs_sorted_by_length.front().first;
+
+  // The highlight color comes from the shortest suggestion marker touching or
+  // intersecting the tapped location. If there's no color set, we use the
+  // default text selection color.
+  const SuggestionMarker& first_suggestion_marker = *ToSuggestionMarker(
+      node_suggestion_marker_pairs_sorted_by_length.front().second);
+
+  suggestion_infos_with_node_and_highlight_color.highlight_color =
+      (first_suggestion_marker.SuggestionHighlightColor() == 0)
+          ? LayoutTheme::TapHighlightColor()
+          : first_suggestion_marker.SuggestionHighlightColor();
+
+  Vector<TextSuggestionInfo>& suggestion_infos =
+      suggestion_infos_with_node_and_highlight_color.suggestion_infos;
+  for (const std::pair<Node*, DocumentMarker*>& node_marker_pair :
+       node_suggestion_marker_pairs_sorted_by_length) {
+    if (node_marker_pair.first !=
+        suggestion_infos_with_node_and_highlight_color.text_node)
+      continue;
+
+    if (suggestion_infos.size() == max_number_of_suggestions)
+      break;
+
+    const SuggestionMarker* marker =
+        ToSuggestionMarker(node_marker_pair.second);
+    const Vector<String>& marker_suggestions = marker->Suggestions();
+    for (size_t suggestion_index = 0;
+         suggestion_index < marker_suggestions.size(); ++suggestion_index) {
+      const String& suggestion = marker_suggestions[suggestion_index];
+      if (suggestion_infos.size() == max_number_of_suggestions)
+        break;
+      if (std::find_if(suggestion_infos.begin(), suggestion_infos.end(),
+                       [marker, &suggestion](const TextSuggestionInfo& info) {
+                         return info.span_start ==
+                                    (int32_t)marker->StartOffset() &&
+                                info.span_end == (int32_t)marker->EndOffset() &&
+                                info.suggestion == suggestion;
+                       }) != suggestion_infos.end())
+        continue;
+
+      TextSuggestionInfo suggestion_info;
+      suggestion_info.marker_tag = marker->Tag();
+      suggestion_info.suggestion_index = suggestion_index;
+      suggestion_info.span_start = marker->StartOffset();
+      suggestion_info.span_end = marker->EndOffset();
+      suggestion_info.suggestion = suggestion;
+      suggestion_infos.push_back(suggestion_info);
+    }
+  }
+
+  return suggestion_infos_with_node_and_highlight_color;
+}
+
 }  // namespace
 
 TextSuggestionController::TextSuggestionController(LocalFrame& frame)
@@ -106,14 +202,15 @@
   return is_suggestion_menu_open_;
 }
 
-void TextSuggestionController::HandlePotentialMisspelledWordTap(
+void TextSuggestionController::HandlePotentialSuggestionTap(
     const PositionInFlatTree& caret_position) {
   const EphemeralRangeInFlatTree& range_to_check =
       ComputeRangeSurroundingCaret(caret_position);
 
   const std::pair<const Node*, const DocumentMarker*>& node_and_marker =
-      FirstMarkerIntersectingRange(range_to_check,
-                                   DocumentMarker::MisspellingMarkers());
+      FirstMarkerIntersectingRange(
+          range_to_check, DocumentMarker::kSpelling | DocumentMarker::kGrammar |
+                              DocumentMarker::kSuggestion);
   if (!node_and_marker.first)
     return;
 
@@ -122,7 +219,7 @@
         mojo::MakeRequest(&text_suggestion_host_));
   }
 
-  text_suggestion_host_->StartSpellCheckMenuTimer();
+  text_suggestion_host_->StartSuggestionMenuTimer();
 }
 
 DEFINE_TRACE(TextSuggestionController) {
@@ -130,18 +227,97 @@
   DocumentShutdownObserver::Trace(visitor);
 }
 
+void TextSuggestionController::ReplaceActiveSuggestionRange(
+    const String& suggestion) {
+  const VisibleSelectionInFlatTree& selection =
+      GetFrame().Selection().ComputeVisibleSelectionInFlatTree();
+  if (selection.IsNone())
+    return;
+
+  const EphemeralRangeInFlatTree& range_to_check =
+      selection.IsRange() ? selection.ToNormalizedEphemeralRange()
+                          : ComputeRangeSurroundingCaret(selection.Start());
+  const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
+      node_marker_pairs =
+          GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
+              range_to_check, DocumentMarker::kActiveSuggestion);
+
+  if (node_marker_pairs.IsEmpty())
+    return;
+
+  Node* const marker_text_node = node_marker_pairs.front().first;
+  const DocumentMarker* const marker = node_marker_pairs.front().second;
+
+  const EphemeralRange& range_to_replace =
+      EphemeralRange(Position(marker_text_node, marker->StartOffset()),
+                     Position(marker_text_node, marker->EndOffset()));
+  ReplaceRangeWithText(range_to_replace, suggestion);
+}
+
 void TextSuggestionController::ApplySpellCheckSuggestion(
     const String& suggestion) {
-  ReplaceSpellingMarkerTouchingSelectionWithText(suggestion);
-  SuggestionMenuClosed();
+  ReplaceActiveSuggestionRange(suggestion);
+  OnSuggestionMenuClosed();
+}
+
+void TextSuggestionController::ApplyTextSuggestion(int32_t marker_tag,
+                                                   uint32_t suggestion_index) {
+  const VisibleSelectionInFlatTree& selection =
+      GetFrame().Selection().ComputeVisibleSelectionInFlatTree();
+  if (selection.IsNone()) {
+    OnSuggestionMenuClosed();
+    return;
+  }
+
+  const EphemeralRangeInFlatTree& range_to_check =
+      selection.IsRange() ? selection.ToNormalizedEphemeralRange()
+                          : ComputeRangeSurroundingCaret(selection.Start());
+
+  const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
+      node_marker_pairs =
+          GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
+              range_to_check, DocumentMarker::kSuggestion);
+
+  const Node* marker_text_node = nullptr;
+  SuggestionMarker* marker = nullptr;
+  for (const std::pair<Member<Node>, Member<DocumentMarker>>& node_marker_pair :
+       node_marker_pairs) {
+    SuggestionMarker* suggestion_marker =
+        ToSuggestionMarker(node_marker_pair.second);
+    if (suggestion_marker->Tag() == marker_tag) {
+      marker_text_node = node_marker_pair.first;
+      marker = suggestion_marker;
+      break;
+    }
+  }
+
+  if (!marker) {
+    OnSuggestionMenuClosed();
+    return;
+  }
+
+  const EphemeralRange& range_to_replace =
+      EphemeralRange(Position(marker_text_node, marker->StartOffset()),
+                     Position(marker_text_node, marker->EndOffset()));
+
+  const String& replacement = marker->Suggestions()[suggestion_index];
+  const String& new_suggestion = PlainText(range_to_replace);
+
+  {
+    SuggestionMarkerReplacementScope scope;
+    ReplaceRangeWithText(range_to_replace, replacement);
+  }
+  marker->SetSuggestion(suggestion_index, new_suggestion);
+
+  OnSuggestionMenuClosed();
 }
 
 void TextSuggestionController::DeleteActiveSuggestionRange() {
   AttemptToDeleteActiveSuggestionRange();
-  SuggestionMenuClosed();
+  OnSuggestionMenuClosed();
 }
 
-void TextSuggestionController::NewWordAddedToDictionary(const String& word) {
+void TextSuggestionController::OnNewWordAddedToDictionary(const String& word) {
   // Android pops up a dialog to let the user confirm they actually want to add
   // the word to the dictionary; this method gets called as soon as the dialog
   // is shown. So the word isn't actually in the dictionary here, even if the
@@ -151,29 +327,72 @@
   // Note: this actually matches the behavior in native Android text boxes
   GetDocument().Markers().RemoveSpellingMarkersUnderWords(
       Vector<String>({word}));
-  SuggestionMenuClosed();
+  OnSuggestionMenuClosed();
 }
 
-void TextSuggestionController::SpellCheckMenuTimeoutCallback() {
-  const std::pair<const Node*, const DocumentMarker*>& node_and_marker =
-      FirstMarkerTouchingSelection(DocumentMarker::MisspellingMarkers());
-  if (!node_and_marker.first)
+void TextSuggestionController::OnSuggestionMenuClosed() {
+  if (!IsAvailable())
     return;
 
-  const Node* const marker_text_node = node_and_marker.first;
-  const SpellCheckMarker* const marker =
-      ToSpellCheckMarker(node_and_marker.second);
+  GetDocument().Markers().RemoveMarkersOfTypes(
+      DocumentMarker::kActiveSuggestion);
+  GetFrame().Selection().SetCaretVisible(true);
+  is_suggestion_menu_open_ = false;
+}
 
-  const EphemeralRange marker_range =
+void TextSuggestionController::SuggestionMenuTimeoutCallback(
+    size_t max_number_of_suggestions) {
+  const VisibleSelectionInFlatTree& selection =
+      GetFrame().Selection().ComputeVisibleSelectionInFlatTree();
+  if (selection.IsNone())
+    return;
+
+  const EphemeralRangeInFlatTree& range_to_check =
+      selection.IsRange() ? selection.ToNormalizedEphemeralRange()
+                          : ComputeRangeSurroundingCaret(selection.Start());
+
+  // We can show a menu if the user tapped on either a spellcheck marker or a
+  // suggestion marker. Suggestion markers take precedence (we don't even try
+  // to draw both underlines, suggestion wins).
+  const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
+      node_suggestion_marker_pairs =
+          GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
+              range_to_check, DocumentMarker::kSuggestion);
+  if (!node_suggestion_marker_pairs.IsEmpty()) {
+    ShowSuggestionMenu(node_suggestion_marker_pairs, max_number_of_suggestions);
+    return;
+  }
+
+  // If we didn't find any suggestion markers, look for spell check markers.
+  const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>
+      node_spelling_marker_pairs =
+          GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
+              range_to_check, DocumentMarker::MisspellingMarkers());
+  if (!node_spelling_marker_pairs.IsEmpty())
+    ShowSpellCheckMenu(node_spelling_marker_pairs.front());
+
+  // If we get here, that means the user tapped on a spellcheck or suggestion
+  // marker a few hundred milliseconds ago (to start the double-click timer)
+  // but it's gone now. Oh well...
+}
+
+void TextSuggestionController::ShowSpellCheckMenu(
+    const std::pair<Node*, DocumentMarker*>& node_spelling_marker_pair) {
+  Node* const marker_text_node = node_spelling_marker_pair.first;
+  SpellCheckMarker* const marker =
+      ToSpellCheckMarker(node_spelling_marker_pair.second);
+
+  const EphemeralRange active_suggestion_range =
       EphemeralRange(Position(marker_text_node, marker->StartOffset()),
                      Position(marker_text_node, marker->EndOffset()));
-  const String& misspelled_word = PlainText(marker_range);
+  const String& misspelled_word = PlainText(active_suggestion_range);
   const String& description = marker->Description();
 
   is_suggestion_menu_open_ = true;
   GetFrame().Selection().SetCaretVisible(false);
   GetDocument().Markers().AddActiveSuggestionMarker(
-      marker_range, SK_ColorTRANSPARENT, StyleableMarker::Thickness::kThin,
+      active_suggestion_range, SK_ColorTRANSPARENT,
+      StyleableMarker::Thickness::kThin,
       LayoutTheme::GetTheme().PlatformActiveSpellingMarkerHighlightColor());
 
   Vector<String> suggestions;
@@ -196,14 +415,80 @@
       std::move(suggestion_ptrs));
 }
 
-void TextSuggestionController::SuggestionMenuClosed() {
-  if (!IsAvailable())
-    return;
+void TextSuggestionController::ShowSuggestionMenu(
+    const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
+        node_suggestion_marker_pairs,
+    size_t max_number_of_suggestions) {
+  DCHECK(!node_suggestion_marker_pairs.IsEmpty());
 
-  GetDocument().Markers().RemoveMarkersOfTypes(
-      DocumentMarker::kActiveSuggestion);
-  GetFrame().Selection().SetCaretVisible(true);
-  is_suggestion_menu_open_ = false;
+  SuggestionInfosWithNodeAndHighlightColor
+      suggestion_infos_with_node_and_highlight_color = ComputeSuggestionInfos(
+          node_suggestion_marker_pairs, max_number_of_suggestions);
+
+  Vector<TextSuggestionInfo>& suggestion_infos =
+      suggestion_infos_with_node_and_highlight_color.suggestion_infos;
+  int span_union_start = suggestion_infos[0].span_start;
+  int span_union_end = suggestion_infos[0].span_end;
+  for (size_t i = 1; i < suggestion_infos.size(); ++i) {
+    span_union_start =
+        std::min(span_union_start, suggestion_infos[i].span_start);
+    span_union_end = std::max(span_union_end, suggestion_infos[i].span_end);
+  }
+
+  const Node* text_node =
+      suggestion_infos_with_node_and_highlight_color.text_node;
+  for (TextSuggestionInfo& info : suggestion_infos) {
+    const EphemeralRange prefix_range(Position(text_node, span_union_start),
+                                      Position(text_node, info.span_start));
+    const String& prefix = PlainText(prefix_range);
+
+    const EphemeralRange suffix_range(Position(text_node, info.span_end),
+                                      Position(text_node, span_union_end));
+    const String& suffix = PlainText(suffix_range);
+
+    info.prefix = prefix;
+    info.suffix = suffix;
+  }
+
+  const EphemeralRange marker_range(Position(text_node, span_union_start),
+                                    Position(text_node, span_union_end));
+
+  GetDocument().Markers().AddActiveSuggestionMarker(
+      marker_range, SK_ColorTRANSPARENT, StyleableMarker::Thickness::kThin,
+      suggestion_infos_with_node_and_highlight_color.highlight_color);
+
+  is_suggestion_menu_open_ = true;
+  GetFrame().Selection().SetCaretVisible(false);
+
+  const String& misspelled_word = PlainText(marker_range);
+  CallMojoShowTextSuggestionMenu(
+      suggestion_infos_with_node_and_highlight_color.suggestion_infos,
+      misspelled_word);
+}
+
+void TextSuggestionController::CallMojoShowTextSuggestionMenu(
+    const Vector<TextSuggestionInfo>& text_suggestion_infos,
+    const String& misspelled_word) {
+  Vector<mojom::blink::TextSuggestionPtr> suggestion_info_ptrs;
+  for (const blink::TextSuggestionInfo& info : text_suggestion_infos) {
+    mojom::blink::TextSuggestionPtr info_ptr(
+        mojom::blink::TextSuggestion::New());
+    info_ptr->marker_tag = info.marker_tag;
+    info_ptr->suggestion_index = info.suggestion_index;
+    info_ptr->prefix = info.prefix;
+    info_ptr->suggestion = info.suggestion;
+    info_ptr->suffix = info.suffix;
+
+    suggestion_info_ptrs.push_back(std::move(info_ptr));
+  }
+
+  const IntRect& absolute_bounds = GetFrame().Selection().AbsoluteCaretBounds();
+  const IntRect& viewport_bounds =
+      GetFrame().View()->ContentsToViewport(absolute_bounds);
+
+  text_suggestion_host_->ShowTextSuggestionMenu(
+      viewport_bounds.X(), viewport_bounds.MaxY(), misspelled_word,
+      std::move(suggestion_info_ptrs));
 }
 
 Document& TextSuggestionController::GetDocument() const {
@@ -287,22 +572,6 @@
   ReplaceRangeWithText(range_to_delete, "");
 }
 
-void TextSuggestionController::ReplaceSpellingMarkerTouchingSelectionWithText(
-    const String& suggestion) {
-  const std::pair<const Node*, const DocumentMarker*>& node_and_marker =
-      FirstMarkerTouchingSelection(DocumentMarker::MisspellingMarkers());
-  if (!node_and_marker.first)
-    return;
-
-  const Node* const marker_text_node = node_and_marker.first;
-  const DocumentMarker* const marker = node_and_marker.second;
-
-  const EphemeralRange range_to_replace(
-      Position(marker_text_node, marker->StartOffset()),
-      Position(marker_text_node, marker->EndOffset()));
-  ReplaceRangeWithText(range_to_replace, suggestion);
-}
-
 void TextSuggestionController::ReplaceRangeWithText(const EphemeralRange& range,
                                                     const String& replacement) {
   GetFrame().Selection().SetSelection(
diff --git a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.h b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.h
index 3e84230..361899ec 100644
--- a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.h
+++ b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionController.h
@@ -16,7 +16,9 @@
 namespace blink {
 
 class Document;
+class DocumentMarker;
 class LocalFrame;
+struct TextSuggestionInfo;
 
 // This class handles functionality related to displaying a menu of text
 // suggestions (e.g. from spellcheck), and performing actions relating to those
@@ -33,14 +35,14 @@
 
   bool IsMenuOpen() const;
 
-  void HandlePotentialMisspelledWordTap(
-      const PositionInFlatTree& caret_position);
+  void HandlePotentialSuggestionTap(const PositionInFlatTree& caret_position);
 
   void ApplySpellCheckSuggestion(const String& suggestion);
+  void ApplyTextSuggestion(int32_t marker_tag, uint32_t suggestion_index);
   void DeleteActiveSuggestionRange();
-  void NewWordAddedToDictionary(const String& word);
-  void SpellCheckMenuTimeoutCallback();
-  void SuggestionMenuClosed();
+  void OnNewWordAddedToDictionary(const String& word);
+  void OnSuggestionMenuClosed();
+  void SuggestionMenuTimeoutCallback(size_t max_number_of_suggestions);
 
   DECLARE_TRACE();
 
@@ -56,7 +58,16 @@
       DocumentMarker::MarkerTypes) const;
 
   void AttemptToDeleteActiveSuggestionRange();
-  void ReplaceSpellingMarkerTouchingSelectionWithText(const String&);
+  void CallMojoShowTextSuggestionMenu(
+      const Vector<TextSuggestionInfo>& text_suggestion_infos,
+      const String& misspelled_word);
+  void ShowSpellCheckMenu(
+      const std::pair<Node*, DocumentMarker*>& node_spelling_marker_pair);
+  void ShowSuggestionMenu(
+      const HeapVector<std::pair<Member<Node>, Member<DocumentMarker>>>&
+          node_suggestion_marker_pairs,
+      size_t max_number_of_suggestions);
+  void ReplaceActiveSuggestionRange(const String&);
   void ReplaceRangeWithText(const EphemeralRange&, const String& replacement);
 
   bool is_suggestion_menu_open_;
diff --git a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionControllerTest.cpp b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionControllerTest.cpp
index 387b969..f39d182 100644
--- a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionControllerTest.cpp
@@ -21,8 +21,9 @@
   Element* div = GetDocument().QuerySelector("div");
   Node* text = div->firstChild();
 
-  GetDocument().Markers().AddSpellingMarker(
-      EphemeralRange(Position(text, 0), Position(text, 8)));
+  GetDocument().Markers().AddActiveSuggestionMarker(
+      EphemeralRange(Position(text, 0), Position(text, 8)), Color::kBlack,
+      StyleableMarker::Thickness::kThin, Color::kBlack);
   // Select immediately before misspelling
   GetDocument().GetFrame()->Selection().SetSelection(
       SelectionInDOMTree::Builder()
@@ -34,6 +35,119 @@
       .ApplySpellCheckSuggestion("spellcheck");
 
   EXPECT_EQ("spellcheck", text->textContent());
+
+  // Cursor should be at end of replaced text
+  const VisibleSelectionInFlatTree& selection =
+      GetFrame().Selection().ComputeVisibleSelectionInFlatTree();
+  EXPECT_EQ(text, selection.Start().ComputeContainerNode());
+  EXPECT_EQ(10, selection.Start().ComputeOffsetInContainerNode());
+  EXPECT_EQ(text, selection.End().ComputeContainerNode());
+  EXPECT_EQ(10, selection.End().ComputeOffsetInContainerNode());
+}
+
+TEST_F(TextSuggestionControllerTest, ApplyTextSuggestion) {
+  SetBodyContent(
+      "<div contenteditable>"
+      "word1 word2 word3 word4"
+      "</div>");
+  Element* div = GetDocument().QuerySelector("div");
+  Node* text = div->firstChild();
+
+  // Add marker on "word1". This marker should *not* be cleared by the
+  // replace operation.
+  GetDocument().Markers().AddSuggestionMarker(
+      EphemeralRange(Position(text, 0), Position(text, 5)),
+      Vector<String>({"marker1"}), Color::kBlack, Color::kBlack,
+      StyleableMarker::Thickness::kThick, Color::kBlack);
+
+  // Add marker on "word1 word2 word3 word4". This marker should *not* be
+  // cleared by the replace operation.
+  GetDocument().Markers().AddSuggestionMarker(
+      EphemeralRange(Position(text, 0), Position(text, 23)),
+      Vector<String>({"marker2"}), Color::kBlack, Color::kBlack,
+      StyleableMarker::Thickness::kThick, Color::kBlack);
+
+  // Add marker on "word2 word3". This marker should *not* be cleared by the
+  // replace operation.
+  GetDocument().Markers().AddSuggestionMarker(
+      EphemeralRange(Position(text, 6), Position(text, 17)),
+      Vector<String>({"marker3"}), Color::kBlack, Color::kBlack,
+      StyleableMarker::Thickness::kThick, Color::kBlack);
+
+  // Add marker on "word4". This marker should *not* be cleared by the
+  // replace operation.
+  GetDocument().Markers().AddSuggestionMarker(
+      EphemeralRange(Position(text, 18), Position(text, 23)),
+      Vector<String>({"marker4"}), Color::kBlack, Color::kBlack,
+      StyleableMarker::Thickness::kThick, Color::kBlack);
+
+  // Add marker on "word1 word2". This marker should be cleared by the
+  // replace operation.
+  GetDocument().Markers().AddSuggestionMarker(
+      EphemeralRange(Position(text, 0), Position(text, 11)),
+      Vector<String>({"marker5"}), Color::kBlack, Color::kBlack,
+      StyleableMarker::Thickness::kThick, Color::kBlack);
+
+  // Add marker on "word3 word4". This marker should be cleared by the
+  // replace operation.
+  GetDocument().Markers().AddSuggestionMarker(
+      EphemeralRange(Position(text, 12), Position(text, 23)),
+      Vector<String>({"marker6"}), Color::kBlack, Color::kBlack,
+      StyleableMarker::Thickness::kThick, Color::kBlack);
+
+  // Select immediately before word2.
+  GetDocument().GetFrame()->Selection().SetSelection(
+      SelectionInDOMTree::Builder()
+          .SetBaseAndExtent(Position(text, 6), Position(text, 6))
+          .Build());
+
+  // Replace "word2 word3" with "marker3" (marker should have tag 3; tags start
+  // from 1, not 0).
+  GetDocument().GetFrame()->GetTextSuggestionController().ApplyTextSuggestion(
+      3, 0);
+
+  // This returns the markers sorted by start offset; we need them sorted by
+  // start *and* end offset, since we have multiple markers starting at 0.
+  DocumentMarkerVector markers = GetDocument().Markers().MarkersFor(text);
+  std::sort(markers.begin(), markers.end(),
+            [](const DocumentMarker* marker1, const DocumentMarker* marker2) {
+              if (marker1->StartOffset() != marker2->StartOffset())
+                return marker1->StartOffset() < marker2->StartOffset();
+              return marker1->EndOffset() < marker2->EndOffset();
+            });
+
+  EXPECT_EQ(4u, markers.size());
+
+  // marker1
+  EXPECT_EQ(0u, markers[0]->StartOffset());
+  EXPECT_EQ(5u, markers[0]->EndOffset());
+
+  // marker2
+  EXPECT_EQ(0u, markers[1]->StartOffset());
+  EXPECT_EQ(19u, markers[1]->EndOffset());
+
+  // marker3
+  EXPECT_EQ(6u, markers[2]->StartOffset());
+  EXPECT_EQ(13u, markers[2]->EndOffset());
+
+  const SuggestionMarker* const suggestion_marker =
+      ToSuggestionMarker(markers[2]);
+  EXPECT_EQ(1u, suggestion_marker->Suggestions().size());
+  EXPECT_EQ(String("word2 word3"), suggestion_marker->Suggestions()[0]);
+
+  // marker4
+  EXPECT_EQ(14u, markers[3]->StartOffset());
+  EXPECT_EQ(19u, markers[3]->EndOffset());
+
+  // marker5 and marker6 should've been cleared
+
+  // Cursor should be at end of replaced text
+  const VisibleSelectionInFlatTree& selection =
+      GetFrame().Selection().ComputeVisibleSelectionInFlatTree();
+  EXPECT_EQ(text, selection.Start().ComputeContainerNode());
+  EXPECT_EQ(13, selection.Start().ComputeOffsetInContainerNode());
+  EXPECT_EQ(text, selection.End().ComputeContainerNode());
+  EXPECT_EQ(13, selection.End().ComputeOffsetInContainerNode());
 }
 
 TEST_F(TextSuggestionControllerTest, DeleteActiveSuggestionRange_DeleteAtEnd) {
@@ -226,7 +340,7 @@
 }
 
 TEST_F(TextSuggestionControllerTest,
-       DeleteActiveSuggestionRange_NewWordAddedToDictionary) {
+       DeleteActiveSuggestionRange_OnNewWordAddedToDictionary) {
   SetBodyContent(
       "<div contenteditable>"
       "embiggen"
@@ -247,7 +361,7 @@
   GetDocument()
       .GetFrame()
       ->GetTextSuggestionController()
-      .NewWordAddedToDictionary("cromulent");
+      .OnNewWordAddedToDictionary("cromulent");
   // Verify the spelling marker is still present
   EXPECT_NE(nullptr, GetDocument()
                          .GetFrame()
@@ -259,7 +373,7 @@
   GetDocument()
       .GetFrame()
       ->GetTextSuggestionController()
-      .NewWordAddedToDictionary("embiggen");
+      .OnNewWordAddedToDictionary("embiggen");
   // Verify the spelling marker is gone
   EXPECT_EQ(nullptr, GetDocument()
                          .GetFrame()
diff --git a/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionInfo.h b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionInfo.h
new file mode 100644
index 0000000..1d9d6a2
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/suggestion/TextSuggestionInfo.h
@@ -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.
+
+#ifndef TextSuggestionInfo_h
+#define TextSuggestionInfo_h
+
+#include "platform/wtf/text/WTFString.h"
+
+namespace blink {
+
+struct TextSuggestionInfo {
+  int32_t marker_tag;
+  uint32_t suggestion_index;
+
+  int32_t span_start;
+  int32_t span_end;
+
+  String prefix;
+  String suggestion;
+  String suffix;
+};
+
+}  // namespace blink
+
+#endif  // TextSuggestionList_h
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
index 4bc312b..1cf2120 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
@@ -203,9 +203,7 @@
       (layout_object->BorderLeft() + layout_object->PaddingLeft()).ToInt(),
       (layout_object->BorderTop() + layout_object->PaddingTop()).ToInt());
 
-  pending_invalidation_rect_.Unite(dirty_rect);
-
-  layout_object->SetMayNeedPaintInvalidation();
+  layout_object->InvalidatePaintRectangle(LayoutRect(dirty_rect));
 }
 
 void WebPluginContainerImpl::SetFocused(bool focused, WebFocusType focus_type) {
@@ -1014,19 +1012,6 @@
   frame->GetPage()->GetFocusController().SetFocusedElement(element_, frame);
 }
 
-void WebPluginContainerImpl::IssuePaintInvalidations() {
-  if (pending_invalidation_rect_.IsEmpty())
-    return;
-
-  LayoutBox* layout_object = ToLayoutBox(element_->GetLayoutObject());
-  if (!layout_object)
-    return;
-
-  layout_object->InvalidatePaintRectangle(
-      LayoutRect(pending_invalidation_rect_));
-  pending_invalidation_rect_ = IntRect();
-}
-
 void WebPluginContainerImpl::ComputeClipRectsForPlugin(
     const HTMLFrameOwnerElement* owner_element,
     IntRect& window_rect,
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
index 3776b539..a57e7fe 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.h
@@ -92,7 +92,6 @@
   bool CanProcessDrag() const override;
   bool WantsWheelEvents() override;
   void UpdateAllLifecyclePhases() override;
-  void InvalidatePaint() override { IssuePaintInvalidations(); }
   void InvalidateRect(const IntRect&);
   void SetFocused(bool, WebFocusType) override;
   void HandleEvent(Event*) override;
@@ -221,8 +220,6 @@
 
   void FocusPlugin();
 
-  void IssuePaintInvalidations();
-
   void CalculateGeometry(IntRect& window_rect,
                          IntRect& clip_rect,
                          IntRect& unobscured_rect);
@@ -233,7 +230,6 @@
   WebPlugin* web_plugin_;
   WebLayer* web_layer_;
   IntRect frame_rect_;
-  IntRect pending_invalidation_rect_;
   TouchEventRequestType touch_event_request_type_;
   bool wants_wheel_events_;
   bool self_visible_;
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 4178524..acb00824 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -209,7 +209,6 @@
           DocumentLifecycle::kUninitialized),
       past_layout_lifecycle_update_(false),
       scroll_anchor_(this),
-      in_perform_scroll_anchoring_adjustments_(false),
       scrollbar_manager_(*this),
       needs_scrollbars_update_(false),
       suppress_adjust_view_size_(false),
@@ -3276,20 +3275,18 @@
 }
 
 void LocalFrameView::PerformScrollAnchoringAdjustments() {
-  // TODO(bokan): Temporary to get more information about crash in
-  // crbug.com/745686.
-  CHECK(!in_perform_scroll_anchoring_adjustments_);
-  in_perform_scroll_anchoring_adjustments_ = true;
+  // Adjust() will cause a scroll which could end up causing a layout and
+  // reentering this method. Copy and clear the queue so we don't modify it
+  // during iteration.
+  AnchoringAdjustmentQueue queue_copy = anchoring_adjustment_queue_;
+  anchoring_adjustment_queue_.clear();
 
-  for (WeakMember<ScrollableArea>& scroller : anchoring_adjustment_queue_) {
+  for (WeakMember<ScrollableArea>& scroller : queue_copy) {
     if (scroller) {
       DCHECK(scroller->GetScrollAnchor());
       scroller->GetScrollAnchor()->Adjust();
     }
   }
-  anchoring_adjustment_queue_.clear();
-
-  in_perform_scroll_anchoring_adjustments_ = false;
 }
 
 void LocalFrameView::PrePaint() {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index c55b2f3..0cc55426 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -1219,10 +1219,6 @@
       HeapLinkedHashSet<WeakMember<ScrollableArea>>;
   AnchoringAdjustmentQueue anchoring_adjustment_queue_;
 
-  // TODO(bokan): Temporary to get more information about crash in
-  // crbug.com/745686.
-  bool in_perform_scroll_anchoring_adjustments_;
-
   // ScrollbarManager holds the Scrollbar instances.
   ScrollbarManager scrollbar_manager_;
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
index 94c469b..400aafd 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -238,6 +238,12 @@
     if (!request)
       return nullptr;
 
+    if (Match(tag_impl_, scriptTag)) {
+      request->SetScriptType(type_attribute_value_ == "module"
+                                 ? ScriptType::kModule
+                                 : ScriptType::kClassic);
+    }
+
     request->SetCrossOrigin(cross_origin_);
     request->SetNonce(nonce_);
     request->SetCharset(Charset());
@@ -520,10 +526,6 @@
               ScriptLoader::kAllowLegacyTypeInTypeAttribute, script_type)) {
         return false;
       }
-      // TODO(kouhei): Enable preload for module scripts, with correct
-      // credentials mode.
-      if (type_attribute_value_ == "module")
-        return false;
       if (ScriptLoader::BlockForNoModule(script_type,
                                          nomodule_attribute_value_)) {
         return false;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
index 256d6f0e..6c47d08 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
@@ -53,6 +53,13 @@
   const char* expected_referrer;
 };
 
+struct CORSTestCase {
+  const char* base_url;
+  const char* input_html;
+  WebURLRequest::FetchRequestMode request_mode;
+  WebURLRequest::FetchCredentialsMode credentials_mode;
+};
+
 struct NonceTestCase {
   const char* base_url;
   const char* input_html;
@@ -132,6 +139,19 @@
     }
   }
 
+  void CORSRequestVerification(
+      Document* document,
+      WebURLRequest::FetchRequestMode request_mode,
+      WebURLRequest::FetchCredentialsMode credentials_mode) {
+    ASSERT_TRUE(preload_request_.get());
+    Resource* resource = preload_request_->Start(document);
+    ASSERT_TRUE(resource);
+    EXPECT_EQ(request_mode,
+              resource->GetResourceRequest().GetFetchRequestMode());
+    EXPECT_EQ(credentials_mode,
+              resource->GetResourceRequest().GetFetchCredentialsMode());
+  }
+
   void NonceRequestVerification(const char* nonce) {
     ASSERT_TRUE(preload_request_.get());
     if (strlen(nonce))
@@ -254,6 +274,18 @@
     }
   }
 
+  void Test(CORSTestCase test_case) {
+    HTMLMockHTMLResourcePreloader preloader;
+    KURL base_url(kParsedURLString, test_case.base_url);
+    scanner_->AppendToEnd(String(test_case.input_html));
+    PreloadRequestStream requests = scanner_->Scan(base_url, nullptr);
+    preloader.TakeAndPreload(requests);
+
+    preloader.CORSRequestVerification(&dummy_page_holder_->GetDocument(),
+                                      test_case.request_mode,
+                                      test_case.credentials_mode);
+  }
+
   void Test(NonceTestCase test_case) {
     HTMLMockHTMLResourcePreloader preloader;
     KURL base_url(kParsedURLString, test_case.base_url);
@@ -760,6 +792,38 @@
     Test(test_case);
 }
 
+TEST_F(HTMLPreloadScannerTest, testCORS) {
+  CORSTestCase test_cases[] = {
+      {"http://example.test", "<script src='/script'></script>",
+       WebURLRequest::kFetchRequestModeNoCORS,
+       WebURLRequest::kFetchCredentialsModeInclude},
+      {"http://example.test", "<script crossorigin src='/script'></script>",
+       WebURLRequest::kFetchRequestModeCORS,
+       WebURLRequest::kFetchCredentialsModeSameOrigin},
+      {"http://example.test",
+       "<script crossorigin=use-credentials src='/script'></script>",
+       WebURLRequest::kFetchRequestModeCORS,
+       WebURLRequest::kFetchCredentialsModeInclude},
+      {"http://example.test", "<script type='module' src='/script'></script>",
+       WebURLRequest::kFetchRequestModeCORS,
+       WebURLRequest::kFetchCredentialsModeOmit},
+      {"http://example.test",
+       "<script type='module' crossorigin='anonymous' src='/script'></script>",
+       WebURLRequest::kFetchRequestModeCORS,
+       WebURLRequest::kFetchCredentialsModeSameOrigin},
+      {"http://example.test",
+       "<script type='module' crossorigin='use-credentials' "
+       "src='/script'></script>",
+       WebURLRequest::kFetchRequestModeCORS,
+       WebURLRequest::kFetchCredentialsModeInclude},
+  };
+
+  for (const auto& test_case : test_cases) {
+    SCOPED_TRACE(test_case.input_html);
+    Test(test_case);
+  }
+}
+
 TEST_F(HTMLPreloadScannerTest, testNonce) {
   NonceTestCase test_cases[] = {
       {"http://example.test", "<script src='/script'></script>", ""},
diff --git a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
index e1540b9..87329f5 100644
--- a/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/PreloadRequest.cpp
@@ -63,7 +63,24 @@
                                        kCrossOriginAttributeAnonymous);
   }
 
-  if (cross_origin_ != kCrossOriginAttributeNotSet) {
+  if (script_type_ == ScriptType::kModule) {
+    DCHECK_EQ(resource_type_, Resource::kScript);
+    WebURLRequest::FetchCredentialsMode credentials_mode =
+        WebURLRequest::kFetchCredentialsModeOmit;
+    switch (cross_origin_) {
+      case kCrossOriginAttributeNotSet:
+        credentials_mode = WebURLRequest::kFetchCredentialsModeOmit;
+        break;
+      case kCrossOriginAttributeAnonymous:
+        credentials_mode = WebURLRequest::kFetchCredentialsModeSameOrigin;
+        break;
+      case kCrossOriginAttributeUseCredentials:
+        credentials_mode = WebURLRequest::kFetchCredentialsModeInclude;
+        break;
+    }
+    params.SetCrossOriginAccessControl(document->GetSecurityOrigin(),
+                                       credentials_mode);
+  } else if (cross_origin_ != kCrossOriginAttributeNotSet) {
     params.SetCrossOriginAccessControl(document->GetSecurityOrigin(),
                                        cross_origin_);
   }
@@ -78,9 +95,13 @@
   if (request_type_ == kRequestTypeLinkRelPreload)
     params.SetLinkPreload(true);
 
-  if (resource_type_ == Resource::kScript ||
-      resource_type_ == Resource::kCSSStyleSheet ||
-      resource_type_ == Resource::kImportResource) {
+  if (script_type_ == ScriptType::kModule) {
+    DCHECK_EQ(resource_type_, Resource::kScript);
+    params.SetDecoderOptions(
+        TextResourceDecoderOptions::CreateAlwaysUseUTF8ForText());
+  } else if (resource_type_ == Resource::kScript ||
+             resource_type_ == Resource::kCSSStyleSheet ||
+             resource_type_ == Resource::kImportResource) {
     params.SetCharset(charset_.IsEmpty() ? document->Encoding()
                                          : WTF::TextEncoding(charset_));
   }
diff --git a/third_party/WebKit/Source/core/html/parser/PreloadRequest.h b/third_party/WebKit/Source/core/html/parser/PreloadRequest.h
index 91f02caa..66cf4a9 100644
--- a/third_party/WebKit/Source/core/html/parser/PreloadRequest.h
+++ b/third_party/WebKit/Source/core/html/parser/PreloadRequest.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include "core/CoreExport.h"
+#include "core/dom/Script.h"
 #include "platform/CrossOriginAttributeValue.h"
 #include "platform/loader/fetch/ClientHintsPreferences.h"
 #include "platform/loader/fetch/FetchParameters.h"
@@ -95,6 +96,8 @@
   }
   ReferrerPolicy GetReferrerPolicy() const { return referrer_policy_; }
 
+  void SetScriptType(ScriptType script_type) { script_type_ = script_type; }
+
   // Only scripts and css stylesheets need to have integrity set on preloads.
   // This is because neither resource keeps raw data around to redo an
   // integrity check. A resource in memory cache needs integrity
@@ -127,6 +130,7 @@
         resource_url_(resource_url.IsolatedCopy()),
         base_url_(base_url.Copy()),
         resource_type_(resource_type),
+        script_type_(ScriptType::kClassic),
         cross_origin_(kCrossOriginAttributeNotSet),
         discovery_time_(MonotonicallyIncreasingTime()),
         defer_(FetchParameters::kNoDefer),
@@ -146,6 +150,7 @@
   KURL base_url_;
   String charset_;
   Resource::Type resource_type_;
+  ScriptType script_type_;
   CrossOriginAttributeValue cross_origin_;
   String nonce_;
   double discovery_time_;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index d1b5ac1bf..c84f66b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1128,11 +1128,15 @@
   return IntSize();
 }
 
-LayoutRect LayoutObject::InvalidatePaintRectangle(
-    const LayoutRect& dirty_rect,
-    DisplayItemClient* display_item_client) const {
-  return ObjectPaintInvalidator(*this).InvalidatePaintRectangle(
-      dirty_rect, display_item_client);
+void LayoutObject::InvalidatePaintRectangle(const LayoutRect& dirty_rect) {
+  if (dirty_rect.IsEmpty())
+    return;
+
+  auto& rare_paint_data = EnsureRarePaintData();
+  rare_paint_data.SetPartialInvalidationRect(
+      UnionRect(dirty_rect, rare_paint_data.PartialInvalidationRect()));
+
+  SetMayNeedPaintInvalidationWithoutGeometryChange();
 }
 
 LayoutRect LayoutObject::SelectionRectInViewCoordinates() const {
@@ -3370,6 +3374,8 @@
 #if DCHECK_IS_ON()
   DCHECK(!ShouldCheckForPaintInvalidation() || PaintInvalidationStateIsDirty());
 #endif
+  if (rare_paint_data_)
+    rare_paint_data_->SetPartialInvalidationRect(LayoutRect());
   ClearShouldDoFullPaintInvalidation();
   bitfields_.SetMayNeedPaintInvalidation(false);
   bitfields_.SetMayNeedPaintInvalidationSubtree(false);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 52edf5c..85709b192 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1364,12 +1364,7 @@
 
   // Invalidate the paint of a specific subrectangle within a given object. The
   // rect is in the object's coordinate space.
-  // If a DisplayItemClient is specified, that client is invalidated rather than
-  // |this|.
-  // Returns the visual rect that was invalidated (i.e, invalidation in the
-  // space of the GraphicsLayer backing this LayoutObject).
-  LayoutRect InvalidatePaintRectangle(const LayoutRect&,
-                                      DisplayItemClient* = nullptr) const;
+  void InvalidatePaintRectangle(const LayoutRect&);
 
   void SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
 
@@ -1891,6 +1886,10 @@
     return rare_paint_data_ ? rare_paint_data_->SelectionVisualRect()
                             : LayoutRect();
   }
+  LayoutRect PartialInvalidationRect() const {
+    return rare_paint_data_ ? rare_paint_data_->PartialInvalidationRect()
+                            : LayoutRect();
+  }
 
  protected:
   enum LayoutObjectType {
diff --git a/third_party/WebKit/Source/core/paint/BlockPainter.cpp b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
index 3da2342..1247a21 100644
--- a/third_party/WebKit/Source/core/paint/BlockPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BlockPainter.cpp
@@ -284,7 +284,7 @@
     Optional<ScopedPaintChunkProperties> scoped_scroll_property;
     Optional<ScrollRecorder> scroll_recorder;
     Optional<PaintInfo> scrolled_paint_info;
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       const auto* object_properties =
           layout_block_.FirstFragment()
               ? layout_block_.FirstFragment()->PaintProperties()
diff --git a/third_party/WebKit/Source/core/paint/BoxClipper.cpp b/third_party/WebKit/Source/core/paint/BoxClipper.cpp
index 18400e2..373a49a5 100644
--- a/third_party/WebKit/Source/core/paint/BoxClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxClipper.cpp
@@ -43,7 +43,7 @@
   if (paint_info_.phase == kPaintPhaseMask)
     return;
 
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     const auto* object_properties =
         box_.FirstFragment() ? box_.FirstFragment()->PaintProperties()
                              : nullptr;
diff --git a/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp b/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
index 8ceee8ad..fbe1e16 100644
--- a/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
@@ -68,7 +68,7 @@
       clipper_state_(ClipperState::kNotApplied),
       layout_object_(layout_object),
       context_(context) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   if (clip_path_operation.GetType() == ClipPathOperation::SHAPE) {
     ShapeClipPathOperation& shape =
@@ -106,7 +106,7 @@
 }
 
 ClipPathClipper::~ClipPathClipper() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   if (resource_clipper_)
     FinishEffect();
diff --git a/third_party/WebKit/Source/core/paint/FilterPainter.cpp b/third_party/WebKit/Source/core/paint/FilterPainter.cpp
index 704bdd3..8c53a55 100644
--- a/third_party/WebKit/Source/core/paint/FilterPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/FilterPainter.cpp
@@ -20,7 +20,7 @@
 namespace blink {
 
 sk_sp<SkImageFilter> FilterPainter::GetImageFilter(PaintLayer& layer) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return nullptr;
 
   if (!layer.PaintsWithFilters())
diff --git a/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp b/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
index bbc06ad1..d2cdd27 100644
--- a/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/FloatClipRecorder.cpp
@@ -17,14 +17,14 @@
     : context_(context),
       client_(client),
       clip_type_(DisplayItem::PaintPhaseToFloatClipType(paint_phase)) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().CreateAndAppend<FloatClipDisplayItem>(
       client_, clip_type_, clip_rect);
 }
 
 FloatClipRecorder::~FloatClipRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   DisplayItem::Type end_type =
       DisplayItem::FloatClipTypeToEndFloatClipType(clip_type_);
diff --git a/third_party/WebKit/Source/core/paint/FramePainter.cpp b/third_party/WebKit/Source/core/paint/FramePainter.cpp
index 76ec4d3..7628b03 100644
--- a/third_party/WebKit/Source/core/paint/FramePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/FramePainter.cpp
@@ -38,7 +38,7 @@
       GetFrameView().Location(), GetFrameView().VisibleContentRect().Size());
   IntPoint content_offset =
       -GetFrameView().Location() + GetFrameView().ScrollOffsetInt();
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
       !RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
     auto content_cull_rect = rect;
     content_cull_rect.UpdateForScrollingContents(
@@ -63,7 +63,7 @@
     // settings()->rootLayerScrolls() is enabled.
     // TODO(pdr): Make this conditional on the rootLayerScrolls setting.
     Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
         !RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
       if (const PropertyTreeState* contents_state =
               frame_view_->TotalPropertyTreeStateForContents()) {
@@ -103,7 +103,7 @@
     scroll_view_dirty_rect.MoveBy(-GetFrameView().Location());
 
     Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       if (const PropertyTreeState* contents_state =
               frame_view_->TotalPropertyTreeStateForContents()) {
         // The scrollbar's property nodes are similar to the frame view's
diff --git a/third_party/WebKit/Source/core/paint/HTMLCanvasPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/HTMLCanvasPaintInvalidator.cpp
index a1b6443..8c49a4a9 100644
--- a/third_party/WebKit/Source/core/paint/HTMLCanvasPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/HTMLCanvasPaintInvalidator.cpp
@@ -12,17 +12,11 @@
 namespace blink {
 
 PaintInvalidationReason HTMLCanvasPaintInvalidator::InvalidatePaint() {
-  PaintInvalidationReason reason =
-      BoxPaintInvalidator(html_canvas_, context_).InvalidatePaint();
-
-  HTMLCanvasElement* element = toHTMLCanvasElement(html_canvas_.GetNode());
-  if (element->IsDirty()) {
+  auto* element = toHTMLCanvasElement(html_canvas_.GetNode());
+  if (element->IsDirty())
     element->DoDeferredPaintInvalidation();
-    if (reason < PaintInvalidationReason::kRectangle)
-      reason = PaintInvalidationReason::kRectangle;
-  }
 
-  return reason;
+  return BoxPaintInvalidator(html_canvas_, context_).InvalidatePaint();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp b/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp
index ddb33be..1d2132f 100644
--- a/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/LayerClipRecorder.cpp
@@ -27,7 +27,7 @@
     : graphics_context_(graphics_context),
       client_(client),
       clip_type_(clip_type) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   IntRect snapped_clip_rect = PixelSnappedIntRect(clip_rect.Rect());
   bool painting_masks =
@@ -107,7 +107,7 @@
 }
 
 LayerClipRecorder::~LayerClipRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   graphics_context_.GetPaintController().EndItem<EndClipDisplayItem>(
       client_, DisplayItem::ClipTypeToEndClipType(clip_type_));
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
index 93c7be0..3f8ae83 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.cpp
@@ -353,42 +353,6 @@
   }
 }
 
-LayoutRect ObjectPaintInvalidator::InvalidatePaintRectangle(
-    const LayoutRect& dirty_rect,
-    DisplayItemClient* display_item_client) {
-  CHECK(object_.IsRooted());
-
-  if (dirty_rect.IsEmpty())
-    return LayoutRect();
-
-  if (object_.View()->GetDocument().Printing() &&
-      !RuntimeEnabledFeatures::PrintBrowserEnabled())
-    return LayoutRect();  // Don't invalidate paints if we're printing.
-
-  const LayoutBoxModelObject& paint_invalidation_container =
-      object_.ContainerForPaintInvalidation();
-  LayoutRect dirty_rect_on_backing = dirty_rect;
-  PaintLayer::MapRectToPaintInvalidationBacking(
-      object_, paint_invalidation_container, dirty_rect_on_backing);
-  dirty_rect_on_backing.Move(object_.ScrollAdjustmentForPaintInvalidation(
-      paint_invalidation_container));
-  // TODO(crbug.com/732612): Implement rectangle raster invalidation for SPv2.
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
-    InvalidatePaintUsingContainer(paint_invalidation_container,
-                                  dirty_rect_on_backing,
-                                  PaintInvalidationReason::kRectangle);
-  }
-  SlowSetPaintingLayerNeedsRepaint();
-  if (display_item_client) {
-    InvalidateDisplayItemClient(*display_item_client,
-                                PaintInvalidationReason::kRectangle);
-  } else {
-    object_.InvalidateDisplayItemClients(PaintInvalidationReason::kRectangle);
-  }
-
-  return dirty_rect_on_backing;
-}
-
 void ObjectPaintInvalidator::SlowSetPaintingLayerNeedsRepaint() {
   if (PaintLayer* painting_layer = object_.PaintingLayer())
     painting_layer->SetNeedsRepaint();
@@ -534,7 +498,7 @@
 }
 
 DISABLE_CFI_PERF
-void ObjectPaintInvalidatorWithContext::InvalidateSelectionIfNeeded(
+void ObjectPaintInvalidatorWithContext::InvalidateSelection(
     PaintInvalidationReason reason) {
   // Update selection rect when we are doing full invalidation with geometry
   // change (in case that the object is moved, composite status changed, etc.)
@@ -572,6 +536,32 @@
 }
 
 DISABLE_CFI_PERF
+void ObjectPaintInvalidatorWithContext::InvalidatePartialRect(
+    PaintInvalidationReason reason) {
+  if (IsImmediateFullPaintInvalidationReason(reason))
+    return;
+
+  auto rect = object_.PartialInvalidationRect();
+  if (rect.IsEmpty())
+    return;
+
+  if (reason == PaintInvalidationReason::kNone) {
+    context_.painting_layer->SetNeedsRepaint();
+    object_.InvalidateDisplayItemClients(PaintInvalidationReason::kRectangle);
+  }
+
+  // TODO(crbug.com/732612): Implement rectangle raster invalidation for SPv2.
+  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+    return;
+
+  context_.MapLocalRectToVisualRectInBacking(object_, rect);
+  if (rect.IsEmpty())
+    return;
+  InvalidatePaintRectangleWithContext(rect,
+                                      PaintInvalidationReason::kRectangle);
+}
+
+DISABLE_CFI_PERF
 PaintInvalidationReason
 ObjectPaintInvalidatorWithContext::InvalidatePaintWithComputedReason(
     PaintInvalidationReason reason) {
@@ -581,7 +571,9 @@
   // We need to invalidate the selection before checking for whether we are
   // doing a full invalidation.  This is because we need to update the previous
   // selection rect regardless.
-  InvalidateSelectionIfNeeded(reason);
+  InvalidateSelection(reason);
+
+  InvalidatePartialRect(reason);
 
   switch (reason) {
     case PaintInvalidationReason::kNone:
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.h b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.h
index c378560c..ac6029f 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.h
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintInvalidator.h
@@ -60,13 +60,6 @@
       const LayoutRect&,
       PaintInvalidationReason);
 
-  // Invalidate the paint of a specific subrectangle within a given object. The
-  // rect is in the object's coordinate space.  If a DisplayItemClient is
-  // specified, that client is invalidated rather than |m_object|.
-  // Returns the visual rect that was invalidated (i.e, invalidation in the
-  // space of the GraphicsLayer backing this LayoutObject).
-  LayoutRect InvalidatePaintRectangle(const LayoutRect&, DisplayItemClient*);
-
   void InvalidatePaintIncludingNonCompositingDescendants();
   void InvalidatePaintIncludingNonSelfPaintingLayerDescendants(
       const LayoutBoxModelObject& paint_invalidation_container);
@@ -109,7 +102,8 @@
                                            PaintInvalidationReason);
 
  private:
-  void InvalidateSelectionIfNeeded(PaintInvalidationReason);
+  void InvalidateSelection(PaintInvalidationReason);
+  void InvalidatePartialRect(PaintInvalidationReason);
   bool ParentFullyInvalidatedOnSameBacking();
 
   const PaintInvalidatorContext& context_;
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
index 9f04dd5..8b8095a 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -153,7 +153,6 @@
 void PaintInvalidatorContext::MapLocalRectToVisualRectInBacking(
     const LayoutObject& object,
     LayoutRect& rect) const {
-  DCHECK(NeedsVisualRectUpdate(object));
   rect = PaintInvalidator::MapLocalRectToVisualRectInBacking<LayoutRect,
                                                              LayoutPoint>(
       object, rect, *this);
@@ -162,6 +161,7 @@
 LayoutRect PaintInvalidator::ComputeVisualRectInBacking(
     const LayoutObject& object,
     const PaintInvalidatorContext& context) {
+  DCHECK(context.NeedsVisualRectUpdate(object));
   if (object.IsSVGChild()) {
     FloatRect local_rect = SVGLayoutSupport::LocalVisualRect(object);
     return MapLocalRectToVisualRectInBacking<FloatRect, FloatPoint>(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index aad4413..dc0bc26 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -265,7 +265,7 @@
     return result;
 
   Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
       RuntimeEnabledFeatures::RootLayerScrollingEnabled() &&
       paint_layer_.GetLayoutObject().IsLayoutView()) {
     const auto* local_border_box_properties = paint_layer_.GetLayoutObject()
@@ -524,7 +524,7 @@
   }
 
   Optional<ScopedPaintChunkProperties> content_scoped_paint_chunk_properties;
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
       !scoped_paint_chunk_properties.has_value()) {
     // If layoutObject() is a LayoutView and root layer scrolling is enabled,
     // the LayoutView's paint properties will already have been applied at
@@ -642,7 +642,7 @@
     const ClipRect& clip_rect,
     const PaintLayerFlags& paint_flags) {
   // Clipping will be applied by property nodes directly for SPv2.
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return false;
   return clip_rect.Rect() != local_painting_info.paint_dirty_rect ||
          (paint_flags & kPaintLayerPaintingAncestorClippingMaskPhase) ||
@@ -780,7 +780,7 @@
 
   for (const auto& fragment : layer_fragments) {
     Optional<LayerClipRecorder> clip_recorder;
-    if (parent_layer && !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (parent_layer && !RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       if (NeedsToClip(painting_info, fragment.background_rect, paint_flags)) {
         clip_recorder.emplace(
             context, *parent_layer, DisplayItem::kClipLayerParent,
@@ -935,7 +935,7 @@
     }
 
     Optional<ScrollRecorder> scroll_recorder;
-    if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+    if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
         !local_painting_info.scroll_offset_accumulation.IsZero()) {
       cull_rect.Move(local_painting_info.scroll_offset_accumulation);
       scroll_recorder.emplace(context, paint_layer_.GetLayoutObject(),
@@ -1010,7 +1010,7 @@
   LayoutRect new_cull_rect(clip_rect.Rect());
   Optional<ScrollRecorder> scroll_recorder;
   LayoutPoint paint_offset = -paint_layer_.LayoutBoxLocation();
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     paint_offset += paint_layer_.GetLayoutObject().PaintOffset();
     new_cull_rect.Move(painting_info.scroll_offset_accumulation);
   } else {
@@ -1182,7 +1182,7 @@
     cache_skipper.emplace(context);
 
   Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     const auto* object_paint_properties =
         paint_layer_.GetLayoutObject().FirstFragment()->PaintProperties();
     DCHECK(object_paint_properties && object_paint_properties->Mask());
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 1129f9d..fe1df83 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -24,6 +24,7 @@
 #include "core/paint/ObjectPaintProperties.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/SVGRootPainter.h"
+#include "core/paint/compositing/CompositedLayerMapping.h"
 #include "core/paint/compositing/CompositingReasonFinder.h"
 #include "platform/transforms/TransformationMatrix.h"
 #include "platform/wtf/PtrUtil.h"
@@ -854,6 +855,37 @@
   return false;
 }
 
+void PaintPropertyTreeBuilder::UpdateCompositedLayerStates(
+    const LayoutObject& object,
+    PaintPropertyTreeBuilderFragmentContext& context,
+    bool& force_subtree_update) {
+  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+         !RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+  if (!object.NeedsPaintPropertyUpdate() && !force_subtree_update)
+    return;
+
+  if (!object.HasLayer())
+    return;
+  CompositedLayerMapping* mapping =
+      ToLayoutBoxModelObject(object).Layer()->GetCompositedLayerMapping();
+  if (!mapping)
+    return;
+
+  LayoutPoint snapped_paint_offset =
+      context.current.paint_offset - mapping->SubpixelAccumulation();
+  DCHECK(snapped_paint_offset == RoundedIntPoint(snapped_paint_offset));
+
+  if (GraphicsLayer* main_layer = mapping->MainGraphicsLayer()) {
+    PropertyTreeState layer_state(context.current.transform,
+                                  context.current.clip, context.current_effect);
+    IntPoint layer_offset = RoundedIntPoint(snapped_paint_offset) +
+                            main_layer->OffsetFromLayoutObject();
+    main_layer->SetLayerState(std::move(layer_state), layer_offset);
+  }
+
+  // TODO(trchen): Complete for all drawable layers.
+}
+
 // TODO(trchen): Remove this once we bake the paint offset into frameRect.
 void PaintPropertyTreeBuilder::UpdateScrollbarPaintOffset(
     const LayoutObject& object,
@@ -1305,7 +1337,7 @@
   // CSS mask and clip-path comes with an implicit clip to the border box.
   // Currently only SPv2 generate and take advantage of those.
   const bool box_generates_property_nodes_for_mask_and_clip_path =
-      RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+      RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
       (box.HasMask() || box.HasClipPath());
   // The overflow clip paint property depends on the border box rect through
   // overflowClipRect(). The border box rect's size equals the frame rect's
@@ -1549,7 +1581,7 @@
                     full_context.force_subtree_update);
     UpdateCssClip(object, *properties, fragment_context,
                   full_context.force_subtree_update, full_context.clip_changed);
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       UpdateEffect(object, *properties, fragment_context,
                    full_context.force_subtree_update,
                    full_context.clip_changed);
@@ -1559,9 +1591,14 @@
   }
   UpdateLocalBorderBoxContext(object, fragment_context, fragment_data,
                               full_context.force_subtree_update);
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+      !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    UpdateCompositedLayerStates(object, fragment_context,
+                                full_context.force_subtree_update);
+  }
   if (fragment_data && fragment_data->PaintProperties()) {
     ObjectPaintProperties* properties = fragment_data->PaintProperties();
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       UpdateScrollbarPaintOffset(object, *properties, fragment_context,
                                  full_context.force_subtree_update);
     }
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
index edcc8a5..76561c3 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.h
@@ -228,6 +228,10 @@
       PaintPropertyTreeBuilderFragmentContext&,
       FragmentData*,
       bool& force_subtree_update);
+  ALWAYS_INLINE static void UpdateCompositedLayerStates(
+      const LayoutObject&,
+      PaintPropertyTreeBuilderFragmentContext&,
+      bool& force_subtree_update);
   ALWAYS_INLINE static void UpdateScrollbarPaintOffset(
       const LayoutObject&,
       ObjectPaintProperties&,
diff --git a/third_party/WebKit/Source/core/paint/README.md b/third_party/WebKit/Source/core/paint/README.md
index 0584db42a..641f09e 100644
--- a/third_party/WebKit/Source/core/paint/README.md
+++ b/third_party/WebKit/Source/core/paint/README.md
@@ -3,6 +3,7 @@
 This directory contains implementation of painters of layout objects. It covers
 the following document lifecycle phases:
 
+*   Layerization (`kInCompositingUpdate`, `kCompositingInputsClean` and `kCompositingClean`)
 *   PaintInvalidation (`InPaintInvalidation` and `PaintInvalidationClean`)
 *   PrePaint (`InPrePaint` and `PrePaintClean`)
 *   Paint (`InPaint` and `PaintClean`)
@@ -96,6 +97,194 @@
 *   Visual rect: the bounding box of all pixels that will be painted by a
     display item client.
 
+## Overview
+
+The primary responsibility of this module is to convert the outputs from layout
+(the `LayoutObject` tree) to the inputs of the compositor (the `cc::Layer` tree
+and associated display items).
+
+At the time of writing, there are three operation modes that are switched by
+`RuntimeEnabledFeatures`.
+
+### SlimmingPaintV1 (a.k.a. SPv1, SPv1.5, old-world compositing)
+
+This is the default operation mode. In this mode, layerization runs before
+pre-paint and paint. `PaintLayerCompositor` and `CompositedLayerMapping` use
+layout and style information to determine which subtrees of the `PaintLayer`
+tree should be pulled out to paint in its own layer, this is also known as
+'being composited'. Transforms, clips, and effects enclosing the subtree are
+applied as `GraphicsLayer` parameters.
+
+Then during pre-paint, a property tree is generated for fast calculating
+paint location and visual rects of each `LayoutObject` on their backing layer,
+for invalidation purposes.
+
+During paint, the paint function of each `GraphicsLayer` created by
+`CompositedLayerMapping` will be invoked, which then calls into the painter
+of each `PaintLayer` subtree. The painter then outputs a list of display
+items which may be drawing, or meta display items that represents non-composited
+transforms, clips and effects.
+
+  |
+  | from layout
+  v
++------------------------------+
+| LayoutObject/PaintLayer tree |
++------------------------------+
+  |
+  | PaintLayerCompositor::UpdateIfNeeded()
+  |   CompositingInputsUpdater::Update()
+  |   CompositingLayerAssigner::Assign()
+  |   GraphicsLayerUpdater::Update()
+  |   GraphicsLayerTreeBuilder::Rebuild()
+  v
++--------------------+
+| GraphicsLayer tree |
++--------------------+
+  |   |
+  |   | LocalFrameView::PaintTree()
+  |   |   LocalFrameView::PaintGraphicsLayerRecursively()
+  |   |     GraphicsLayer::Paint()
+  |   |       CompositedLayerMapping::PaintContents()
+  |   |         PaintLayerPainter::PaintLayerContents()
+  |   |           ObjectPainter::Paint()
+  |   v
+  | +-----------------+
+  | | DisplayItemList |
+  | +-----------------+
+  |   |
+  |   | WebContentLayer shim
+  v   v
++----------------+
+| cc::Layer tree |
++----------------+
+  |
+  | to compositor
+  v
+
+### SlimmingPaintV2 (a.k.a. SPv2)
+
+This is a new mode under development. In this mode, layerization runs after
+pre-paint and paint, and meta display items are abandoned in favor of property
+trees.
+
+The process starts with pre-paint to generate property trees. During paint,
+each generated display item will be associated with a property tree state.
+Adjacent display items having the same property tree state will be grouped as
+`PaintChunk`. The list of paint chunks then will be processed by
+`PaintArtifactCompositor` for layerization. Property nodes that will be
+composited are converted into cc property nodes, while non-composited property
+nodes are converted into meta display items by `PaintChunksToCcLayer`.
+
+  |
+  | from layout
+  v
++------------------------------+
+| LayoutObject/PaintLayer tree |
++------------------------------+
+  |     |
+  |     | PrePaintTreeWalk::Walk()
+  |     |   PaintPropertyTreeBuider::UpdatePropertiesForSelf()
+  |     v
+  |   +--------------------------------+
+  |<--|         Property trees         |
+  |   +--------------------------------+
+  |                                  |
+  | LocalFrameView::PaintTree()      |
+  |   FramePainter::Paint()          |
+  |     PaintLayerPainter::Paint()   |
+  |       ObjectPainter::Paint()     |
+  v                                  |
++---------------------------------+  |
+| DisplayItemList/PaintChunk list |  |
++---------------------------------+  |
+  |                                  |
+  |<---------------------------------+
+  | LocalFrameView::PushPaintArtifactToCompositor()
+  |   PaintArtifactCompositor::Update()
+  |
+  +---+---------------------------------+
+  |   v                                 |
+  | +----------------------+            |
+  | | Chunk list for layer |            |
+  | +----------------------+            |
+  |   |                                 |
+  |   | PaintChunksToCcLayer::Convert() |
+  v   v                                 v
++----------------+ +-----------------------+
+| cc::Layer list | |   cc property trees   |
++----------------+ +-----------------------+
+  |                  |
+  +------------------+
+  | to compositor
+  v
+
+### SlimmingPaintV175 (a.k.a. SPv1.75)
+
+This mode is for incrementally shipping completed features from SPv2. It is
+numbered 1.75 because invalidation using property trees was called SPv1.5,
+which is now a part of SPv1. SPv1.75 will again replace SPv1 once completed.
+
+SPv1.75 reuses layerization from SPv1, but will cherrypick property-tree-based
+paint from SPv2. Meta display items are abandoned in favor of property tree.
+Each drawable GraphicsLayer's layer state will be computed by the property tree
+builder. During paint, each display item will be associated with a property
+tree state. At the end of paint, meta display items will be generated from
+the state differences between the chunk and the layer.
+
+  |
+  | from layout
+  v
++------------------------------+
+| LayoutObject/PaintLayer tree |-----------+
++------------------------------+           |
+  |                                        |
+  | PaintLayerCompositor::UpdateIfNeeded() |
+  |   CompositingInputsUpdater::Update()   |
+  |   CompositingLayerAssigner::Assign()   |
+  |   GraphicsLayerUpdater::Update()       | PrePaintTreeWalk::Walk()
+  |   GraphicsLayerTreeBuilder::Rebuild()  |   PaintPropertyTreeBuider::UpdatePropertiesForSelf()
+  v                                        |
++--------------------+                   +------------------+
+| GraphicsLayer tree |<------------------|  Property trees  |
++--------------------+                   +------------------+
+  |   |                                    |              |
+  |   |<-----------------------------------+              |
+  |   | LocalFrameView::PaintTree()                       |
+  |   |   LocalFrameView::PaintGraphicsLayerRecursively() |
+  |   |     GraphicsLayer::Paint()                        |
+  |   |       CompositedLayerMapping::PaintContents()     |
+  |   |         PaintLayerPainter::PaintLayerContents()   |
+  |   |           ObjectPainter::Paint()                  |
+  |   v                                                   |
+  | +---------------------------------+                   |
+  | | DisplayItemList/PaintChunk list |                   |
+  | +---------------------------------+                   |
+  |   |                                                   |
+  |   |<--------------------------------------------------+
+  |   | PaintChunksToCcLayer::Convert()
+  |   |
+  |   | WebContentLayer shim
+  v   v
++----------------+
+| cc::Layer tree |
++----------------+
+  |
+  | to compositor
+  v
+
+### Comparison of the three modes
+
+                          | SPv1               | SPv175             | SPv2
+--------------------------+--------------------+--------------------+-------------
+REF::SPv175Enabled        | false              | true               | true
+REF::SPv2Enabled          | false              | false              | true
+Property tree             | without effects    | full               | full
+Paint chunks              | no                 | yes                | yes
+Layerization              | PLC/CLM            | PLC/CLM            | PAC
+Non-composited properties | meta items         | PC2CL              | PC2CL
+Raster invalidation       | LayoutObject-based | LayoutObject-based | chunk-based
+
 ## PaintInvalidation (Deprecated by [PrePaint](#PrePaint))
 
 Paint invalidation marks anything that need to be painted differently from the
diff --git a/third_party/WebKit/Source/core/paint/RarePaintData.h b/third_party/WebKit/Source/core/paint/RarePaintData.h
index 9f73951..3a3d8e50 100644
--- a/third_party/WebKit/Source/core/paint/RarePaintData.h
+++ b/third_party/WebKit/Source/core/paint/RarePaintData.h
@@ -47,6 +47,13 @@
     selection_visual_rect_ = r;
   }
 
+  LayoutRect PartialInvalidationRect() const {
+    return partial_invalidation_rect_;
+  }
+  void SetPartialInvalidationRect(const LayoutRect& r) {
+    partial_invalidation_rect_ = r;
+  }
+
  private:
   // The PaintLayer associated with this LayoutBoxModelObject. This can be null
   // depending on the return value of LayoutBoxModelObject::layerTypeRequired().
@@ -58,6 +65,7 @@
 
   LayoutPoint location_in_backing_;
   LayoutRect selection_visual_rect_;
+  LayoutRect partial_invalidation_rect_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
index 39876b9..aa9dd79 100644
--- a/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/RoundedInnerRectClipper.cpp
@@ -23,7 +23,8 @@
       clip_type_(use_paint_controller_
                      ? paint_info_.DisplayItemTypeForClipping()
                      : DisplayItem::kClipBoxPaintPhaseFirst) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && use_paint_controller_)
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+      use_paint_controller_)
     return;
 
   Vector<FloatRoundedRect> rounded_rect_clips;
@@ -83,7 +84,8 @@
 }
 
 RoundedInnerRectClipper::~RoundedInnerRectClipper() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() && use_paint_controller_)
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
+      use_paint_controller_)
     return;
 
   DisplayItem::Type end_type = DisplayItem::ClipTypeToEndClipType(clip_type_);
diff --git a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
index 8c4cfee6..2bb56a76 100644
--- a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
@@ -23,7 +23,7 @@
 
   // Content painted into a new PaintRecord in SPv2 will have an
   // independent property tree set.
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     paint_controller_->UpdateCurrentPaintChunkProperties(
         nullptr, PropertyTreeState::Root());
   }
diff --git a/third_party/WebKit/Source/core/paint/SVGMaskPainter.cpp b/third_party/WebKit/Source/core/paint/SVGMaskPainter.cpp
index 503be52..ba1faca 100644
--- a/third_party/WebKit/Source/core/paint/SVGMaskPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGMaskPainter.cpp
@@ -27,7 +27,7 @@
   if (visual_rect.IsEmpty() || !mask_.GetElement()->HasChildren())
     return false;
 
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     context.GetPaintController().CreateAndAppend<BeginCompositingDisplayItem>(
         object, SkBlendMode::kSrcOver, 1, &visual_rect);
   }
@@ -48,7 +48,7 @@
     CompositingRecorder mask_compositing(context, object, SkBlendMode::kDstIn,
                                          1, &visual_rect, mask_layer_filter);
     Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties;
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       DCHECK(object.FirstFragment());
       const auto* object_paint_properties =
           object.FirstFragment()->PaintProperties();
@@ -64,7 +64,7 @@
                             visual_rect);
   }
 
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     context.GetPaintController().EndItem<EndCompositingDisplayItem>(object);
 }
 
diff --git a/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp b/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp
index 398fb3e..a4496e3 100644
--- a/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGPaintContext.cpp
@@ -116,7 +116,7 @@
 }
 
 void SVGPaintContext::ApplyPaintPropertyState() {
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
 
   // SVGRoot works like normal CSS replaced element and its effects are
@@ -163,7 +163,7 @@
   ClipPathOperation* clip_path_operation = object_.StyleRef().ClipPath();
   if (!clip_path_operation)
     return;
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     clip_path_clipper_.emplace(GetPaintInfo().context, *clip_path_operation,
                                object_, object_.ObjectBoundingBox(),
                                FloatPoint());
diff --git a/third_party/WebKit/Source/core/paint/SVGPaintContext.h b/third_party/WebKit/Source/core/paint/SVGPaintContext.h
index 1906284..1bac4d2 100644
--- a/third_party/WebKit/Source/core/paint/SVGPaintContext.h
+++ b/third_party/WebKit/Source/core/paint/SVGPaintContext.h
@@ -54,7 +54,7 @@
                       const LayoutObject& object,
                       const AffineTransform& transform)
       : TransformRecorder(context, object, transform) {
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       const auto* fragment_data = object.FirstFragment();
       if (!fragment_data)
         return;
diff --git a/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp b/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp
index 64f5bc1..25c0759 100644
--- a/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/ScrollRecorder.cpp
@@ -15,7 +15,7 @@
                                DisplayItem::Type type,
                                const IntSize& current_offset)
     : client_(client), begin_item_type_(type), context_(context) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().CreateAndAppend<BeginScrollDisplayItem>(
       client_, begin_item_type_, current_offset);
@@ -31,7 +31,7 @@
                      current_offset) {}
 
 ScrollRecorder::~ScrollRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().EndItem<EndScrollDisplayItem>(
       client_, DisplayItem::ScrollTypeToEndScrollType(begin_item_type_));
diff --git a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
index 609b204..2343c2ef 100644
--- a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
@@ -178,7 +178,7 @@
 
   {
     Optional<ScopedPaintChunkProperties> scoped_transform_property;
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       if (auto* fragment_data = GetScrollableArea().Box().FirstFragment()) {
         const auto* object_properties = fragment_data->PaintProperties();
         if (object_properties && object_properties->ScrollbarPaintOffset()) {
diff --git a/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp b/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp
index 921f422..39f6f98 100644
--- a/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/Transform3DRecorder.cpp
@@ -16,7 +16,7 @@
                                          const TransformationMatrix& transform,
                                          const FloatPoint3D& transform_origin)
     : context_(context), client_(client), type_(type) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   DCHECK(DisplayItem::IsTransform3DType(type));
   skip_recording_for_identity_transform_ = transform.IsIdentity();
@@ -29,7 +29,7 @@
 }
 
 Transform3DRecorder::~Transform3DRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   if (skip_recording_for_identity_transform_)
     return;
diff --git a/third_party/WebKit/Source/core/paint/TransformRecorder.cpp b/third_party/WebKit/Source/core/paint/TransformRecorder.cpp
index 2ab9266..4d9cb05 100644
--- a/third_party/WebKit/Source/core/paint/TransformRecorder.cpp
+++ b/third_party/WebKit/Source/core/paint/TransformRecorder.cpp
@@ -14,7 +14,7 @@
                                      const DisplayItemClient& client,
                                      const AffineTransform& transform)
     : context_(context), client_(client) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   skip_recording_for_identity_transform_ = transform.IsIdentity();
 
@@ -26,7 +26,7 @@
 }
 
 TransformRecorder::~TransformRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   if (skip_recording_for_identity_transform_)
     return;
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
index 57cef37..f904c82 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
@@ -73,6 +73,7 @@
 #include "platform/graphics/CompositorMutableProperties.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/paint/ClipDisplayItem.h"
+#include "platform/graphics/paint/ClipRecorder.h"
 #include "platform/graphics/paint/CullRect.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
 #include "platform/graphics/paint/PaintController.h"
@@ -3143,14 +3144,11 @@
     // FIXME: Is it correct to clip to dirtyRect in slimming paint mode?
     // FIXME: Combine similar code here and LayerClipRecorder.
     dirty_rect.Intersect(paint_info.local_clip_rect_for_squashed_layer);
-    context.GetPaintController().CreateAndAppend<ClipDisplayItem>(
-        graphics_layer, DisplayItem::kClipLayerOverflowControls, dirty_rect);
-
+    ClipRecorder clip_recorder(context, graphics_layer,
+                               DisplayItem::kClipLayerOverflowControls,
+                               dirty_rect);
     PaintLayerPainter(*paint_info.paint_layer)
         .Paint(context, painting_info, paint_layer_flags);
-    context.GetPaintController().EndItem<EndClipDisplayItem>(
-        graphics_layer, DisplayItem::ClipTypeToEndClipType(
-                            DisplayItem::kClipLayerOverflowControls));
   }
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
index 63e131c..5205bd9 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -1019,7 +1019,7 @@
     this._filterByExecutionContextSetting.addChangeListener(this._filterChanged);
     this._filterByConsoleAPISetting.addChangeListener(this._filterChanged);
 
-    this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'), 0.2, 1, true);
+    this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'), 0.2, 1);
     this._textFilterUI.element.title = Common.UIString('e.g. /event\\d/ -cdn url:a.com');
     this._textFilterUI.addEventListener(UI.ToolbarInput.Event.TextChanged, this._textFilterChanged, this);
     this._filterParser = new TextUtils.FilterParser(Object.values(Console.ConsoleViewFilter._filterType));
diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js
index 78ef4f7..53e2930b 100644
--- a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js
+++ b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js
@@ -35,7 +35,7 @@
     this._textFilterRegExp = null;
 
     toolbar.appendSeparator();
-    this._filterInput = new UI.ToolbarInput(Common.UIString('URL filter'), 0.4, 1, true);
+    this._filterInput = new UI.ToolbarInput(Common.UIString('URL filter'), 0.4, 1);
     this._filterInput.setEnabled(false);
     this._filterInput.addEventListener(UI.ToolbarInput.Event.TextChanged, this._onFilterChanged, this);
     toolbar.appendToolbarItem(this._filterInput);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/ResourceWebSocketFrameView.js b/third_party/WebKit/Source/devtools/front_end/network/ResourceWebSocketFrameView.js
index a17aea8..3c33b203 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/ResourceWebSocketFrameView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/ResourceWebSocketFrameView.js
@@ -73,7 +73,7 @@
     this._filterType = null;
 
     var placeholder = 'Enter regex, for example: (web)?socket';
-    this._filterTextInput = new UI.ToolbarInput(Common.UIString(placeholder), 0.4, undefined, true);
+    this._filterTextInput = new UI.ToolbarInput(Common.UIString(placeholder), 0.4);
     this._filterTextInput.addEventListener(UI.ToolbarInput.Event.TextChanged, this._updateFilterSetting, this);
     this._mainToolbar.appendToolbarItem(this._filterTextInput);
     this._filterRegex = null;
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js
index 9692ac0..9bf6f5f 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/StorageItemsView.js
@@ -19,7 +19,7 @@
 
     this._mainToolbar = new UI.Toolbar('top-resources-toolbar', this.element);
 
-    this._filterItem = new UI.ToolbarInput(Common.UIString('Filter'), 0.4, undefined, true);
+    this._filterItem = new UI.ToolbarInput(Common.UIString('Filter'), 0.4);
     this._filterItem.addEventListener(UI.ToolbarInput.Event.TextChanged, this._filterChanged, this);
 
     var toolbarItems = [this._refreshButton, this._deleteAllButton, this._deleteSelectedButton, this._filterItem];
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
index 097c516..470f879 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -131,7 +131,7 @@
     this._threadSelector.setMaxWidth(230);
     this._currentThreadSetting = Common.settings.createSetting('timelineTreeCurrentThread', 0);
     toolbar.appendToolbarItem(this._threadSelector);
-    this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'), 0, 0, true);
+    this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'));
     this._textFilterUI.addEventListener(UI.ToolbarInput.Event.TextChanged, textFilterChanged, this);
     toolbar.appendToolbarItem(this._textFilterUI);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
index f3959ec..d503020 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -575,16 +575,14 @@
    * @param {string} placeholder
    * @param {number=} growFactor
    * @param {number=} shrinkFactor
-   * @param {boolean=} isSearchField
    */
-  constructor(placeholder, growFactor, shrinkFactor, isSearchField) {
+  constructor(placeholder, growFactor, shrinkFactor) {
     super(createElementWithClass('div', 'toolbar-input'));
 
     this.input = this.element.createChild('input');
     this.input.addEventListener('focus', () => this.element.classList.add('focused'));
     this.input.addEventListener('blur', () => this.element.classList.remove('focused'));
     this.input.addEventListener('input', () => this._onChangeCallback(), false);
-    this._isSearchField = !!isSearchField;
     if (growFactor)
       this.element.style.flexGrow = growFactor;
     if (shrinkFactor)
@@ -592,8 +590,10 @@
     if (placeholder)
       this.input.setAttribute('placeholder', placeholder);
 
-    if (isSearchField)
-      this._setupSearchControls();
+    var clearButton = this.element.createChild('div', 'toolbar-input-clear-button');
+    clearButton.appendChild(UI.Icon.create('mediumicon-gray-cross-hover', 'search-cancel-button'));
+    clearButton.addEventListener('click', () => this._internalSetValue('', true));
+    this.input.addEventListener('keydown', event => this._onKeydownCallback(event));
 
     this._updateEmptyStyles();
   }
@@ -606,13 +606,6 @@
     this.input.disabled = !enabled;
   }
 
-  _setupSearchControls() {
-    var clearButton = this.element.createChild('div', 'toolbar-input-clear-button');
-    clearButton.appendChild(UI.Icon.create('mediumicon-gray-cross-hover', 'search-cancel-button'));
-    clearButton.addEventListener('click', () => this._internalSetValue('', true));
-    this.input.addEventListener('keydown', event => this._onKeydownCallback(event));
-  }
-
   /**
    * @param {string} value
    */
@@ -642,7 +635,7 @@
    * @param {!Event} event
    */
   _onKeydownCallback(event) {
-    if (!this._isSearchField || !isEscKey(event) || !this.input.value)
+    if (!isEscKey(event) || !this.input.value)
       return;
     this._internalSetValue('', true);
     event.consume(true);
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index b1a57417..b087a9c 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -994,6 +994,10 @@
       name: "SlimmingPaintStrictCullRectClipping",
     },
     {
+      name: "SlimmingPaintV175",
+      implied_by: ["SlimmingPaintV2"],
+    },
+    {
       name: "SlimmingPaintV2",
     },
     {
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp
index 2ecfc44f..9688b5a 100644
--- a/third_party/WebKit/Source/platform/exported/Platform.cpp
+++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -123,10 +123,13 @@
 
   ProcessHeap::Init();
   MemoryCoordinator::Initialize();
-  if (base::ThreadTaskRunnerHandle::IsSet())
+  if (base::ThreadTaskRunnerHandle::IsSet()) {
+    base::trace_event::MemoryDumpProvider::Options options;
+    options.supports_heap_profiling = true;
     base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
         BlinkGCMemoryDumpProvider::Instance(), "BlinkGC",
-        base::ThreadTaskRunnerHandle::Get());
+        base::ThreadTaskRunnerHandle::Get(), options);
+  }
 
   ThreadState::AttachMainThread();
 
@@ -140,9 +143,11 @@
   if (g_platform->main_thread_) {
     DCHECK(!g_gc_task_runner);
     g_gc_task_runner = new GCTaskRunner(g_platform->main_thread_);
+    base::trace_event::MemoryDumpProvider::Options heap_profiling_options;
+    heap_profiling_options.supports_heap_profiling = true;
     base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
         PartitionAllocMemoryDumpProvider::Instance(), "PartitionAlloc",
-        base::ThreadTaskRunnerHandle::Get());
+        base::ThreadTaskRunnerHandle::Get(), heap_profiling_options);
     base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
         FontCacheMemoryDumpProvider::Instance(), "FontCaches",
         base::ThreadTaskRunnerHandle::Get());
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index f2ab221..127cb22 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -45,8 +45,10 @@
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/Image.h"
 #include "platform/graphics/LinkHighlight.h"
+#include "platform/graphics/compositing/PaintChunksToCcLayer.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
 #include "platform/graphics/paint/PaintController.h"
+#include "platform/graphics/paint/PropertyTreeState.h"
 #include "platform/graphics/paint/RasterInvalidationTracking.h"
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/json/JSONValues.h"
@@ -61,6 +63,7 @@
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebCompositorSupport.h"
+#include "public/platform/WebDisplayItemList.h"
 #include "public/platform/WebFloatPoint.h"
 #include "public/platform/WebFloatRect.h"
 #include "public/platform/WebLayer.h"
@@ -1249,6 +1252,17 @@
   return graphics_context.EndRecording();
 }
 
+void GraphicsLayer::SetLayerState(PropertyTreeState&& layer_state,
+                                  const IntPoint& layer_offset) {
+  if (!layer_state_) {
+    layer_state_ = base::MakeUnique<LayerState>(
+        LayerState{std::move(layer_state), layer_offset});
+    return;
+  }
+  layer_state_->state = std::move(layer_state);
+  layer_state_->offset = layer_offset;
+}
+
 void GraphicsLayer::PaintContents(WebDisplayItemList* web_display_item_list,
                                   PaintingControlSetting painting_control) {
   TRACE_EVENT0("blink,benchmark", "GraphicsLayer::PaintContents");
@@ -1283,8 +1297,25 @@
   if (painting_control != kPaintDefaultBehavior)
     Paint(nullptr, disabled_mode);
 
-  paint_controller.GetPaintArtifact().AppendToWebDisplayItemList(
-      OffsetFromLayoutObjectWithSubpixelAccumulation(), web_display_item_list);
+  if (layer_state_) {
+    DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
+
+    Vector<const PaintChunk*> all_chunks;
+    all_chunks.ReserveInitialCapacity(
+        paint_controller.GetPaintArtifact().PaintChunks().size());
+    for (const auto& chunk : paint_controller.GetPaintArtifact().PaintChunks())
+      all_chunks.push_back(&chunk);
+
+    PaintChunksToCcLayer::ConvertInto(
+        all_chunks, layer_state_->state,
+        gfx::Vector2dF(layer_state_->offset.X(), layer_state_->offset.Y()),
+        paint_controller.GetPaintArtifact().GetDisplayItemList(),
+        *web_display_item_list->GetCcDisplayItemList());
+  } else {
+    paint_controller.GetPaintArtifact().AppendToWebDisplayItemList(
+        OffsetFromLayoutObjectWithSubpixelAccumulation(),
+        web_display_item_list);
+  }
 
   paint_controller.SetDisplayItemConstructionIsDisabled(false);
   paint_controller.SetSubsequenceCachingIsDisabled(false);
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
index 0afce88..4cf223c 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -283,6 +283,8 @@
   void SetScrollBoundaryBehavior(const WebScrollBoundaryBehavior&);
   void SetIsResizedByBrowserControls(bool);
 
+  void SetLayerState(PropertyTreeState&&, const IntPoint& layer_offset);
+
  protected:
   String DebugName(cc::Layer*) const;
   bool ShouldFlattenTransform() const { return should_flatten_transform_; }
@@ -403,6 +405,12 @@
   mutable std::unique_ptr<PaintController> paint_controller_;
 
   IntRect previous_interest_rect_;
+
+  struct LayerState {
+    PropertyTreeState state;
+    IntPoint offset;
+  };
+  std::unique_ptr<LayerState> layer_state_;
 };
 
 // ObjectPaintInvalidatorWithContext::InvalidatePaintRectangleWithContext uses
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
index cae90ca..ebbf0e4b 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -356,6 +356,26 @@
 
 }  // unnamed namespace
 
+void PaintChunksToCcLayer::ConvertInto(
+    const Vector<const PaintChunk*>& paint_chunks,
+    const PropertyTreeState& layer_state,
+    const gfx::Vector2dF& layer_offset,
+    const DisplayItemList& display_items,
+    cc::DisplayItemList& cc_list) {
+  bool need_translate = !layer_offset.IsZero();
+  if (need_translate) {
+    cc_list.StartPaint();
+    cc_list.push<cc::SaveOp>();
+    cc_list.push<cc::TranslateOp>(-layer_offset.x(), -layer_offset.y());
+    cc_list.EndPaintOfPairedBegin();
+  }
+
+  ConversionContext(layer_state, cc_list).Convert(paint_chunks, display_items);
+
+  if (need_translate)
+    AppendRestore(cc_list, 1);
+}
+
 scoped_refptr<cc::DisplayItemList> PaintChunksToCcLayer::Convert(
     const Vector<const PaintChunk*>& paint_chunks,
     const PropertyTreeState& layer_state,
@@ -364,18 +384,7 @@
     cc::DisplayItemList::UsageHint hint,
     RasterUnderInvalidationCheckingParams* under_invalidation_checking_params) {
   auto cc_list = base::MakeRefCounted<cc::DisplayItemList>(hint);
-  bool need_translate = !layer_offset.IsZero();
-  if (need_translate) {
-    cc_list->StartPaint();
-    cc_list->push<cc::SaveOp>();
-    cc_list->push<cc::TranslateOp>(-layer_offset.x(), -layer_offset.y());
-    cc_list->EndPaintOfPairedBegin();
-  }
-
-  ConversionContext(layer_state, *cc_list).Convert(paint_chunks, display_items);
-
-  if (need_translate)
-    AppendRestore(*cc_list, 1);
+  ConvertInto(paint_chunks, layer_state, layer_offset, display_items, *cc_list);
 
   if (under_invalidation_checking_params) {
     auto& params = *under_invalidation_checking_params;
@@ -383,9 +392,10 @@
     recorder.beginRecording(params.interest_rect);
     // Create a complete cloned list for under-invalidation checking. We can't
     // use cc_list because it is not finalized yet.
-    auto list_clone =
-        Convert(paint_chunks, layer_state, layer_offset, display_items,
-                cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
+    auto list_clone = base::MakeRefCounted<cc::DisplayItemList>(
+        cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
+    ConvertInto(paint_chunks, layer_state, layer_offset, display_items,
+                *list_clone);
     recorder.getRecordingCanvas()->drawPicture(list_clone->ReleaseAsRecord());
     params.tracking.CheckUnderInvalidations(params.debug_name,
                                             recorder.finishRecordingAsPicture(),
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h
index 37324be..ec6834bb 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.h
@@ -42,6 +42,26 @@
 
 class PLATFORM_EXPORT PaintChunksToCcLayer {
  public:
+  // Converts a list of Blink paint chunks and display items into cc display
+  // items, inserting appropriate begin/end items with respect to property
+  // tree state. The converted items are appended into a unfinalized cc display
+  // item list.
+  // |layer_state| is the target property tree state of the output. This method
+  // generates begin/end items for the relative state differences between the
+  // layer state and the chunk state.
+  // |layer_offset| is an extra translation on top of layer_state.Transform(),
+  // in other word, point (x, y) in the output list maps to
+  // layer_state.Transform() * (layer_offset + (x, y)) on the screen. It is
+  // equivalent to say that |layer_offset| is the layer origin in the space
+  // of layer_state.Transform().
+  static void ConvertInto(const Vector<const PaintChunk*>&,
+                          const PropertyTreeState& layer_state,
+                          const gfx::Vector2dF& layer_offset,
+                          const DisplayItemList&,
+                          cc::DisplayItemList&);
+
+  // Similar to ConvertInto(), but returns a finalized new list instead of
+  // appending converted items to an existing list.
   static scoped_refptr<cc::DisplayItemList> Convert(
       const Vector<const PaintChunk*>&,
       const PropertyTreeState& layer_state,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp
index 7d524b4a..a3ab8a45 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPathRecorder.cpp
@@ -14,14 +14,14 @@
                                    const DisplayItemClient& client,
                                    const Path& clip_path)
     : context_(context), client_(client) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().CreateAndAppend<BeginClipPathDisplayItem>(
       client_, clip_path);
 }
 
 ClipPathRecorder::~ClipPathRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().EndItem<EndClipPathDisplayItem>(client_);
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp
index f682aa7..30950e0 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipRecorder.cpp
@@ -15,14 +15,14 @@
                            DisplayItem::Type type,
                            const IntRect& clip_rect)
     : client_(client), context_(context), type_(type) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().CreateAndAppend<ClipDisplayItem>(client_, type,
                                                                  clip_rect);
 }
 
 ClipRecorder::~ClipRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   context_.GetPaintController().EndItem<EndClipDisplayItem>(
       client_, DisplayItem::ClipTypeToEndClipType(type_));
diff --git a/third_party/WebKit/Source/platform/graphics/paint/CompositingRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/CompositingRecorder.cpp
index c99e518..9d1422c 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/CompositingRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/CompositingRecorder.cpp
@@ -19,7 +19,7 @@
                                          const FloatRect* bounds,
                                          ColorFilter color_filter)
     : client_(client), graphics_context_(graphics_context) {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   graphics_context.GetPaintController()
       .CreateAndAppend<BeginCompositingDisplayItem>(client_, xfer_mode, opacity,
@@ -27,7 +27,7 @@
 }
 
 CompositingRecorder::~CompositingRecorder() {
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
     return;
   graphics_context_.GetPaintController().EndItem<EndCompositingDisplayItem>(
       client_);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
index 3cbb94c1..ea9b8333 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItem.h
@@ -389,7 +389,7 @@
                          Type type,
                          size_t derived_size)
       : DisplayItem(client, type, derived_size) {
-    DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+    DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
   }
 
  private:
@@ -402,7 +402,7 @@
                        Type type,
                        size_t derived_size)
       : DisplayItem(client, type, derived_size) {
-    DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+    DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
   }
 
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
index a5ff791..4be7480 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
@@ -52,7 +52,8 @@
                              Vector<PaintChunk> paint_chunks)
     : display_item_list_(std::move(display_items)),
       paint_chunks_(std::move(paint_chunks)) {
-  ComputeChunkBoundsAndOpaqueness(display_item_list_, paint_chunks_);
+  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
+    ComputeChunkBoundsAndOpaqueness(display_item_list_, paint_chunks_);
 }
 
 PaintArtifact::PaintArtifact(PaintArtifact&& source)
@@ -80,7 +81,7 @@
 void PaintArtifact::Replay(const FloatRect& bounds,
                            GraphicsContext& graphics_context) const {
   TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay");
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     for (const DisplayItem& display_item : display_item_list_)
       display_item.Replay(graphics_context);
   } else {
@@ -92,7 +93,7 @@
                            PaintCanvas& canvas,
                            const PropertyTreeState& replay_state) const {
   TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay");
-  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
   Vector<const PaintChunk*> pointer_paint_chunks;
   pointer_paint_chunks.ReserveInitialCapacity(PaintChunks().size());
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp
index a80b47d..ef04c25 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintChunker.cpp
@@ -15,7 +15,7 @@
 void PaintChunker::UpdateCurrentPaintChunkProperties(
     const PaintChunk::Id* chunk_id,
     const PaintChunkProperties& properties) {
-  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
 
   current_chunk_id_ = WTF::nullopt;
   if (chunk_id)
@@ -24,16 +24,20 @@
 }
 
 bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) {
-  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+  DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
 
 #if DCHECK_IS_ON()
   // Property nodes should never be null because they should either be set to
   // properties created by a LayoutObject/FrameView, or be set to a non-null
   // root node. If these DCHECKs are hit we are missing a call to update the
   // properties. See: ScopedPaintChunkProperties.
-  DCHECK(current_properties_.property_tree_state.Transform());
-  DCHECK(current_properties_.property_tree_state.Clip());
-  DCHECK(current_properties_.property_tree_state.Effect());
+  // TODO(trchen): Enable this check for SPv175 too. Some drawable layers
+  // don't paint with property tree yet, e.g. scrollbar layers.
+  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    DCHECK(current_properties_.property_tree_state.Transform());
+    DCHECK(current_properties_.property_tree_state.Clip());
+    DCHECK(current_properties_.property_tree_state.Effect());
+  }
 #endif
 
   bool item_forces_new_chunk = item.IsForeignLayer() || item.IsScrollHitTest();
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index bbfdaa2..58edcae 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -210,7 +210,7 @@
 }
 
 bool PaintController::LastDisplayItemIsNoopBegin() const {
-  DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+  DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
 
   if (new_display_item_list_.IsEmpty())
     return false;
@@ -225,7 +225,7 @@
 }
 
 void PaintController::RemoveLastDisplayItem() {
-  DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+  DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
 
   if (new_display_item_list_.IsEmpty())
     return;
@@ -271,19 +271,22 @@
         &display_item.Client(), display_item.Client().DebugName());
   }
 
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     size_t last_chunk_index = new_paint_chunks_.LastChunkIndex();
-    if (new_paint_chunks_.IncrementDisplayItemIndex(display_item)) {
-      DCHECK(last_chunk_index != new_paint_chunks_.LastChunkIndex());
-      if (last_chunk_index != kNotFound) {
+    bool chunk_added =
+        new_paint_chunks_.IncrementDisplayItemIndex(display_item);
+
+    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+      if (chunk_added && last_chunk_index != kNotFound) {
+        DCHECK(last_chunk_index != new_paint_chunks_.LastChunkIndex());
         GenerateRasterInvalidations(
             new_paint_chunks_.PaintChunkAt(last_chunk_index));
       }
-    }
 
-    new_paint_chunks_.LastChunk().outset_for_raster_effects =
-        std::max(new_paint_chunks_.LastChunk().outset_for_raster_effects,
-                 display_item.OutsetForRasterEffects().ToFloat());
+      new_paint_chunks_.LastChunk().outset_for_raster_effects =
+          std::max(new_paint_chunks_.LastChunk().outset_for_raster_effects,
+                   display_item.OutsetForRasterEffects().ToFloat());
+    }
   }
 
 #if DCHECK_IS_ON()
@@ -496,7 +499,7 @@
 
   Vector<PaintChunk>::const_iterator cached_chunk;
   PaintChunkProperties properties_before_subsequence;
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     cached_chunk =
         current_paint_artifact_.FindChunkByDisplayItemIndex(begin_index);
     DCHECK(cached_chunk != current_paint_artifact_.PaintChunks().end());
@@ -523,7 +526,7 @@
     DCHECK(cached_item->Client().IsAlive());
 #endif
 
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
         current_index == cached_chunk->end_index) {
       ++cached_chunk;
       DCHECK(cached_chunk != current_paint_artifact_.PaintChunks().end());
@@ -546,7 +549,7 @@
 #endif
 
     ProcessNewItem(MoveItemFromCurrentListToNewList(current_index));
-    if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
       DCHECK((!new_paint_chunks_.LastChunk().is_cacheable &&
               !cached_chunk->is_cacheable) ||
              new_paint_chunks_.LastChunk().Matches(*cached_chunk));
@@ -556,7 +559,7 @@
   if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) {
     under_invalidation_checking_end_ = end_index;
     DCHECK(IsCheckingUnderInvalidation());
-  } else if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  } else if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     // Restore properties and force new chunk for any trailing display items
     // after the cached subsequence without new properties.
     new_paint_chunks_.ForceNewChunk();
@@ -628,7 +631,7 @@
   out_of_order_chunk_indices_.clear();
   items_moved_into_new_list_.clear();
 
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     for (const auto& chunk : current_paint_artifact_.PaintChunks()) {
       if (chunk.id.client.IsJustCreated())
         chunk.id.client.ClearIsJustCreated();
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index 78ad5e9..44281f8 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -102,7 +102,7 @@
   // item construction is disabled, no list mutations will be performed.
   template <typename DisplayItemClass, typename... Args>
   void EndItem(Args&&... args) {
-    DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV2Enabled());
+    DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled());
 
     if (DisplayItemConstructionIsDisabled())
       return;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp
index 419994c..d71c335 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerDebugData.cpp
@@ -74,8 +74,8 @@
 
   json_object->SetString("subsequence", ClientName(*subsequence.client));
   json_object->SetArray(
-      RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ? "chunks"
-                                                       : "displayItems",
+      RuntimeEnabledFeatures::SlimmingPaintV175Enabled() ? "chunks"
+                                                         : "displayItems",
       SubsequenceAsJSONArrayRecursive(subsequence.start, subsequence.end));
 
   return json_object;
@@ -112,7 +112,7 @@
     JSONArray& json_array) {
   DCHECK(end_item > start_item);
 
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     list_.AppendSubsequenceAsJSON(start_item, end_item, flags_, json_array);
     return;
   }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintRecordBuilder.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintRecordBuilder.cpp
index 0022d60..be7879d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintRecordBuilder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintRecordBuilder.cpp
@@ -28,7 +28,7 @@
     paint_controller_ = paint_controller_ptr_.get();
   }
 
-  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     paint_controller_->UpdateCurrentPaintChunkProperties(
         nullptr, PropertyTreeState::Root());
   }
@@ -67,7 +67,7 @@
 void PaintRecordBuilder::EndRecording(
     PaintCanvas& canvas,
     const PropertyTreeState& property_tree_state) {
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+  if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) {
     canvas.drawPicture(EndRecording());
   } else {
     paint_controller_->CommitNewDisplayItems();
diff --git a/third_party/WebKit/public/platform/WebDisplayItemList.h b/third_party/WebKit/public/platform/WebDisplayItemList.h
index 3f89349..ea38263 100644
--- a/third_party/WebKit/public/platform/WebDisplayItemList.h
+++ b/third_party/WebKit/public/platform/WebDisplayItemList.h
@@ -23,6 +23,7 @@
 class SkRRect;
 
 namespace cc {
+class DisplayItemList;
 class FilterOperations;
 }
 
@@ -68,6 +69,8 @@
   virtual void AppendScrollItem(const WebSize& scroll_offset,
                                 ScrollContainerId) {}
   virtual void AppendEndScrollItem() {}
+
+  virtual cc::DisplayItemList* GetCcDisplayItemList() { return nullptr; }
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/input_host.mojom b/third_party/WebKit/public/platform/input_host.mojom
index 7a4ae78..acb97af 100644
--- a/third_party/WebKit/public/platform/input_host.mojom
+++ b/third_party/WebKit/public/platform/input_host.mojom
@@ -8,7 +8,29 @@
   string suggestion;
 };
 
+struct TextSuggestion {
+  int32 marker_tag;
+  // This index is used by browser code as an opaque identifier to send back to
+  // the renderer. It is not possible for the renderer to use it to cause an
+  // out-of-bounds error in the browser.
+  int32 suggestion_index;
+  string prefix;
+  string suggestion;
+  string suffix;
+};
+
+// This interface runs in the browser. Blink editing code calls it to tell it
+// when to display a spell check or text suggestion menu.
 interface TextSuggestionHost {
-  StartSpellCheckMenuTimer();
-  ShowSpellCheckSuggestionMenu(double caret_x, double caret_y, string marked_text, array<SpellCheckSuggestion> suggestions);
+  StartSuggestionMenuTimer();
+  ShowSpellCheckSuggestionMenu(
+    double caret_x,
+    double caret_y,
+    string marked_text,
+    array<SpellCheckSuggestion> suggestions);
+  ShowTextSuggestionMenu(
+    double caret_x,
+    double caret_y,
+    string marked_text,
+    array<TextSuggestion> suggestions);
 };
diff --git a/third_party/WebKit/public/platform/input_messages.mojom b/third_party/WebKit/public/platform/input_messages.mojom
index 54c3fe8..00cbb06 100644
--- a/third_party/WebKit/public/platform/input_messages.mojom
+++ b/third_party/WebKit/public/platform/input_messages.mojom
@@ -4,10 +4,14 @@
 
 module blink.mojom;
 
+// This interface is implemented in blink by TextSuggestionBackendImpl. It is
+// called by browser code on Android implementing the spell check/text
+// suggestion menu.
 interface TextSuggestionBackend {
   ApplySpellCheckSuggestion(string suggestion);
+  ApplyTextSuggestion(int32 marker_tag, int32 suggestion_index);
   DeleteActiveSuggestionRange();
-  NewWordAddedToDictionary(string suggestion);
-  SpellCheckMenuTimeoutCallback();
-  SuggestionMenuClosed();
+  OnNewWordAddedToDictionary(string suggestion);
+  OnSuggestionMenuClosed();
+  SuggestionMenuTimeoutCallback(int32 max_number_of_suggestions);
 };
diff --git a/third_party/blink/tools/move_blink_source.py b/third_party/blink/tools/move_blink_source.py
index 4b9640e..1f96731 100755
--- a/third_party/blink/tools/move_blink_source.py
+++ b/third_party/blink/tools/move_blink_source.py
@@ -51,6 +51,7 @@
     DEPS = 4
     MOJOM = 5
     TYPEMAP = 6
+    BLINK_BUILD_PY = 7
 
     @staticmethod
     def detect(path):
@@ -63,6 +64,8 @@
             return FileType.MOJOM
         if basename.endswith('.typemap'):
             return FileType.TYPEMAP
+        if basename.endswith('.py') and 'third_party/WebKit/Source/build' in path.replace('\\', '/'):
+            return FileType.BLINK_BUILD_PY
         if basename.endswith(('.gn', '.gni')):
             path = path.replace('\\', '/')
             if 'third_party/WebKit' in path or 'third_party/blink' in path:
@@ -102,9 +105,6 @@
         self._append_unless_upper_dir_exists(dirs, self._fs.join(self._repo_root, 'third_party', 'WebKit', 'public'))
         self._update_cpp_includes_in_directories(dirs)
 
-        # TODO(tkent): Update basenames in generated files;
-        # bindings/scripts/*.py, build/scripts/*.py.
-
         # Content update for individual files
         self._update_single_file_content('third_party/WebKit/Source/config.gni',
                                          [('snake_case_source_files = false',
@@ -207,6 +207,12 @@
         content = content.replace('//third_party/WebKit/public', '//third_party/blink/renderer/public')
         return self._update_basename(content)
 
+    def _update_blink_build_py(self, content):
+        # We don't prepend 'third_party/blink/renderer/' to matched basenames
+        # because it won't affect build and manual update after the great mv is
+        # enough.
+        return self._update_basename(content)
+
     def _update_basename(self, content):
         return self._basename_re.sub(lambda match: self._basename_map[match.group(1)], content)
 
@@ -221,7 +227,7 @@
         dirs.append(new_dir)
 
     def _update_file_content(self):
-        _log.info('Find *.gn, *.mojom, *.typemap, DEPS, and OWNERS ...')
+        _log.info('Find *.gn, *.mojom, *.py, *.typemap, DEPS, and OWNERS ...')
         files = self._fs.files_under(
             self._repo_root, dirs_to_skip=['.git', 'out'], file_filter=self._filter_file)
         _log.info('Scan contents of %d files ...', len(files))
@@ -242,6 +248,8 @@
                 content = self._update_mojom(content)
             elif file_type == FileType.TYPEMAP:
                 content = self._update_typemap(content)
+            elif file_type == FileType.BLINK_BUILD_PY:
+                content = self._update_blink_build_py(content)
 
             if original_content == content:
                 continue
diff --git a/third_party/closure_compiler/externs/networking_private.js b/third_party/closure_compiler/externs/networking_private.js
index 4e63c9e..0cc93886 100644
--- a/third_party/closure_compiler/externs/networking_private.js
+++ b/third_party/closure_compiler/externs/networking_private.js
@@ -1202,9 +1202,12 @@
  * list returned by $(ref:getVisibleNetworks). This is only a request: the
  * network subsystem can choose to ignore it.  If the list is updated, then the
  * $(ref:onNetworkListChanged) event will be fired.
+ * @param {!chrome.networkingPrivate.NetworkType=} networkType If provided,
+ *     requests a scan specific to the type.     For Cellular a mobile network
+ *     scan will be requested if supported.
  * @see https://developer.chrome.com/extensions/networkingPrivate#method-requestNetworkScan
  */
-chrome.networkingPrivate.requestNetworkScan = function() {};
+chrome.networkingPrivate.requestNetworkScan = function(networkType) {};
 
 /**
  * Starts a connection to the network with networkGuid.
@@ -1349,6 +1352,19 @@
 chrome.networkingPrivate.setCellularSimState = function(networkGuid, simState, callback) {};
 
 /**
+ * Selects whic Cellular Mobile Network to use. |networkId| must be the
+ * NetworkId property of a member of Cellular.FoundNetworks for the network
+ * properties for the specified Cellular network.
+ * @param {string} networkGuid The GUID of the cellular network to select the
+ *     network     for. If empty, the default cellular device will be used.
+ * @param {string} networkId The networkId to select.
+ * @param {function():void=} callback Called when the operation has completed.
+ * @see https://developer.chrome.com/extensions/networkingPrivate#method-selectCellularMobileNetwork
+ */
+chrome.networkingPrivate.selectCellularMobileNetwork = function(
+    networkGuid, networkId, callback) {};
+
+/**
  * Gets the global policy properties. These properties are not expected to
  * change during a session.
  * @param {function(!chrome.networkingPrivate.GlobalPolicy):void} callback
diff --git a/third_party/closure_compiler/interfaces/networking_private_interface.js b/third_party/closure_compiler/interfaces/networking_private_interface.js
index 8d4e42b..3b243b3 100644
--- a/third_party/closure_compiler/interfaces/networking_private_interface.js
+++ b/third_party/closure_compiler/interfaces/networking_private_interface.js
@@ -132,6 +132,9 @@
    * list returned by $(ref:getVisibleNetworks). This is only a request: the
    * network subsystem can choose to ignore it.  If the list is updated, then
    * the $(ref:onNetworkListChanged) event will be fired.
+   * @param {!chrome.networkingPrivate.NetworkType=} networkType If provided,
+   *     requests a scan specific to the type.     For Cellular a mobile network
+   *     scan will be requested if supported.
    * @see https://developer.chrome.com/extensions/networkingPrivate#method-requestNetworkScan
    */
   requestNetworkScan: assertNotReached,
@@ -214,6 +217,18 @@
   setCellularSimState: assertNotReached,
 
   /**
+   * Selects which Cellular Mobile Network to use. |networkId| must be the
+   * NetworkId property of a member of Cellular.FoundNetworks from the network
+   * properties for the specified Cellular network.
+   * @param {string} networkGuid The GUID of the cellular network to select the
+   *     network     for. If empty, the default cellular device will be used.
+   * @param {string} networkId The networkId to select.
+   * @param {function():void=} callback Called when the operation has completed.
+   * @see https://developer.chrome.com/extensions/networkingPrivate#method-selectCellularMobileNetwork
+   */
+  selectCellularMobileNetwork: assertNotReached,
+
+  /**
    * Gets the global policy properties. These properties are not expected to
    * change during a session.
    * @param {function(!chrome.networkingPrivate.GlobalPolicy):void} callback
@@ -262,7 +277,7 @@
 NetworkingPrivate.prototype.onPortalDetectionCompleted;
 
 /**
- * Fired when any certificate list has changed..
+ * Fired when any certificate list has changed.
  * @type {!ChromeEvent}
  * @see https://developer.chrome.com/extensions/networkingPrivate#event-onCertificateListsChanged
  */
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9e410f9..8bd2614a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -13477,6 +13477,7 @@
   <int value="1190" label="FILEMANAGERPRIVATE_RENAMEVOLUME"/>
   <int value="1191" label="AUTOTESTPRIVATE_SETMOUSEREVERSESCROLL"/>
   <int value="1192" label="METRICSPRIVATE_RECORDSPARSEHASHABLE"/>
+  <int value="1193" label="NETWORKINGPRIVATE_SELECTCELLULARMOBILENETWORK"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -39362,6 +39363,7 @@
   <int value="20" label="DolbyVision profile4"/>
   <int value="21" label="DolbyVision profile5"/>
   <int value="22" label="DolbyVision profile7"/>
+  <int value="23" label="Theora"/>
 </enum>
 
 <enum name="VideoDecodeAcceleratorError">
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py
index e991e33..279d861c 100644
--- a/tools/perf/benchmarks/rasterize_and_record_micro.py
+++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -60,7 +60,9 @@
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
-        pass # Nothing disabled.
+        self.DisableStory(
+            'file://static_top_25/wikipedia.html', [story.expectations.ALL],
+            'crbug.com/764543')
     return StoryExpectations()
 
 
diff --git a/tools/perf/benchmarks/service_worker.py b/tools/perf/benchmarks/service_worker.py
index 366f666..f9530e36 100644
--- a/tools/perf/benchmarks/service_worker.py
+++ b/tools/perf/benchmarks/service_worker.py
@@ -178,9 +178,8 @@
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
-        self.DisableStory('first_load',
-                          [story.expectations.ALL_ANDROID],
-                          'crbug.com/736518, crbug.com/763153')
+        self.DisableBenchmark([story.expectations.ALL],
+                              'crbug.com/736518, crbug.com/763153')
     return StoryExpectations()
 
 
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 5a688491..e4d70f9 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -606,10 +606,22 @@
   return result
 
 
-BENCHMARKS_TO_UPLOAD_TO_FLAKINESS_DASHBOARD = ['system_health.common_desktop',
-                                               'system_health.common_mobile',
-                                               'system_health.memory_desktop',
-                                               'system_health.memory_mobile']
+# Manually curated for now. System health is in here because it's an important
+# benchmark. Others are semi randomly chosen; they've failed on the waterfall
+# recently, so should be useful to upload.
+BENCHMARKS_TO_UPLOAD_TO_FLAKINESS_DASHBOARD = [
+    'service_worker.service_worker',
+    'smoothness.tough_texture_upload_cases',
+    'smoothness.tough_webgl_ad_cases',
+    'system_health.common_desktop',
+    'system_health.common_mobile',
+    'system_health.memory_desktop',
+    'system_health.memory_mobile',
+    'v8.browsing_mobile',
+    'v8.browsing_desktop',
+    'v8.runtimestats.browsing_mobile',
+    'v8.runtimestats.browsing_desktop',
+]
 
 
 BENCHMARKS_TO_OUTPUT_HISTOGRAMS = []
diff --git a/tools/v8_context_snapshot/BUILD.gn b/tools/v8_context_snapshot/BUILD.gn
index 12f80524..b1b35724 100644
--- a/tools/v8_context_snapshot/BUILD.gn
+++ b/tools/v8_context_snapshot/BUILD.gn
@@ -10,6 +10,7 @@
 import("//build/config/c++/c++.gni")
 import("//build/config/chromecast_build.gni")
 import("//build/config/compiler/compiler.gni")
+import("//build/config/v8_target_cpu.gni")
 import("//v8/snapshot_toolchain.gni")
 
 if (is_android) {
@@ -17,7 +18,9 @@
 }
 
 declare_args() {
-  use_v8_context_snapshot = !is_chromeos && !is_android && !is_chromecast
+  # TODO(crbug.com/764576): Enable the feature on more environments.
+  use_v8_context_snapshot = !is_chromeos && !is_android && !is_chromecast &&
+                            v8_target_cpu == target_cpu
 }
 
 if (is_android) {
diff --git a/tools/win/DebugVisualizers/webkit.natvis b/tools/win/DebugVisualizers/webkit.natvis
index 8180fc7..6001763b 100644
--- a/tools/win/DebugVisualizers/webkit.natvis
+++ b/tools/win/DebugVisualizers/webkit.natvis
@@ -34,7 +34,7 @@
       <Item Name="Length">length_</Item>
       <Item Name="Hash">hash_</Item>
       <Item Name="AsciiText" Condition="is8_bit_">(this+1),[length_]s</Item>
-      <Item Name="UnicodeText" Condition="!is8_bit_">(this+1),[length_]su</Item>
+      <Item Name="UnicodeText" Condition="!is8_bit_">(wchar_t*)(this+1),[length_]su</Item>
     </Expand>
   </Type>
   <Type Name="WTF::AtomicString">
@@ -211,14 +211,12 @@
   </Type>
   <!-- Layout: LayoutNG -->
   <Type Name="blink::NGBlockNode">
-    <DisplayString>{layout_box_}</DisplayString>
+    <DisplayString>{*box_}</DisplayString>
   </Type>
   <Type Name="blink::NGInlineNode">
-    <DisplayString>{*start_inline_}</DisplayString>
+    <DisplayString>{*box_}</DisplayString>
     <Expand>
-      <Item Name="inline_node_data">*block_->ng_inline_node_data_</Item>
-      <Item Name="text_content">block_->ng_inline_node_data_->text_content_</Item>
-      <Item Name="items">block_->ng_inline_node_data_->items_</Item>
+      <Item Name="inline_node_data">*((blink::LayoutNGBlockFlow*)box_)->ng_inline_node_data_</Item>
     </Expand>
   </Type>
   <Type Name="blink::NGInlineItem">
@@ -276,6 +274,6 @@
     <DisplayString>{platform_data_}</DisplayString>
   </Type>
   <Type Name="blink::FontPlatformData">
-    <DisplayString>{*typeface_.ptr_}, {text_size_}px</DisplayString>
+    <DisplayString>{*typeface_.fPtr}, {text_size_}px</DisplayString>
   </Type>
 </AutoVisualizer>
\ No newline at end of file
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index 6ad16377..967d73f 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -431,10 +431,8 @@
 
 // static
 bool ViewAndroid::SendDragEventToClient(ViewClient* client,
-                                        const DragEventAndroid& event,
-                                        const gfx::PointF& point) {
-  std::unique_ptr<DragEventAndroid> e = event.CreateFor(point);
-  return client->OnDragEvent(*e);
+                                        const DragEventAndroid& event) {
+  return client->OnDragEvent(event);
 }
 
 bool ViewAndroid::OnTouchEvent(const MotionEventAndroid& event) {
@@ -444,10 +442,8 @@
 
 // static
 bool ViewAndroid::SendTouchEventToClient(ViewClient* client,
-                                         const MotionEventAndroid& event,
-                                         const gfx::PointF& point) {
-  std::unique_ptr<MotionEventAndroid> e(event.CreateFor(point));
-  return client->OnTouchEvent(*e);
+                                         const MotionEventAndroid& event) {
+  return client->OnTouchEvent(event);
 }
 
 bool ViewAndroid::OnMouseEvent(const MotionEventAndroid& event) {
@@ -457,10 +453,8 @@
 
 // static
 bool ViewAndroid::SendMouseEventToClient(ViewClient* client,
-                                         const MotionEventAndroid& event,
-                                         const gfx::PointF& point) {
-  std::unique_ptr<MotionEventAndroid> e(event.CreateFor(point));
-  return client->OnMouseEvent(*e);
+                                         const MotionEventAndroid& event) {
+  return client->OnMouseEvent(event);
 }
 
 bool ViewAndroid::OnMouseWheelEvent(const MotionEventAndroid& event) {
@@ -470,18 +464,24 @@
 
 // static
 bool ViewAndroid::SendMouseWheelEventToClient(ViewClient* client,
-                                              const MotionEventAndroid& event,
-                                              const gfx::PointF& point) {
-  std::unique_ptr<MotionEventAndroid> e(event.CreateFor(point));
-  return client->OnMouseWheelEvent(*e);
+                                              const MotionEventAndroid& event) {
+  return client->OnMouseWheelEvent(event);
 }
 
 template <typename E>
 bool ViewAndroid::HitTest(ViewClientCallback<E> send_to_client,
                           const E& event,
                           const gfx::PointF& point) {
-  if (client_ && send_to_client.Run(client_, event, point))
-    return true;
+  if (client_) {
+    if (view_rect_.origin().IsOrigin()) {  // (x, y) == (0, 0)
+      if (send_to_client.Run(client_, event))
+        return true;
+    } else {
+      std::unique_ptr<E> e(event.CreateFor(point));
+      if (send_to_client.Run(client_, *e))
+        return true;
+    }
+  }
 
   if (!children_.empty()) {
     gfx::PointF offset_point(point);
diff --git a/ui/android/view_android.h b/ui/android/view_android.h
index be27534..8b60c60 100644
--- a/ui/android/view_android.h
+++ b/ui/android/view_android.h
@@ -190,8 +190,7 @@
   void SetLayoutForTesting(int x, int y, int width, int height);
 
   template <typename E>
-  using ViewClientCallback =
-      const base::Callback<bool(ViewClient*, const E&, const gfx::PointF&)>;
+  using ViewClientCallback = const base::Callback<bool(ViewClient*, const E&)>;
 
   template <typename E>
   bool HitTest(ViewClientCallback<E> send_to_client,
@@ -199,17 +198,13 @@
                const gfx::PointF& point);
 
   static bool SendDragEventToClient(ViewClient* client,
-                                    const DragEventAndroid& event,
-                                    const gfx::PointF& point);
+                                    const DragEventAndroid& event);
   static bool SendTouchEventToClient(ViewClient* client,
-                                     const MotionEventAndroid& event,
-                                     const gfx::PointF& point);
+                                     const MotionEventAndroid& event);
   static bool SendMouseEventToClient(ViewClient* client,
-                                     const MotionEventAndroid& event,
-                                     const gfx::PointF& point);
+                                     const MotionEventAndroid& event);
   static bool SendMouseWheelEventToClient(ViewClient* client,
-                                          const MotionEventAndroid& event,
-                                          const gfx::PointF& point);
+                                          const MotionEventAndroid& event);
 
   bool has_event_forwarder() const { return !!event_forwarder_; }
 
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 8ca2300..2724f70 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -309,6 +309,13 @@
   app_list_main_view_->ShowAppListWhenReady();
 }
 
+void AppListView::Dismiss() {
+  app_list_main_view_->Close();
+  delegate_->Dismiss();
+  SetState(CLOSED);
+  GetWidget()->Deactivate();
+}
+
 void AppListView::UpdateBounds() {
   // if the AppListView is a bubble
   if (!is_fullscreen_app_list_enabled_)
@@ -562,7 +569,7 @@
   }
 
   if (!search_box_view_->is_search_box_active()) {
-    SetState(CLOSED);
+    Dismiss();
     return;
   }
 
@@ -616,7 +623,7 @@
         case HALF:
         case FULLSCREEN_SEARCH:
         case FULLSCREEN_ALL_APPS:
-          SetState(CLOSED);
+          Dismiss();
           break;
         case CLOSED:
           NOTREACHED();
@@ -676,7 +683,7 @@
     // If the drag ended near the bezel, close the app list and return early.
     if (location_y_in_current_display >=
         (display_height - kAppListBezelMargin)) {
-      SetState(CLOSED);
+      Dismiss();
       return;
     }
     switch (app_list_state_) {
@@ -688,7 +695,7 @@
         break;
       case FULLSCREEN_SEARCH:
         if (std::abs(drag_delta) > app_list_threshold)
-          SetState(CLOSED);
+          Dismiss();
         else
           SetState(app_list_state_);
         break;
@@ -706,7 +713,7 @@
             UMA_HISTOGRAM_ENUMERATION(kAppListPeekingToFullscreenHistogram,
                                       kSwipe, kMaxPeekingToFullscreen);
           } else {
-            SetState(CLOSED);
+            Dismiss();
           }
         } else {
           SetState(app_list_state_);
@@ -989,13 +996,7 @@
   // If the ContentsView does not handle the back action, then this is the
   // top level, so we close the app list.
   if (!app_list_main_view_->contents_view()->Back()) {
-    if (is_fullscreen_app_list_enabled_) {
-      SetState(CLOSED);
-    } else {
-      app_list_main_view_->Close();
-      delegate_->Dismiss();
-    }
-    GetWidget()->Deactivate();
+    Dismiss();
   }
 
   // Don't let DialogClientView handle the accelerator.
@@ -1153,8 +1154,6 @@
         case PEEKING:
         case FULLSCREEN_ALL_APPS:
         case FULLSCREEN_SEARCH:
-          delegate_->Dismiss();
-          app_list_main_view_->Close();
           break;
       }
   }
@@ -1162,7 +1161,9 @@
   RecordStateTransitionForUma(new_state_override);
   model_->SetStateFullscreen(new_state_override);
   app_list_state_ = new_state_override;
-
+  if (new_state_override == CLOSED) {
+    return;
+  }
   // Updates the visibility of app list items according to the change of
   // |app_list_state_|.
   app_list_main_view_->contents_view()
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index db9a1b7..5d084ca 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -116,6 +116,9 @@
   // timer to show the UI when a maximum allowed wait time has expired.
   void ShowWhenReady();
 
+  // Dismisses the UI, cleans up and sets the state to CLOSED.
+  void Dismiss();
+
   void UpdateBounds();
 
   // Enables/disables a semi-transparent overlay over the app list (good for
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 3374acd..1e43a99 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -451,7 +451,7 @@
         apps_container_view_->app_list_folder_view()->CloseFolderPage();
       } else {
         is_fullscreen_app_list_enabled_
-            ? app_list_view_->SetState(AppListView::CLOSED)
+            ? app_list_view_->Dismiss()
             : SetActiveState(AppListModel::STATE_START);
       }
       break;
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index f22bfbb4..3f9fe50 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -110,44 +110,6 @@
   return gfx::FontList(font);
 }
 
-#if defined(OS_CHROMEOS)
-// Return true if the default |display_source| should be used for the
-// notifications from the notifier.
-//
-// Ideally, we shuold fix the callers to set appropriate |display_source|, but
-// string resource is frozen in M62. For now, we should use this to prevent
-// empty |display_source| in system notifications.
-// TODO(tetsui): Remove this hack after M62 is released.
-bool ShowDefaultDisplaySource(const NotifierId& notifier) {
-  // The string constants are written in plain to prevent circular dependencies.
-  // This should not be accepted usually but I think it's OK here, as this
-  // function has a clear plan to be removed soon.
-  return notifier.type == NotifierId::SYSTEM_COMPONENT &&
-         (
-             // ARC notification.
-             // chrome/browser/chromeos/arc/arc_auth_notification.cc
-             notifier.id == "arc_auth" ||
-             // chrome/browser/chromeos/arc/notification/
-             //   arc_boot_error_notification.cc
-             notifier.id == "arc_boot_error" ||
-             // chrome/browser/chromeos/arc/notification/
-             //   arc_provision_notification_service.cc
-             notifier.id == "arc_managed_provision" ||
-             // Happiness survey notification.
-             // chrome/browser/chromeos/hats/hats_notification_controller.cc
-             notifier.id == "ash.hats" ||
-             // Sign-in error notification.
-             // chrome/browser/signin/signin_error_notifier_ash.cc
-             // chrome/browser/chromeos/authpolicy/
-             //   auth_policy_credentials_manager.cc
-             notifier.id == "chrome://settings/signin/" ||
-             // CUPS printing notification.
-             // chrome/browser/chromeos/printing/cups_print_job_notification.cc
-             notifier.id ==
-                 "chrome://settings/printing/cups-print-job-notification");
-}
-#endif
-
 // ItemView ////////////////////////////////////////////////////////////////////
 
 // ItemViews are responsible for drawing each list notification item's title and
@@ -628,9 +590,8 @@
   // TODO(tetsui): Remove this after all system notification transition is
   // completed.
   // All system notification should use Notification::CreateSystemNotification()
-  if ((notification.display_source().empty() &&
-       notification.origin_url().is_empty()) ||
-      ShowDefaultDisplaySource(notification.notifier_id())) {
+  if (notification.display_source().empty() &&
+      notification.origin_url().is_empty()) {
     header_row_->SetAppName(l10n_util::GetStringFUTF16(
         IDS_MESSAGE_CENTER_NOTIFICATION_CHROMEOS_SYSTEM,
         MessageCenter::Get()->GetProductOSName()));
diff --git a/ui/platform_window/mojo/ime_type_converters.h b/ui/platform_window/mojo/ime_type_converters.h
index 94fbda3..05d1486 100644
--- a/ui/platform_window/mojo/ime_type_converters.h
+++ b/ui/platform_window/mojo/ime_type_converters.h
@@ -5,6 +5,7 @@
 #ifndef UI_PLATFORM_WINDOW_MOJO_IME_TYPE_CONVERTERS_H_
 #define UI_PLATFORM_WINDOW_MOJO_IME_TYPE_CONVERTERS_H_
 
+#include "ui/base/ime/ime_text_span.h"
 #include "ui/platform_window/mojo/mojo_ime_export.h"
 #include "ui/platform_window/mojo/text_input_state.mojom.h"
 #include "ui/platform_window/text_input_state.h"