diff --git a/DEPS b/DEPS
index 6fe7096..16761847 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': '5eda734194d2d6dfaee766a9f3ad97cf16f56e2f',
+  'skia_revision': '2ac96dc82c45b4425c288dedbf3d35d70ac36928',
   # 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': '9006c5d397848354f0f30092094f03ff8d1750ae',
+  'v8_revision': '71062f39efd675ed137cea600d55f666499f1c56',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '8d57d4e4986bf9984793ef25c0a68db7fb1c752a',
+  'catapult_revision': '3d3b6d368d4aea08015591e995ac3d50c7ea77f4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -510,7 +510,7 @@
       Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4',
 
     'src/third_party/custom_tabs_client/src':
-      Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + '4889dd9d552d24f08584dde29f639c0da4ea0f12',
+      Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + 'bbdd5c4537fd4372d4339984fadc4791055bc182',
 
     'src/third_party/gvr-android-sdk/src':
       Var('chromium_git') + '/external/github.com/googlevr/gvr-android-sdk.git' + '@' + 'a27f768b13682189c23eed69656319db5ef7cbfc',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 3cee95a8..fea3fa9 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1007,6 +1007,8 @@
     "shell/panel_window.h",
     "shell/shell_delegate_impl.cc",
     "shell/shell_delegate_impl.h",
+    "shell/shell_views_delegate.cc",
+    "shell/shell_views_delegate.h",
     "shell/toplevel_window.cc",
     "shell/toplevel_window.h",
     "shell/widgets.cc",
diff --git a/ash/accelerators/ash_focus_manager_factory.cc b/ash/accelerators/ash_focus_manager_factory.cc
index d9091cdb..b22c9a9f 100644
--- a/ash/accelerators/ash_focus_manager_factory.cc
+++ b/ash/accelerators/ash_focus_manager_factory.cc
@@ -14,20 +14,20 @@
 AshFocusManagerFactory::AshFocusManagerFactory() {}
 AshFocusManagerFactory::~AshFocusManagerFactory() {}
 
-views::FocusManager* AshFocusManagerFactory::CreateFocusManager(
+std::unique_ptr<views::FocusManager> AshFocusManagerFactory::CreateFocusManager(
     views::Widget* widget,
     bool desktop_widget) {
-  return new views::FocusManager(
-      widget,
-      desktop_widget ? nullptr : base::WrapUnique<Delegate>(new Delegate));
+  return base::MakeUnique<views::FocusManager>(
+      widget, desktop_widget ? nullptr : base::MakeUnique<Delegate>());
 }
 
+AshFocusManagerFactory::Delegate::Delegate() {}
+AshFocusManagerFactory::Delegate::~Delegate() {}
+
 bool AshFocusManagerFactory::Delegate::ProcessAccelerator(
     const ui::Accelerator& accelerator) {
   AcceleratorController* controller = Shell::Get()->accelerator_controller();
-  if (controller)
-    return controller->Process(accelerator);
-  return false;
+  return controller && controller->Process(accelerator);
 }
 
 }  // namespace ash
diff --git a/ash/accelerators/ash_focus_manager_factory.h b/ash/accelerators/ash_focus_manager_factory.h
index 5d4ac24..5f05301 100644
--- a/ash/accelerators/ash_focus_manager_factory.h
+++ b/ash/accelerators/ash_focus_manager_factory.h
@@ -20,12 +20,16 @@
 
  protected:
   // views::FocusManagerFactory overrides:
-  views::FocusManager* CreateFocusManager(views::Widget* widget,
-                                          bool desktop_widget) override;
+  std::unique_ptr<views::FocusManager> CreateFocusManager(
+      views::Widget* widget,
+      bool desktop_widget) override;
 
  private:
   class Delegate : public views::FocusManagerDelegate {
    public:
+    Delegate();
+    ~Delegate() override;
+
     // views::FocusManagerDelegate overrides:
     bool ProcessAccelerator(const ui::Accelerator& accelerator) override;
   };
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index 42eaa130..948fb78a 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -6,7 +6,10 @@
 
 #include "ash/ash_switches.h"
 #include "ash/public/cpp/config.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_app_list_view_presenter_impl.h"
@@ -230,4 +233,33 @@
   EXPECT_FALSE(app_list_presenter_impl()->GetTargetVisibility());
 }
 
+// Tests that the shelf background displays/hides with bottom shelf
+// alignment.
+TEST_F(AppListPresenterDelegateTest,
+       ShelfBackgroundRespondsToAppListBeingShown) {
+  // TODO(newcomer): Investigate mash failures crbug.com/726838
+   if (Shell::GetAshConfig() == Config::MASH)
+     return;
+  EnableFullscreenAppList();
+  GetPrimaryShelf()->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+
+  // Show the app list, the shelf background should be transparent.
+  app_list_presenter_impl()->Show(GetPrimaryDisplayId());
+  ShelfLayoutManager* shelf_layout_manager =
+      GetPrimaryShelf()->shelf_layout_manager();
+  EXPECT_EQ(shelf_layout_manager->GetShelfBackgroundType(),
+            SHELF_BACKGROUND_DEFAULT);
+  app_list_presenter_impl()->Dismiss();
+
+  // Set the alignment to the side and show the app list. The background should
+  // show.
+  GetPrimaryShelf()->SetAlignment(ShelfAlignment::SHELF_ALIGNMENT_LEFT);
+  app_list_presenter_impl()->Show(GetPrimaryDisplayId());
+  EXPECT_TRUE(app_list::features::IsFullscreenAppListEnabled());
+  EXPECT_FALSE(GetPrimaryShelf()->IsHorizontalAlignment());
+  EXPECT_EQ(GetPrimaryShelf()->shelf_layout_manager()->
+            GetShelfBackgroundType(),
+            SHELF_BACKGROUND_DEFAULT);
+}
+
 }  // namespace ash
diff --git a/ash/aura/shell_port_classic.cc b/ash/aura/shell_port_classic.cc
index 105edb5c..f669e5a 100644
--- a/ash/aura/shell_port_classic.cc
+++ b/ash/aura/shell_port_classic.cc
@@ -85,6 +85,10 @@
   Shell::Get()->cursor_manager()->HideCursor();
 }
 
+void ShellPortClassic::SetCursorSize(ui::CursorSize cursor_size) {
+  Shell::Get()->cursor_manager()->SetCursorSize(cursor_size);
+}
+
 void ShellPortClassic::SetGlobalOverrideCursor(
     base::Optional<ui::CursorData> cursor) {
   // This is part of a fat interface that is only implemented on the mash side;
diff --git a/ash/aura/shell_port_classic.h b/ash/aura/shell_port_classic.h
index 99221d0..c007a69 100644
--- a/ash/aura/shell_port_classic.h
+++ b/ash/aura/shell_port_classic.h
@@ -39,6 +39,7 @@
   void UnlockCursor() override;
   void ShowCursor() override;
   void HideCursor() override;
+  void SetCursorSize(ui::CursorSize cursor_size) override;
   void SetGlobalOverrideCursor(base::Optional<ui::CursorData> cursor) override;
   bool IsMouseEventsEnabled() override;
   void RecordGestureAction(GestureActionType action) override;
diff --git a/ash/display/cursor_window_controller.cc b/ash/display/cursor_window_controller.cc
index 0755296..c57f542 100644
--- a/ash/display/cursor_window_controller.cc
+++ b/ash/display/cursor_window_controller.cc
@@ -90,7 +90,7 @@
       container_(NULL),
       cursor_type_(ui::CursorType::kNone),
       visible_(true),
-      cursor_set_(ui::CURSOR_SET_NORMAL),
+      cursor_size_(ui::CursorSize::kNormal),
       large_cursor_size_in_dip_(ash::kDefaultLargeCursorSize),
       delegate_(new CursorWindowDelegate()) {}
 
@@ -190,8 +190,8 @@
   UpdateCursorVisibility();
 }
 
-void CursorWindowController::SetCursorSet(ui::CursorSetType cursor_set) {
-  cursor_set_ = cursor_set;
+void CursorWindowController::SetCursorSize(ui::CursorSize cursor_size) {
+  cursor_size_ = cursor_size;
   UpdateCursorImage();
 }
 
@@ -246,7 +246,7 @@
   }
   int resource_id;
   // TODO(hshi): support custom cursor set.
-  if (!ui::GetCursorDataFor(cursor_set_, cursor_type_, cursor_scale,
+  if (!ui::GetCursorDataFor(cursor_size_, cursor_type_, cursor_scale,
                             &resource_id, &hot_point_)) {
     return;
   }
@@ -288,7 +288,7 @@
     // large cursor. We don't need to care about the case where cursor
     // compositing is disabled as we always use cursor compositing if
     // accessibility large cursor is enabled.
-    if (cursor_set_ == ui::CursorSetType::CURSOR_SET_LARGE &&
+    if (cursor_size_ == ui::CursorSize::kLarge &&
         large_cursor_size_in_dip_ != image->size().width()) {
       float rescale = static_cast<float>(large_cursor_size_in_dip_) /
                       static_cast<float>(image->size().width());
diff --git a/ash/display/cursor_window_controller.h b/ash/display/cursor_window_controller.h
index b8163803..762bd40 100644
--- a/ash/display/cursor_window_controller.h
+++ b/ash/display/cursor_window_controller.h
@@ -50,7 +50,7 @@
   // Sets cursor location, shape, set and visibility.
   void UpdateLocation();
   void SetCursor(gfx::NativeCursor cursor);
-  void SetCursorSet(ui::CursorSetType);
+  void SetCursorSize(ui::CursorSize cursor_size);
   void SetVisibility(bool visible);
 
  private:
@@ -84,7 +84,7 @@
   // The last requested cursor visibility.
   bool visible_;
 
-  ui::CursorSetType cursor_set_;
+  ui::CursorSize cursor_size_;
   gfx::Point hot_point_;
 
   int large_cursor_size_in_dip_;
diff --git a/ash/display/screen_orientation_controller_chromeos.cc b/ash/display/screen_orientation_controller_chromeos.cc
index b7bf293..b77d865 100644
--- a/ash/display/screen_orientation_controller_chromeos.cc
+++ b/ash/display/screen_orientation_controller_chromeos.cc
@@ -220,6 +220,17 @@
       ->IsMaximizeModeWindowManagerEnabled();
 }
 
+bool ScreenOrientationController::IsUserLockedOrientationPortrait() {
+  switch (user_locked_orientation_) {
+    case blink::kWebScreenOrientationLockPortraitPrimary:
+    case blink::kWebScreenOrientationLockPortraitSecondary:
+    case blink::kWebScreenOrientationLockPortrait:
+      return true;
+    default:
+      return false;
+  }
+}
+
 void ScreenOrientationController::ToggleUserRotationLock() {
   if (!display::Display::HasInternalDisplay())
     return;
diff --git a/ash/display/screen_orientation_controller_chromeos.h b/ash/display/screen_orientation_controller_chromeos.h
index a83d77f..23ed91a9 100644
--- a/ash/display/screen_orientation_controller_chromeos.h
+++ b/ash/display/screen_orientation_controller_chromeos.h
@@ -78,6 +78,11 @@
 
   bool ScreenOrientationProviderSupported() const;
 
+  // Returns true if the user has locked the orientation to portrait, false if
+  // the user has locked the orientation to landscape or not locked the
+  // orientation.
+  bool IsUserLockedOrientationPortrait();
+
   bool ignore_display_configuration_updates() const {
     return ignore_display_configuration_updates_;
   }
diff --git a/ash/mus/bridge/shell_port_mash.cc b/ash/mus/bridge/shell_port_mash.cc
index a01e4bfb..965c70f 100644
--- a/ash/mus/bridge/shell_port_mash.cc
+++ b/ash/mus/bridge/shell_port_mash.cc
@@ -147,6 +147,10 @@
   window_manager_->window_manager_client()->SetCursorVisible(false);
 }
 
+void ShellPortMash::SetCursorSize(ui::CursorSize cursor_size) {
+  window_manager_->window_manager_client()->SetCursorSize(cursor_size);
+}
+
 void ShellPortMash::SetGlobalOverrideCursor(
     base::Optional<ui::CursorData> cursor) {
   window_manager_->window_manager_client()->SetGlobalOverrideCursor(
diff --git a/ash/mus/bridge/shell_port_mash.h b/ash/mus/bridge/shell_port_mash.h
index 4878c26..83028f1 100644
--- a/ash/mus/bridge/shell_port_mash.h
+++ b/ash/mus/bridge/shell_port_mash.h
@@ -64,6 +64,7 @@
   void UnlockCursor() override;
   void ShowCursor() override;
   void HideCursor() override;
+  void SetCursorSize(ui::CursorSize cursor_size) override;
   void SetGlobalOverrideCursor(base::Optional<ui::CursorData> cursor) override;
   bool IsMouseEventsEnabled() override;
   void RecordGestureAction(GestureActionType action) override;
diff --git a/ash/mus/standalone/ash_standalone_main.cc b/ash/mus/standalone/ash_standalone_main.cc
index b595679..386338e 100644
--- a/ash/mus/standalone/ash_standalone_main.cc
+++ b/ash/mus/standalone/ash_standalone_main.cc
@@ -7,6 +7,7 @@
 #include "ash/shell/example_app_list_presenter.h"
 #include "ash/shell/example_session_controller_client.h"
 #include "ash/shell/shell_delegate_impl.h"
+#include "ash/shell/shell_views_delegate.h"
 #include "ash/shell/window_type_launcher.h"
 #include "ash/shell/window_watcher.h"
 #include "ash/shell_observer.h"
@@ -97,6 +98,7 @@
 }  // namespace ash
 
 MojoResult ServiceMain(MojoHandle service_request_handle) {
+  ash::shell::ShellViewsDelegate shell_views_delegate;
   const bool show_primary_host_on_connect = false;
   std::unique_ptr<ash::ShellInit> shell_init_ptr =
       base::MakeUnique<ash::ShellInit>();
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 1336dc3..ae74752 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -147,6 +147,8 @@
       shelf_(shelf),
       window_overlaps_shelf_(false),
       mouse_over_shelf_when_auto_hide_timer_started_(false),
+      is_fullscreen_app_list_enabled_(
+          app_list::features::IsFullscreenAppListEnabled()),
       gesture_drag_status_(GESTURE_DRAG_NONE),
       gesture_drag_amount_(0.f),
       gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
@@ -432,7 +434,7 @@
     return;
 
   is_app_list_visible_ = shown;
-  if (app_list::features::IsFullscreenAppListEnabled())
+  if (is_fullscreen_app_list_enabled_)
     MaybeUpdateShelfBackground(AnimationChangeType::IMMEDIATE);
 }
 
@@ -479,8 +481,14 @@
   if (state_.session_state != session_manager::SessionState::ACTIVE)
     return SHELF_BACKGROUND_OVERLAP;
 
+  // If the app list is active and the shelf is oriented vertically, enable the
+  // shelf background.
+  if (is_app_list_visible_ && !shelf_->IsHorizontalAlignment() &&
+      is_fullscreen_app_list_enabled_)
+    return SHELF_BACKGROUND_OVERLAP;
+
   // If the app list is active, hide the shelf background to prevent overlap.
-  if (is_app_list_visible_ && app_list::features::IsFullscreenAppListEnabled())
+  if (is_app_list_visible_ && is_fullscreen_app_list_enabled_)
     return SHELF_BACKGROUND_DEFAULT;
 
   if (state_.visibility_state != SHELF_AUTO_HIDE &&
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 7c3731a..18b7373 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -328,6 +328,9 @@
   // False when neither the auto hide timer nor the timer task are running.
   bool mouse_over_shelf_when_auto_hide_timer_started_;
 
+  // Whether the fullscreen app list feature is enabled.
+  const bool is_fullscreen_app_list_enabled_;
+
   base::ObserverList<ShelfLayoutManagerObserver> observers_;
 
   // The shelf reacts to gesture-drags, and can be set to auto-hide for certain
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc
index fae6a9f..f8f291b 100644
--- a/ash/shell/content/client/shell_browser_main_parts.cc
+++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -11,6 +11,7 @@
 #include "ash/shell/example_app_list_presenter.h"
 #include "ash/shell/example_session_controller_client.h"
 #include "ash/shell/shell_delegate_impl.h"
+#include "ash/shell/shell_views_delegate.h"
 #include "ash/shell/window_type_launcher.h"
 #include "ash/shell/window_watcher.h"
 #include "ash/shell_init_params.h"
@@ -40,7 +41,6 @@
 #include "ui/display/screen.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/examples/examples_window_with_content.h"
-#include "ui/views/test/test_views_delegate.h"
 #include "ui/wm/core/wm_state.h"
 
 #if defined(USE_X11)
@@ -50,37 +50,6 @@
 namespace ash {
 namespace shell {
 
-namespace {
-
-class ShellViewsDelegate : public views::TestViewsDelegate {
- public:
-  ShellViewsDelegate() {}
-  ~ShellViewsDelegate() override {}
-
-  // Overridden from views::TestViewsDelegate:
-  views::NonClientFrameView* CreateDefaultNonClientFrameView(
-      views::Widget* widget) override {
-    return ash::Shell::Get()->CreateDefaultNonClientFrameView(widget);
-  }
-  void OnBeforeWidgetInit(
-      views::Widget::InitParams* params,
-      views::internal::NativeWidgetDelegate* delegate) override {
-    if (params->opacity == views::Widget::InitParams::INFER_OPACITY)
-      params->opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-
-    if (params->native_widget)
-      return;
-
-    if (!params->parent && !params->context && !params->child)
-      params->context = Shell::GetPrimaryRootWindow();
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate);
-};
-
-}  // namespace
-
 ShellBrowserMainParts::ShellBrowserMainParts(
     const content::MainFunctionParams& parameters)
     : BrowserMainParts(), delegate_(nullptr) {}
diff --git a/ash/shell/shell_views_delegate.cc b/ash/shell/shell_views_delegate.cc
new file mode 100644
index 0000000..1522fa8
--- /dev/null
+++ b/ash/shell/shell_views_delegate.cc
@@ -0,0 +1,35 @@
+// 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 "ash/shell/shell_views_delegate.h"
+
+#include "ash/shell.h"
+
+namespace ash {
+namespace shell {
+
+ShellViewsDelegate::ShellViewsDelegate() = default;
+
+ShellViewsDelegate::~ShellViewsDelegate() = default;
+
+views::NonClientFrameView* ShellViewsDelegate::CreateDefaultNonClientFrameView(
+    views::Widget* widget) {
+  return ash::Shell::Get()->CreateDefaultNonClientFrameView(widget);
+}
+
+void ShellViewsDelegate::OnBeforeWidgetInit(
+    views::Widget::InitParams* params,
+    views::internal::NativeWidgetDelegate* delegate) {
+  if (params->opacity == views::Widget::InitParams::INFER_OPACITY)
+    params->opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+
+  if (params->native_widget)
+    return;
+
+  if (!params->parent && !params->context && !params->child)
+    params->context = Shell::GetPrimaryRootWindow();
+}
+
+}  // namespace shell
+}  // namespace ash
diff --git a/ash/shell/shell_views_delegate.h b/ash/shell/shell_views_delegate.h
new file mode 100644
index 0000000..d14c175
--- /dev/null
+++ b/ash/shell/shell_views_delegate.h
@@ -0,0 +1,32 @@
+// 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 ASH_SHELL_SHELL_VIEWS_DELEGATE_H_
+#define ASH_SHELL_SHELL_VIEWS_DELEGATE_H_
+
+#include "ui/views/test/test_views_delegate.h"
+
+namespace ash {
+namespace shell {
+
+class ShellViewsDelegate : public views::TestViewsDelegate {
+ public:
+  ShellViewsDelegate();
+  ~ShellViewsDelegate() override;
+
+  // views::TestViewsDelegate:
+  views::NonClientFrameView* CreateDefaultNonClientFrameView(
+      views::Widget* widget) override;
+  void OnBeforeWidgetInit(
+      views::Widget::InitParams* params,
+      views::internal::NativeWidgetDelegate* delegate) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegate);
+};
+
+}  // namespace shell
+}  // namespace ash
+
+#endif  // ASH_SHELL_SHELL_VIEWS_DELEGATE_H_
diff --git a/ash/shell_port.h b/ash/shell_port.h
index a2844be..a4632615 100644
--- a/ash/shell_port.h
+++ b/ash/shell_port.h
@@ -33,6 +33,10 @@
 class Point;
 }
 
+namespace ui {
+enum class CursorSize;
+}
+
 namespace views {
 class PointerWatcher;
 enum class PointerWatcherEventTypes;
@@ -102,6 +106,7 @@
   virtual void UnlockCursor() = 0;
   virtual void ShowCursor() = 0;
   virtual void HideCursor() = 0;
+  virtual void SetCursorSize(ui::CursorSize cursor_size) = 0;
   virtual void SetGlobalOverrideCursor(
       base::Optional<ui::CursorData> cursor) = 0;
   virtual bool IsMouseEventsEnabled() = 0;
diff --git a/ash/system/rotation/tray_rotation_lock.cc b/ash/system/rotation/tray_rotation_lock.cc
index 0fbdba1..eab1074 100644
--- a/ash/system/rotation/tray_rotation_lock.cc
+++ b/ash/system/rotation/tray_rotation_lock.cc
@@ -40,16 +40,6 @@
   return Shell::Get()->screen_orientation_controller()->user_rotation_locked();
 }
 
-bool IsCurrentRotationPortrait() {
-  display::Display::Rotation current_rotation =
-      Shell::Get()
-          ->display_manager()
-          ->GetDisplayInfo(display::Display::InternalDisplayId())
-          .GetActiveRotation();
-  return current_rotation == display::Display::ROTATE_90 ||
-         current_rotation == display::Display::ROTATE_270;
-}
-
 }  // namespace
 
 namespace tray {
@@ -117,12 +107,19 @@
   TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL);
   base::string16 label;
   if (IsUserRotationLocked()) {
-    icon_->SetImage(gfx::CreateVectorIcon(
-        IsCurrentRotationPortrait() ? kSystemMenuRotationLockPortraitIcon
-                                    : kSystemMenuRotationLockLandscapeIcon,
-        kMenuIconSize, style.GetIconColor()));
+    // If user rotation is locked, display the icon and text of the preferred
+    // orientation.
+    bool is_user_locked_orientation_portrait =
+        Shell::Get()
+            ->screen_orientation_controller()
+            ->IsUserLockedOrientationPortrait();
+    icon_->SetImage(
+        gfx::CreateVectorIcon(is_user_locked_orientation_portrait
+                                  ? kSystemMenuRotationLockPortraitIcon
+                                  : kSystemMenuRotationLockLandscapeIcon,
+                              kMenuIconSize, style.GetIconColor()));
     label = l10n_util::GetStringUTF16(
-        IsCurrentRotationPortrait()
+        is_user_locked_orientation_portrait
             ? IDS_ASH_STATUS_TRAY_ROTATION_LOCK_PORTRAIT
             : IDS_ASH_STATUS_TRAY_ROTATION_LOCK_LANDSCAPE);
   } else {
diff --git a/ash/test/cursor_manager_test_api.cc b/ash/test/cursor_manager_test_api.cc
index 029269e..77ad774 100644
--- a/ash/test/cursor_manager_test_api.cc
+++ b/ash/test/cursor_manager_test_api.cc
@@ -20,8 +20,8 @@
 CursorManagerTestApi::~CursorManagerTestApi() {}
 
 // TODO(tdanderson): CursorManagerTestApi may no longer be needed.
-ui::CursorSetType CursorManagerTestApi::GetCurrentCursorSet() const {
-  return cursor_manager_->GetCursorSet();
+ui::CursorSize CursorManagerTestApi::GetCurrentCursorSize() const {
+  return cursor_manager_->GetCursorSize();
 }
 
 gfx::NativeCursor CursorManagerTestApi::GetCurrentCursor() const {
diff --git a/ash/test/cursor_manager_test_api.h b/ash/test/cursor_manager_test_api.h
index ff22dd8..47310b21 100644
--- a/ash/test/cursor_manager_test_api.h
+++ b/ash/test/cursor_manager_test_api.h
@@ -23,7 +23,7 @@
   explicit CursorManagerTestApi(::wm::CursorManager* cursor_manager);
   ~CursorManagerTestApi();
 
-  ui::CursorSetType GetCurrentCursorSet() const;
+  ui::CursorSize GetCurrentCursorSize() const;
   gfx::NativeCursor GetCurrentCursor() const;
   display::Display::Rotation GetCurrentCursorRotation() const;
   float GetCurrentCursorScale() const;
diff --git a/ash/utility/screenshot_controller_unittest.cc b/ash/utility/screenshot_controller_unittest.cc
index 2b9503d..bac14b8 100644
--- a/ash/utility/screenshot_controller_unittest.cc
+++ b/ash/utility/screenshot_controller_unittest.cc
@@ -296,7 +296,7 @@
 // Make sure ScreenshotController doesn't prevent handling of large
 // cursor. See http://crbug.com/459214
 TEST_F(PartialScreenshotControllerTest, LargeCursor) {
-  Shell::Get()->cursor_manager()->SetCursorSet(ui::CURSOR_SET_LARGE);
+  Shell::Get()->cursor_manager()->SetCursorSize(ui::CursorSize::kLarge);
   Shell::Get()
       ->window_tree_host_manager()
       ->cursor_window_controller()
diff --git a/ash/wm/native_cursor_manager_ash_classic.cc b/ash/wm/native_cursor_manager_ash_classic.cc
index 8b5112c..7514717 100644
--- a/ash/wm/native_cursor_manager_ash_classic.cc
+++ b/ash/wm/native_cursor_manager_ash_classic.cc
@@ -119,11 +119,11 @@
     SetCursorOnAllRootWindows(cursor);
 }
 
-void NativeCursorManagerAshClassic::SetCursorSet(
-    ui::CursorSetType cursor_set,
+void NativeCursorManagerAshClassic::SetCursorSize(
+    ui::CursorSize cursor_size,
     ::wm::NativeCursorManagerDelegate* delegate) {
-  image_cursors_->SetCursorSet(cursor_set);
-  delegate->CommitCursorSet(cursor_set);
+  image_cursors_->SetCursorSize(cursor_size);
+  delegate->CommitCursorSize(cursor_size);
 
   // Sets the cursor to reflect the scale change immediately.
   if (delegate->IsCursorVisible())
@@ -132,7 +132,7 @@
   Shell::Get()
       ->window_tree_host_manager()
       ->cursor_window_controller()
-      ->SetCursorSet(cursor_set);
+      ->SetCursorSize(cursor_size);
 }
 
 void NativeCursorManagerAshClassic::SetVisibility(
diff --git a/ash/wm/native_cursor_manager_ash_classic.h b/ash/wm/native_cursor_manager_ash_classic.h
index dee120c..07065a6 100644
--- a/ash/wm/native_cursor_manager_ash_classic.h
+++ b/ash/wm/native_cursor_manager_ash_classic.h
@@ -41,8 +41,8 @@
                  ::wm::NativeCursorManagerDelegate* delegate) override;
   void SetVisibility(bool visible,
                      ::wm::NativeCursorManagerDelegate* delegate) override;
-  void SetCursorSet(ui::CursorSetType cursor_set,
-                    ::wm::NativeCursorManagerDelegate* delegate) override;
+  void SetCursorSize(ui::CursorSize cursor_size,
+                     ::wm::NativeCursorManagerDelegate* delegate) override;
   void SetMouseEventsEnabled(
       bool enabled,
       ::wm::NativeCursorManagerDelegate* delegate) override;
diff --git a/ash/wm/native_cursor_manager_ash_mus.cc b/ash/wm/native_cursor_manager_ash_mus.cc
index a53c6b6..279ae7e 100644
--- a/ash/wm/native_cursor_manager_ash_mus.cc
+++ b/ash/wm/native_cursor_manager_ash_mus.cc
@@ -174,12 +174,17 @@
   NotifyCursorVisibilityChange(visible);
 }
 
-void NativeCursorManagerAshMus::SetCursorSet(
-    ui::CursorSetType cursor_set,
+void NativeCursorManagerAshMus::SetCursorSize(
+    ui::CursorSize cursor_size,
     ::wm::NativeCursorManagerDelegate* delegate) {
-  // We can't just hand this off to ImageCursors like we do in the classic ash
-  // case. We need to collaborate with the mus server to fully implement this.
-  NOTIMPLEMENTED();
+  delegate->CommitCursorSize(cursor_size);
+
+  ShellPort::Get()->SetCursorSize(cursor_size);
+
+  Shell::Get()
+      ->window_tree_host_manager()
+      ->cursor_window_controller()
+      ->SetCursorSize(cursor_size);
 }
 
 void NativeCursorManagerAshMus::SetMouseEventsEnabled(
diff --git a/ash/wm/native_cursor_manager_ash_mus.h b/ash/wm/native_cursor_manager_ash_mus.h
index 58a9e81..75e4186 100644
--- a/ash/wm/native_cursor_manager_ash_mus.h
+++ b/ash/wm/native_cursor_manager_ash_mus.h
@@ -41,8 +41,8 @@
                  ::wm::NativeCursorManagerDelegate* delegate) override;
   void SetVisibility(bool visible,
                      ::wm::NativeCursorManagerDelegate* delegate) override;
-  void SetCursorSet(ui::CursorSetType cursor_set,
-                    ::wm::NativeCursorManagerDelegate* delegate) override;
+  void SetCursorSize(ui::CursorSize cursor_size,
+                     ::wm::NativeCursorManagerDelegate* delegate) override;
   void SetMouseEventsEnabled(
       bool enabled,
       ::wm::NativeCursorManagerDelegate* delegate) override;
diff --git a/ash/wm/native_cursor_manager_ash_unittest.cc b/ash/wm/native_cursor_manager_ash_unittest.cc
index edd4671..efd768c 100644
--- a/ash/wm/native_cursor_manager_ash_unittest.cc
+++ b/ash/wm/native_cursor_manager_ash_unittest.cc
@@ -63,7 +63,7 @@
   EXPECT_EQ(ui::CursorType::kCopy, test_api.GetCurrentCursor().native_type());
   UpdateDisplay("800x800*2/r");
   EXPECT_EQ(2.0f, test_api.GetCurrentCursor().device_scale_factor());
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
   EXPECT_EQ(display::Display::ROTATE_90, test_api.GetCurrentCursorRotation());
   EXPECT_TRUE(test_api.GetCurrentCursor().platform());
 
@@ -71,13 +71,13 @@
   EXPECT_TRUE(cursor_manager->IsCursorLocked());
 
   // Cursor type does not change while cursor is locked.
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_LARGE);
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, test_api.GetCurrentCursorSet());
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
+  cursor_manager->SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
+  cursor_manager->SetCursorSize(ui::CursorSize::kLarge);
+  EXPECT_EQ(ui::CursorSize::kLarge, test_api.GetCurrentCursorSize());
+  cursor_manager->SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
 
   // Cursor type does not change while cursor is locked.
   cursor_manager->SetCursor(ui::CursorType::kPointer);
@@ -110,20 +110,20 @@
   EXPECT_TRUE(test_api.GetCurrentCursor().platform());
 }
 
-TEST_F(NativeCursorManagerAshTest, SetCursorSet) {
+TEST_F(NativeCursorManagerAshTest, SetCursorSize) {
   ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
   CursorManagerTestApi test_api(cursor_manager);
 
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
 
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
+  cursor_manager->SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
 
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_LARGE);
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, test_api.GetCurrentCursorSet());
+  cursor_manager->SetCursorSize(ui::CursorSize::kLarge);
+  EXPECT_EQ(ui::CursorSize::kLarge, test_api.GetCurrentCursorSize());
 
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, test_api.GetCurrentCursorSet());
+  cursor_manager->SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_EQ(ui::CursorSize::kNormal, test_api.GetCurrentCursorSize());
 }
 
 TEST_F(NativeCursorManagerAshTest, SetDeviceScaleFactorAndRotation) {
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc
index 9d164a5b..59ee4f5 100644
--- a/ash/wm/window_manager_unittest.cc
+++ b/ash/wm/window_manager_unittest.cc
@@ -848,8 +848,8 @@
   EXPECT_FALSE(observer_b.did_visibility_change());
   EXPECT_FALSE(observer_a.is_cursor_visible());
   EXPECT_FALSE(observer_b.is_cursor_visible());
-  EXPECT_FALSE(observer_a.did_cursor_set_change());
-  EXPECT_FALSE(observer_b.did_cursor_set_change());
+  EXPECT_FALSE(observer_a.did_cursor_size_change());
+  EXPECT_FALSE(observer_b.did_cursor_size_change());
 
   // Keypress should hide the cursor.
   generator.PressKey(ui::VKEY_A, ui::EF_NONE);
@@ -859,11 +859,11 @@
   EXPECT_FALSE(observer_b.is_cursor_visible());
 
   // Set cursor set.
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_LARGE);
-  EXPECT_TRUE(observer_a.did_cursor_set_change());
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, observer_a.cursor_set());
-  EXPECT_TRUE(observer_b.did_cursor_set_change());
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, observer_b.cursor_set());
+  cursor_manager->SetCursorSize(ui::CursorSize::kLarge);
+  EXPECT_TRUE(observer_a.did_cursor_size_change());
+  EXPECT_EQ(ui::CursorSize::kLarge, observer_a.cursor_size());
+  EXPECT_TRUE(observer_b.did_cursor_size_change());
+  EXPECT_EQ(ui::CursorSize::kLarge, observer_b.cursor_size());
 
   // Mouse move should show the cursor.
   observer_a.reset();
@@ -887,10 +887,10 @@
   EXPECT_FALSE(observer_a.is_cursor_visible());
 
   // Set back cursor set to normal.
-  cursor_manager->SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_TRUE(observer_a.did_cursor_set_change());
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, observer_a.cursor_set());
-  EXPECT_FALSE(observer_b.did_cursor_set_change());
+  cursor_manager->SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_TRUE(observer_a.did_cursor_size_change());
+  EXPECT_EQ(ui::CursorSize::kNormal, observer_a.cursor_size());
+  EXPECT_FALSE(observer_b.did_cursor_size_change());
 
   // Mouse move should show the cursor.
   observer_a.reset();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java b/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
index ac60fd5..397e8ab 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
@@ -52,7 +52,14 @@
             return;
         }
 
-        UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        UiDevice uiDevice = null;
+        try {
+            uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        } catch (RuntimeException ex) {
+            Log.d(TAG, "Failed to initialize UiDevice", ex);
+            return;
+        }
+
         File screenshotFile = new File(screenshotFilePath);
         File screenshotDir = screenshotFile.getParentFile();
         if (screenshotDir == null) {
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 76fa0d4..cd64bda 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -21,6 +21,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/run_loop.h"
@@ -33,6 +34,7 @@
 #include "base/strings/stringize_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
 #include "base/test/gtest_util.h"
 #include "base/test/launcher/test_launcher_tracer.h"
 #include "base/test/launcher/test_results_tracker.h"
@@ -803,22 +805,6 @@
   if (command_line->HasSwitch(switches::kTestLauncherForceRunBrokenTests))
     force_run_broken_tests_ = true;
 
-  if (command_line->HasSwitch(switches::kTestLauncherJobs)) {
-    size_t jobs = 0U;
-    if (!StringToSizeT(command_line->GetSwitchValueASCII(
-                         switches::kTestLauncherJobs), &jobs) ||
-        !jobs) {
-      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherJobs;
-      return false;
-    }
-
-    parallel_jobs_ = jobs;
-  } else if (command_line->HasSwitch(kGTestFilterFlag) && !BotModeEnabled()) {
-    // Do not run jobs in parallel by default if we are running a subset of
-    // the tests and if bot mode is off.
-    parallel_jobs_ = 1U;
-  }
-
   fprintf(stdout, "Using %" PRIuS " parallel jobs.\n", parallel_jobs_);
   fflush(stdout);
   if (parallel_jobs_ > 1U) {
@@ -1199,6 +1185,31 @@
   return worker_thread_->task_runner();
 }
 
+size_t NumParallelJobs() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  CommandLine::SwitchMap switches = command_line->GetSwitches();
+
+  size_t jobs = 0U;
+
+  if (command_line->HasSwitch(kGTestFilterFlag) && !BotModeEnabled()) {
+    // Do not run jobs in parallel by default if we are running a subset of
+    // the tests and if bot mode is off.
+    return 1U;
+  } else if (command_line->HasSwitch(switches::kTestLauncherJobs)) {
+    if (!StringToSizeT(
+            command_line->GetSwitchValueASCII(switches::kTestLauncherJobs),
+            &jobs) ||
+        !jobs) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherJobs;
+      return 0U;
+    }
+
+    return jobs;
+  }
+
+  return base::checked_cast<size_t>(SysInfo::NumberOfProcessors());
+}
+
 std::string GetTestOutputSnippet(const TestResult& result,
                                  const std::string& full_output) {
   size_t run_pos = full_output.find(std::string("[ RUN      ] ") +
diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h
index 52288b1..dd69846 100644
--- a/base/test/launcher/test_launcher.h
+++ b/base/test/launcher/test_launcher.h
@@ -244,6 +244,9 @@
   DISALLOW_COPY_AND_ASSIGN(TestLauncher);
 };
 
+// Return the number of parallel jobs to use, or 0U in case of error.
+size_t NumParallelJobs();
+
 // Extract part from |full_output| that applies to |result|.
 std::string GetTestOutputSnippet(const TestResult& result,
                                  const std::string& full_output);
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 65531a2..28a50d3 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -183,7 +183,7 @@
 }
 
 int LaunchUnitTestsInternal(const RunTestSuiteCallback& run_test_suite,
-                            int default_jobs,
+                            size_t parallel_jobs,
                             int default_batch_limit,
                             bool use_job_objects,
                             const Closure& gtest_init) {
@@ -246,7 +246,7 @@
   DefaultUnitTestPlatformDelegate platform_delegate;
   UnitTestLauncherDelegate delegate(
       &platform_delegate, batch_limit, use_job_objects);
-  base::TestLauncher launcher(&delegate, default_jobs);
+  base::TestLauncher launcher(&delegate, parallel_jobs);
   bool success = launcher.Run();
 
   fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
@@ -455,40 +455,33 @@
                     char** argv,
                     const RunTestSuiteCallback& run_test_suite) {
   CommandLine::Init(argc, argv);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      SysInfo::NumberOfProcessors(),
-      kDefaultTestBatchLimit,
-      true,
-      Bind(&InitGoogleTestChar, &argc, argv));
+  size_t parallel_jobs = NumParallelJobs();
+  if (parallel_jobs == 0U) {
+    return 1;
+  }
+  return LaunchUnitTestsInternal(run_test_suite, parallel_jobs,
+                                 kDefaultTestBatchLimit, true,
+                                 Bind(&InitGoogleTestChar, &argc, argv));
 }
 
 int LaunchUnitTestsSerially(int argc,
                             char** argv,
                             const RunTestSuiteCallback& run_test_suite) {
   CommandLine::Init(argc, argv);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      1,
-      kDefaultTestBatchLimit,
-      true,
-      Bind(&InitGoogleTestChar, &argc, argv));
+  return LaunchUnitTestsInternal(run_test_suite, 1U, kDefaultTestBatchLimit,
+                                 true, Bind(&InitGoogleTestChar, &argc, argv));
 }
 
-int LaunchUnitTestsWithOptions(
-    int argc,
-    char** argv,
-    int default_jobs,
-    int default_batch_limit,
-    bool use_job_objects,
-    const RunTestSuiteCallback& run_test_suite) {
+int LaunchUnitTestsWithOptions(int argc,
+                               char** argv,
+                               size_t parallel_jobs,
+                               int default_batch_limit,
+                               bool use_job_objects,
+                               const RunTestSuiteCallback& run_test_suite) {
   CommandLine::Init(argc, argv);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      default_jobs,
-      default_batch_limit,
-      use_job_objects,
-      Bind(&InitGoogleTestChar, &argc, argv));
+  return LaunchUnitTestsInternal(run_test_suite, parallel_jobs,
+                                 default_batch_limit, use_job_objects,
+                                 Bind(&InitGoogleTestChar, &argc, argv));
 }
 
 #if defined(OS_WIN)
@@ -498,12 +491,13 @@
                     const RunTestSuiteCallback& run_test_suite) {
   // Windows CommandLine::Init ignores argv anyway.
   CommandLine::Init(argc, NULL);
-  return LaunchUnitTestsInternal(
-      run_test_suite,
-      SysInfo::NumberOfProcessors(),
-      kDefaultTestBatchLimit,
-      use_job_objects,
-      Bind(&InitGoogleTestWChar, &argc, argv));
+  size_t parallel_jobs = NumParallelJobs();
+  if (parallel_jobs == 0U) {
+    return 1;
+  }
+  return LaunchUnitTestsInternal(run_test_suite, parallel_jobs,
+                                 kDefaultTestBatchLimit, use_job_objects,
+                                 Bind(&InitGoogleTestWChar, &argc, argv));
 }
 #endif  // defined(OS_WIN)
 
diff --git a/base/test/launcher/unit_test_launcher.h b/base/test/launcher/unit_test_launcher.h
index 2e6b813..91abcfb 100644
--- a/base/test/launcher/unit_test_launcher.h
+++ b/base/test/launcher/unit_test_launcher.h
@@ -29,17 +29,16 @@
                             const RunTestSuiteCallback& run_test_suite);
 
 // Launches unit tests in given test suite. Returns exit code.
-// |default_jobs| is the default number of parallel test jobs.
+// |parallel_jobs| is the number of parallel test jobs.
 // |default_batch_limit| is the default size of test batch
 // (use 0 to disable batching).
 // |use_job_objects| determines whether to use job objects.
-int LaunchUnitTestsWithOptions(
-    int argc,
-    char** argv,
-    int default_jobs,
-    int default_batch_limit,
-    bool use_job_objects,
-    const RunTestSuiteCallback& run_test_suite);
+int LaunchUnitTestsWithOptions(int argc,
+                               char** argv,
+                               size_t parallel_jobs,
+                               int default_batch_limit,
+                               bool use_job_objects,
+                               const RunTestSuiteCallback& run_test_suite);
 
 #if defined(OS_WIN)
 // Launches unit tests in given test suite. Returns exit code.
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 3f8f2b6..d9c70b4 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1073,7 +1073,6 @@
     if (is_clang) {
       cflags += [
         # TODO(hans): Make this list shorter eventually, http://crbug.com/504657
-        "-Wno-microsoft-enum-value",  # http://crbug.com/505296
         "-Wno-unknown-pragmas",  # http://crbug.com/505314
         "-Wno-microsoft-cast",  # http://crbug.com/550065
         "-Wno-microsoft-enum-forward-reference",  # http://crbug.com/718880
diff --git a/build/download_gold_plugin.py b/build/download_gold_plugin.py
deleted file mode 100755
index 81231678..0000000
--- a/build/download_gold_plugin.py
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Script to download LLVM gold plugin from google storage."""
-
-import find_depot_tools
-import json
-import os
-import shutil
-import subprocess
-import sys
-import zipfile
-
-SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
-CHROME_SRC = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
-
-
-DEPOT_PATH = find_depot_tools.add_depot_tools_to_path()
-GSUTIL_PATH = os.path.join(DEPOT_PATH, 'gsutil.py')
-
-LLVM_BUILD_PATH = os.path.join(CHROME_SRC, 'third_party', 'llvm-build',
-                               'Release+Asserts')
-CLANG_UPDATE_PY = os.path.join(CHROME_SRC, 'tools', 'clang', 'scripts',
-                               'update.py')
-CLANG_REVISION = os.popen(CLANG_UPDATE_PY + ' --print-revision').read().rstrip()
-
-CLANG_BUCKET = 'gs://chromium-browser-clang/Linux_x64'
-
-def main():
-  targz_name = 'llvmgold-%s.tgz' % CLANG_REVISION
-  remote_path = '%s/%s' % (CLANG_BUCKET, targz_name)
-
-  os.chdir(LLVM_BUILD_PATH)
-
-  subprocess.check_call(['python', GSUTIL_PATH,
-                         'cp', remote_path, targz_name])
-  subprocess.check_call(['tar', 'xzf', targz_name])
-  os.remove(targz_name)
-  return 0
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index c7daf0a..834869b8 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -188,6 +188,72 @@
 
 SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
 
+std::string PaintOpTypeToString(PaintOpType type) {
+  switch (type) {
+    case PaintOpType::Annotate:
+      return "Annotate";
+    case PaintOpType::ClipPath:
+      return "ClipPath";
+    case PaintOpType::ClipRect:
+      return "ClipRect";
+    case PaintOpType::ClipRRect:
+      return "ClipRRect";
+    case PaintOpType::Concat:
+      return "Concat";
+    case PaintOpType::DrawArc:
+      return "DrawArc";
+    case PaintOpType::DrawCircle:
+      return "DrawCircle";
+    case PaintOpType::DrawColor:
+      return "DrawColor";
+    case PaintOpType::DrawDRRect:
+      return "DrawDRRect";
+    case PaintOpType::DrawImage:
+      return "DrawImage";
+    case PaintOpType::DrawImageRect:
+      return "DrawImageRect";
+    case PaintOpType::DrawIRect:
+      return "DrawIRect";
+    case PaintOpType::DrawLine:
+      return "DrawLine";
+    case PaintOpType::DrawOval:
+      return "DrawOval";
+    case PaintOpType::DrawPath:
+      return "DrawPath";
+    case PaintOpType::DrawPosText:
+      return "DrawPosText";
+    case PaintOpType::DrawRecord:
+      return "DrawRecord";
+    case PaintOpType::DrawRect:
+      return "DrawRect";
+    case PaintOpType::DrawRRect:
+      return "DrawRRect";
+    case PaintOpType::DrawText:
+      return "DrawText";
+    case PaintOpType::DrawTextBlob:
+      return "DrawTextBlob";
+    case PaintOpType::Noop:
+      return "Noop";
+    case PaintOpType::Restore:
+      return "Restore";
+    case PaintOpType::Rotate:
+      return "Rotate";
+    case PaintOpType::Save:
+      return "Save";
+    case PaintOpType::SaveLayer:
+      return "SaveLayer";
+    case PaintOpType::SaveLayerAlpha:
+      return "SaveLayerAlpha";
+    case PaintOpType::Scale:
+      return "Scale";
+    case PaintOpType::SetMatrix:
+      return "SetMatrix";
+    case PaintOpType::Translate:
+      return "Translate";
+  }
+  return "UNKNOWN";
+}
+
 void AnnotateOp::Raster(const PaintOp* base_op,
                         SkCanvas* canvas,
                         const SkMatrix& original_ctm) {
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index 465381a..b7b115f 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include <string>
+
 #include "base/logging.h"
 #include "base/memory/aligned_memory.h"
 #include "cc/base/math_util.h"
@@ -72,6 +74,8 @@
   LastPaintOpType = Translate,
 };
 
+std::string PaintOpTypeToString(PaintOpType type);
+
 struct CC_PAINT_EXPORT PaintOp {
   uint32_t type : 8;
   uint32_t skip : 24;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 6dbf6453..8d63a313c 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2116,6 +2116,12 @@
     // Reset will call the destructor and log the timer histogram.
     pending_tree_duration_timer_.reset();
 
+    // In most cases, this will be reset in NotifyReadyToActivate, since we
+    // activate the pending tree only when its ready. But an activation may be
+    // forced, in the case of a context loss for instance, so reset it here as
+    // well.
+    pending_tree_raster_duration_timer_.reset();
+
     // Process any requests in the UI resource queue.  The request queue is
     // given in LayerTreeHost::FinishCommitOnImplThread.  This must take place
     // before the swap.
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 7024bd3..fdc06eb 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1678,6 +1678,12 @@
     ]
   }
 
+  java_cpp_enum("credit_card_javagen") {
+    sources = [
+      "../components/autofill/core/browser/credit_card.h",
+    ]
+  }
+
   java_cpp_enum("signin_metrics_enum_javagen") {
     sources = [
       "../components/signin/core/browser/signin_metrics.h",
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 7c258ae6..1bb7d1ce 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -259,6 +259,7 @@
     ":resource_id_javagen",
     "//chrome:content_setting_javagen",
     "//chrome:content_settings_type_javagen",
+    "//chrome:credit_card_javagen",
     "//chrome:data_use_ui_message_enum_javagen",
     "//chrome:offline_pages_enum_javagen",
     "//chrome:page_info_connection_type_javagen",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
index 62ce02e..1e44667 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java
@@ -352,7 +352,9 @@
      */
     public static class CreditCard {
         // Note that while some of these fields are numbers, they're predominantly read,
-        // marshaled and compared as strings. To save conversions, we use strings everywhere.
+        // marshaled and compared as strings. To save conversions, we sometimes use strings.
+        @CardType
+        private final int mCardType;
         private String mGUID;
         private String mOrigin;
         private boolean mIsLocal;
@@ -371,16 +373,17 @@
         public static CreditCard create(String guid, String origin, boolean isLocal,
                 boolean isCached, String name, String number, String obfuscatedNumber, String month,
                 String year, String basicCardIssuerNetwork, int enumeratedIconId,
-                String billingAddressId, String serverId) {
+                @CardType int cardType, String billingAddressId, String serverId) {
             return new CreditCard(guid, origin, isLocal, isCached, name, number, obfuscatedNumber,
                     month, year, basicCardIssuerNetwork,
-                    ResourceId.mapToDrawableId(enumeratedIconId), billingAddressId, serverId);
+                    ResourceId.mapToDrawableId(enumeratedIconId), cardType, billingAddressId,
+                    serverId);
         }
 
         public CreditCard(String guid, String origin, boolean isLocal, boolean isCached,
                 String name, String number, String obfuscatedNumber, String month, String year,
-                String basicCardIssuerNetwork, int issuerIconDrawableId, String billingAddressId,
-                String serverId) {
+                String basicCardIssuerNetwork, int issuerIconDrawableId, @CardType int cardType,
+                String billingAddressId, String serverId) {
             mGUID = guid;
             mOrigin = origin;
             mIsLocal = isLocal;
@@ -392,6 +395,7 @@
             mYear = year;
             mBasicCardIssuerNetwork = basicCardIssuerNetwork;
             mIssuerIconDrawableId = issuerIconDrawableId;
+            mCardType = cardType;
             mBillingAddressId = billingAddressId;
             mServerId = serverId;
         }
@@ -400,7 +404,7 @@
             this("" /* guid */, AutofillAndPaymentsPreferences.SETTINGS_ORIGIN /*origin */,
                     true /* isLocal */, false /* isCached */, "" /* name */, "" /* number */,
                     "" /* obfuscatedNumber */, "" /* month */, "" /* year */,
-                    "" /* basicCardIssuerNetwork */, 0 /* issuerIconDrawableId */,
+                    "" /* basicCardIssuerNetwork */, 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
                     "" /* billingAddressId */, "" /* serverId */);
         }
 
@@ -410,7 +414,8 @@
                 String obfuscatedNumber, String month, String year) {
             this(guid, origin, true /* isLocal */, false /* isCached */, name, number,
                     obfuscatedNumber, month, year, "" /* basicCardIssuerNetwork */,
-                    0 /* issuerIconDrawableId */, "" /* billingAddressId */, "" /* serverId */);
+                    0 /* issuerIconDrawableId */, CardType.UNKNOWN, "" /* billingAddressId */,
+                    "" /* serverId */);
         }
 
         @CalledByNative("CreditCard")
@@ -472,6 +477,12 @@
             return mIssuerIconDrawableId;
         }
 
+        @CardType
+        @CalledByNative("CreditCard")
+        public int getCardType() {
+            return mCardType;
+        }
+
         @CalledByNative("CreditCard")
         public String getBillingAddressId() {
             return mBillingAddressId;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
index 1af8b573..0c1dd75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuHelper.java
@@ -7,7 +7,6 @@
 import android.app.Activity;
 import android.content.ComponentName;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.util.Pair;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -205,7 +204,7 @@
                 ShareHelper.shareImage(activity, result, name);
             }
         };
-        nativeRetrieveImage(mNativeContextMenuHelper, callback, MAX_SHARE_DIMEN_PX);
+        nativeRetrieveImageForShare(mNativeContextMenuHelper, callback, MAX_SHARE_DIMEN_PX);
     }
 
     /**
@@ -216,15 +215,13 @@
         if (mNativeContextMenuHelper == 0) return;
         int maxSizePx = mActivity.getResources().getDimensionPixelSize(
                 R.dimen.context_menu_header_image_max_size);
-        Callback<byte[]> rawDataCallback = new Callback<byte[]>() {
+        Callback<Bitmap> bitmapCallback = new Callback<Bitmap>() {
             @Override
-            public void onResult(byte[] result) {
-                // TODO(tedchoc): Decode in separate process before launch.
-                Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length);
-                callback.onResult(bitmap);
+            public void onResult(Bitmap result) {
+                callback.onResult(result);
             }
         };
-        nativeRetrieveImage(mNativeContextMenuHelper, rawDataCallback, maxSizePx);
+        nativeRetrieveImageForContextMenu(mNativeContextMenuHelper, bitmapCallback, maxSizePx);
     }
 
     @Override
@@ -253,7 +250,9 @@
     private native void nativeOnStartDownload(
             long nativeContextMenuHelper, boolean isLink, boolean isDataReductionProxyEnabled);
     private native void nativeSearchForImage(long nativeContextMenuHelper);
-    private native void nativeRetrieveImage(
+    private native void nativeRetrieveImageForShare(
             long nativeContextMenuHelper, Callback<byte[]> callback, int maxSizePx);
+    private native void nativeRetrieveImageForContextMenu(
+            long nativeContextMenuHelper, Callback<Bitmap> callback, int maxSizePx);
     private native void nativeOnContextMenuClosed(long nativeContextMenuHelper);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java
index 36284a63..6e11f96 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/TabularContextMenuUi.java
@@ -273,7 +273,11 @@
      */
     public void onImageThumbnailRetrieved(Bitmap bitmap) {
         if (mHeaderImageView != null) {
-            mHeaderImageView.setImageBitmap(bitmap);
+            if (bitmap != null) {
+                mHeaderImageView.setImageBitmap(bitmap);
+            } else {
+                mHeaderImageView.setImageResource(R.drawable.sad_tab);
+            }
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
index 630e4c9..2f7049c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentApp.java
@@ -574,4 +574,9 @@
 
     @Override
     public void dismissInstrument() {}
+
+    @Override
+    public int getAdditionalAppTextResourceId() {
+        return 0;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
index 6b769b43..643b3a8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
@@ -7,11 +7,14 @@
 import android.os.Handler;
 import android.text.TextUtils;
 
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.payments.mojom.BasicCardNetwork;
+import org.chromium.payments.mojom.BasicCardType;
 import org.chromium.payments.mojom.PaymentItem;
 import org.chromium.payments.mojom.PaymentMethodData;
 
@@ -29,7 +32,11 @@
     /** The method name for any type of credit card. */
     public static final String BASIC_CARD_METHOD_NAME = "basic-card";
 
+    /** The total number of all possible card types (i.e., credit, debit, prepaid, unknown). */
+    private static final int TOTAL_NUMBER_OF_CARD_TYPES = 4;
+
     private final WebContents mWebContents;
+    private Set<Integer> mBasicCardTypes;
 
     /**
      * Builds a payment app backed by autofill cards.
@@ -50,11 +57,13 @@
 
         Set<String> basicCardSupportedNetworks =
                 convertBasicCardToNetworks(methodDataMap.get(BASIC_CARD_METHOD_NAME));
+        mBasicCardTypes = convertBasicCardToTypes(methodDataMap.get(BASIC_CARD_METHOD_NAME));
 
         for (int i = 0; i < cards.size(); i++) {
             CreditCard card = cards.get(i);
             AutofillProfile billingAddress = TextUtils.isEmpty(card.getBillingAddressId())
-                    ? null : pdm.getProfile(card.getBillingAddressId());
+                    ? null
+                    : pdm.getProfile(card.getBillingAddressId());
 
             if (billingAddress != null
                     && AutofillAddress.checkAddressCompletionStatus(
@@ -73,9 +82,18 @@
                 methodName = card.getBasicCardIssuerNetwork();
             }
 
-            if (methodName != null) {
-                instruments.add(new AutofillPaymentInstrument(
-                        mWebContents, card, billingAddress, methodName));
+            if (methodName != null && mBasicCardTypes.contains(card.getCardType())) {
+                // Whether this card matches the card type (credit, debit, prepaid) exactly. If the
+                // merchant requests all card types, then this is always true. If the merchant
+                // requests only a subset of card types, then this is false for "unknown" card
+                // types. The "unknown" card types is where Chrome is unable to determine the type
+                // of card. Cards that don't match the card type exactly cannot be pre-selected in
+                // the UI.
+                boolean matchesMerchantCardTypeExactly = card.getCardType() != CardType.UNKNOWN
+                        || mBasicCardTypes.size() == TOTAL_NUMBER_OF_CARD_TYPES;
+
+                instruments.add(new AutofillPaymentInstrument(mWebContents, card, billingAddress,
+                        methodName, matchesMerchantCardTypeExactly));
             }
         }
 
@@ -107,6 +125,29 @@
         return result;
     }
 
+    /**
+     * @return A set of card types (e.g., CardType.DEBIT, CardType.PREPAID)
+     * accepted by "basic-card" method.
+     */
+    public static Set<Integer> convertBasicCardToTypes(PaymentMethodData data) {
+        Set<Integer> result = new HashSet<>();
+        result.add(CardType.UNKNOWN);
+
+        Map<Integer, Integer> cardTypes = getCardTypes();
+        if (data == null || data.supportedTypes == null || data.supportedTypes.length == 0) {
+            // Merchant website supports all card types.
+            result.addAll(cardTypes.values());
+        } else {
+            // Merchant website supports some card types.
+            for (int i = 0; i < data.supportedTypes.length; i++) {
+                Integer cardType = cardTypes.get(data.supportedTypes[i]);
+                if (cardType != null) result.add(cardType);
+            }
+        }
+
+        return result;
+    }
+
     private static Map<Integer, String> getNetworks() {
         Map<Integer, String> networks = new HashMap<>();
         networks.put(BasicCardNetwork.AMEX, "amex");
@@ -120,6 +161,14 @@
         return networks;
     }
 
+    private static Map<Integer, Integer> getCardTypes() {
+        Map<Integer, Integer> cardTypes = new HashMap<>();
+        cardTypes.put(BasicCardType.CREDIT, CardType.CREDIT);
+        cardTypes.put(BasicCardType.DEBIT, CardType.DEBIT);
+        cardTypes.put(BasicCardType.PREPAID, CardType.PREPAID);
+        return cardTypes;
+    }
+
     @Override
     public Set<String> getAppMethodNames() {
         Set<String> methods = new HashSet<>(getNetworks().values());
@@ -151,4 +200,28 @@
     public String getAppIdentifier() {
         return "Chrome_Autofill_Payment_App";
     }
+
+    @Override
+    public int getAdditionalAppTextResourceId() {
+        // If the merchant has restricted the accepted card types (credit, debit, prepaid), then the
+        // list of payment instruments should include a message describing the accepted card types,
+        // e.g., "Debit cards are accepted" or "Debit and prepaid cards are accepted."
+        if (mBasicCardTypes == null || mBasicCardTypes.size() == TOTAL_NUMBER_OF_CARD_TYPES) {
+            return 0;
+        }
+
+        int credit = mBasicCardTypes.contains(CardType.CREDIT) ? 1 : 0;
+        int debit = mBasicCardTypes.contains(CardType.DEBIT) ? 1 : 0;
+        int prepaid = mBasicCardTypes.contains(CardType.PREPAID) ? 1 : 0;
+        int[][][] resourceIds = new int[2][2][2];
+        resourceIds[0][0][0] = 0;
+        resourceIds[0][0][1] = R.string.payments_prepaid_cards_are_accepted_label;
+        resourceIds[0][1][0] = R.string.payments_debit_cards_are_accepted_label;
+        resourceIds[0][1][1] = R.string.payments_debit_prepaid_cards_are_accepted_label;
+        resourceIds[1][0][0] = R.string.payments_credit_cards_are_accepted_label;
+        resourceIds[1][0][1] = R.string.payments_credit_prepaid_cards_are_accepted_label;
+        resourceIds[1][1][0] = R.string.payments_credit_debit_cards_are_accepted_label;
+        resourceIds[1][1][1] = 0;
+        return resourceIds[credit][debit][prepaid];
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
index 80d6156..94465d53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentInstrument.java
@@ -36,6 +36,7 @@
 public class AutofillPaymentInstrument extends PaymentInstrument
         implements FullCardRequestDelegate, NormalizedAddressRequestDelegate {
     private final WebContents mWebContents;
+    private final boolean mIsMatchingMerchantsRequestedCardType;
     private CreditCard mCard;
     private String mSecurityCode;
     @Nullable private AutofillProfile mBillingAddress;
@@ -48,19 +49,26 @@
     /**
      * Builds a payment instrument for the given credit card.
      *
-     * @param webContents    The web contents where PaymentRequest was invoked.
-     * @param card           The autofill card that can be used for payment.
-     * @param billingAddress The billing address for the card.
-     * @param methodName     The payment method name, e.g., "basic-card", "visa", amex", or null.
+     * @param webContents                    The web contents where PaymentRequest was invoked.
+     * @param card                           The autofill card that can be used for payment.
+     * @param billingAddress                 The billing address for the card.
+     * @param methodName                     The payment method name, e.g., "basic-card", "visa",
+     *                                       amex", or null.
+     * @param matchesMerchantCardTypeExactly Whether the card type (credit, debit, prepaid) matches
+     *                                       the type that the merchant has requested exactly. This
+     *                                       should be false for unknown card types, if the merchant
+     *                                       cannot accept some card types.
      */
     public AutofillPaymentInstrument(WebContents webContents, CreditCard card,
-            @Nullable AutofillProfile billingAddress, @Nullable String methodName) {
+            @Nullable AutofillProfile billingAddress, @Nullable String methodName,
+            boolean matchesMerchantCardTypeExactly) {
         super(card.getGUID(), card.getObfuscatedNumber(), card.getName(), null);
         mWebContents = webContents;
         mCard = card;
         mBillingAddress = billingAddress;
         mIsEditable = true;
         mMethodName = methodName;
+        mIsMatchingMerchantsRequestedCardType = matchesMerchantCardTypeExactly;
 
         Context context = ChromeActivity.fromWebContents(mWebContents);
         if (context == null) return;
@@ -91,6 +99,27 @@
     }
 
     @Override
+    public boolean isExactlyMatchingMerchantRequest() {
+        return mIsMatchingMerchantsRequestedCardType;
+    }
+
+    @Override
+    @Nullable
+    public String getCountryCode() {
+        return AutofillAddress.getCountryCode(mBillingAddress);
+    }
+
+    @Override
+    public boolean canMakePayment() {
+        return mHasValidNumberAndName; // Ignore absence of billing address.
+    }
+
+    @Override
+    public boolean canPreselect() {
+        return mIsComplete && mIsMatchingMerchantsRequestedCardType;
+    }
+
+    @Override
     public void invokePaymentApp(String unusedRequestId, String unusedMerchantName,
             String unusedOrigin, String unusedIFrameOrigin, byte[][] unusedCertificateChain,
             Map<String, PaymentMethodData> unusedMethodDataMap, PaymentItem unusedTotal,
@@ -234,14 +263,6 @@
     }
 
     /**
-     * @return Whether the card number is valid and name on card is non-empty. Billing address is
-     * not taken into consideration.
-     */
-    public boolean isValidCard() {
-        return mHasValidNumberAndName;
-    }
-
-    /**
      * Updates the instrument and marks it "complete." Called after the user has edited this
      * instrument.
      *
@@ -338,11 +359,6 @@
         return mCard;
     }
 
-    /** @return The billing address associated with this credit card. */
-    public AutofillProfile getBillingAddress() {
-        return mBillingAddress;
-    }
-
     @Override
     public String getPreviewString(String labelSeparator, int maxLength) {
         StringBuilder previewString = new StringBuilder(getLabel());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
index d092ca71..c48b16b1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
@@ -15,6 +15,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.CreditCardScanner;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
@@ -89,7 +90,7 @@
     /** The dropdown key that triggers the address editor to add a new billing address. */
     private static final String BILLING_ADDRESS_ADD_NEW = "add";
 
-    /** The shared preference for the 'save card to device' checkbox status*/
+    /** The shared preference for the 'save card to device' checkbox status. */
     private static final String CHECK_SAVE_CARD_TO_DEVICE = "check_save_card_to_device";
 
     /** The web contents where the web payments API is invoked. */
@@ -132,6 +133,11 @@
     private final Set<String> mAcceptedBasicCardIssuerNetworks;
 
     /**
+     * The accepted card types: CardType.UNKNOWN, CardType.CREDIT, CardType.DEBIT, CardType.PREPAID.
+     */
+    private final Set<Integer> mAcceptedBasicCardTypes;
+
+    /**
      * The information about the accepted card issuer networks. Used in the editor as a hint to the
      * user about the valid card issuer networks. This is important to keep in a list, because the
      * display order matters.
@@ -229,6 +235,7 @@
 
         mAcceptedIssuerNetworks = new HashSet<>();
         mAcceptedBasicCardIssuerNetworks = new HashSet<>();
+        mAcceptedBasicCardTypes = new HashSet<>();
         mAcceptedCardIssuerNetworks = new ArrayList<>();
         mHandler = new Handler();
 
@@ -313,6 +320,8 @@
                         addAcceptedNetwork(network);
                     }
                 }
+
+                mAcceptedBasicCardTypes.addAll(AutofillPaymentApp.convertBasicCardToTypes(data));
             }
         }
     }
@@ -356,7 +365,8 @@
         // Ensure that |instrument| and |card| are never null.
         final AutofillPaymentInstrument instrument = isNewCard
                 ? new AutofillPaymentInstrument(mWebContents, new CreditCard(),
-                          null /* billingAddress */, null /* methodName */)
+                          null /* billingAddress */, null /* methodName */,
+                          false /* matchesMerchantCardTypeExactly */)
                 : toEdit;
         final CreditCard card = instrument.getCard();
 
@@ -470,8 +480,7 @@
                 descriptions.add(mAcceptedCardIssuerNetworks.get(i).description);
             }
             mIconHint = EditorFieldModel.createIconList(
-                    mContext.getString(R.string.payments_accepted_cards_label), icons,
-                    descriptions);
+                    mContext.getString(getAcceptedCardsLabelResourceId()), icons, descriptions);
         }
         editor.addField(mIconHint);
 
@@ -584,6 +593,22 @@
         editor.addField(mYearField);
     }
 
+    private int getAcceptedCardsLabelResourceId() {
+        int credit = mAcceptedBasicCardTypes.contains(CardType.CREDIT) ? 1 : 0;
+        int debit = mAcceptedBasicCardTypes.contains(CardType.DEBIT) ? 1 : 0;
+        int prepaid = mAcceptedBasicCardTypes.contains(CardType.PREPAID) ? 1 : 0;
+        int[][][] resourceIds = new int[2][2][2];
+        resourceIds[0][0][0] = R.string.payments_accepted_cards_label;
+        resourceIds[0][0][1] = R.string.payments_accepted_prepaid_cards_label;
+        resourceIds[0][1][0] = R.string.payments_accepted_debit_cards_label;
+        resourceIds[0][1][1] = R.string.payments_accepted_debit_prepaid_cards_label;
+        resourceIds[1][0][0] = R.string.payments_accepted_credit_cards_label;
+        resourceIds[1][0][1] = R.string.payments_accepted_credit_prepaid_cards_label;
+        resourceIds[1][1][0] = R.string.payments_accepted_credit_debit_cards_label;
+        resourceIds[1][1][1] = R.string.payments_accepted_cards_label;
+        return resourceIds[credit][debit][prepaid];
+    }
+
     /** Builds the key-value pairs for the month dropdown. */
     private static List<DropdownKeyValue> buildMonthDropdownKeyValues(Calendar calendar) {
         List<DropdownKeyValue> result = new ArrayList<>();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java
index 8f729cf..f7c3c8d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentApp.java
@@ -79,4 +79,10 @@
      * @return The identifier for this payment app.
      */
     String getAppIdentifier();
+
+    /**
+     * @return The resource identifier for the additional text that should be displayed to the user
+     * when selecting a payment instrument from this payment app or 0 if not needed.
+     */
+    int getAdditionalAppTextResourceId();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java
index de4c93b..df6d3546 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentInstrument.java
@@ -91,6 +91,34 @@
     }
 
     /**
+     * @return Whether the instrument is exactly matching all filters provided by the merchant. For
+     * example, this can return false for unknown card types, if the merchant requested only debit
+     * cards.
+     */
+    public boolean isExactlyMatchingMerchantRequest() {
+        return true;
+    }
+
+    /** @return The country code (or null if none) associated with this payment instrument. */
+    @Nullable
+    public String getCountryCode() {
+        return null;
+    }
+
+    /**
+     * @return Whether presence of this payment instrument should cause the
+     * PaymentRequest.canMakePayment() to return true.
+     */
+    public boolean canMakePayment() {
+        return true;
+    }
+
+    /** @return Whether this payment instrument can be pre-selected for immediate payment. */
+    public boolean canPreselect() {
+        return true;
+    }
+
+    /**
      * Invoke the payment app to retrieve the instrument details.
      *
      * The callback will be invoked with the resulting payment details or error.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 8803762..d62de3bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -180,7 +180,7 @@
         public void addObserver(PaymentRequestImpl observer) {
             mObservers.add(observer);
         }
-    };
+    }
 
     /** Limit in the number of suggested items in a section. */
     public static final int SUGGESTIONS_LIMIT = 4;
@@ -197,22 +197,32 @@
             };
 
     /**
-     * Comparator to sort payment apps by maximum frecency score of the contained instruments. Note
-     * that the first instrument in the list must have the maximum frecency score.
+     * Sorts the payment instruments by several rules:
+     * Rule 1: Non-autofill before autofill.
+     * Rule 2: Complete instruments before incomplete intsruments.
+     * Rule 3: Exact type matching instruments before non-exact type matching instruments.
+     * Rule 4: Frequently and recently used instruments before rarely and non-recently used
+     *         instruments.
      */
-    private static final Comparator<List<PaymentInstrument>> APP_FRECENCY_COMPARATOR =
-            new Comparator<List<PaymentInstrument>>() {
-                @Override
-                public int compare(List<PaymentInstrument> a, List<PaymentInstrument> b) {
-                    return compareInstrumentsByFrecency(b.get(0), a.get(0));
-                }
-            };
-
-    /** Comparator to sort instruments in payment apps by frecency. */
-    private static final Comparator<PaymentInstrument> INSTRUMENT_FRECENCY_COMPARATOR =
+    private static final Comparator<PaymentInstrument> PAYMENT_INSTRUMENT_COMPARATOR =
             new Comparator<PaymentInstrument>() {
                 @Override
                 public int compare(PaymentInstrument a, PaymentInstrument b) {
+                    // Payment apps (not autofill) first.
+                    int autofill =
+                            (a.isAutofillInstrument() ? 1 : 0) - (b.isAutofillInstrument() ? 1 : 0);
+                    if (autofill != 0) return autofill;
+
+                    // Complete cards before cards with missing information.
+                    int completeness = (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0);
+                    if (completeness != 0) return completeness;
+
+                    // Cards with matching type before unknown type cards.
+                    int typeMatch = (b.isExactlyMatchingMerchantRequest() ? 1 : 0)
+                            - (a.isExactlyMatchingMerchantRequest() ? 1 : 0);
+                    if (typeMatch != 0) return typeMatch;
+
+                    // More frequently and recently used instruments first.
                     return compareInstrumentsByFrecency(b, a);
                 }
             };
@@ -311,8 +321,8 @@
     private ContactDetailsSection mContactSection;
     private List<PaymentApp> mApps;
     private List<PaymentApp> mPendingApps;
-    private List<List<PaymentInstrument>> mPendingInstruments;
-    private List<PaymentInstrument> mPendingAutofillInstruments;
+    private List<PaymentInstrument> mPendingInstruments;
+    private int mPaymentMethodsSectionAdditionalTextResourceId;
     private SectionInformation mPaymentMethodsSection;
     private PaymentRequestUI mUI;
     private Callback<PaymentInformation> mPaymentInformationCallback;
@@ -483,7 +493,8 @@
         mShouldSkipShowingPaymentRequestUi =
                 ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_PAYMENTS_SINGLE_APP_UI_SKIP)
                 && mMethodData.size() == 1 && !mRequestShipping && !mRequestPayerName
-                && !mRequestPayerPhone && !mRequestPayerEmail
+                && !mRequestPayerPhone
+                && !mRequestPayerEmail
                 // Only allowing payment apps that own their own UIs.
                 // This excludes AutofillPaymentApp as its UI is rendered inline in
                 // the payment request UI, thus can't be skipped.
@@ -692,13 +703,12 @@
 
         mPendingApps = new ArrayList<>(mApps);
         mPendingInstruments = new ArrayList<>();
-        mPendingAutofillInstruments = new ArrayList<>();
 
         Map<PaymentApp, Map<String, PaymentMethodData>> queryApps = new ArrayMap<>();
         for (int i = 0; i < mApps.size(); i++) {
             PaymentApp app = mApps.get(i);
-            Map<String, PaymentMethodData> appMethods = filterMerchantMethodData(mMethodData,
-                    app.getAppMethodNames());
+            Map<String, PaymentMethodData> appMethods =
+                    filterMerchantMethodData(mMethodData, app.getAppMethodNames());
             if (appMethods == null || !app.supportsMethodsAndData(appMethods)) {
                 mPendingApps.remove(app);
             } else {
@@ -851,7 +861,8 @@
     }
 
     /** @return The first modifier that matches the given instrument, or null. */
-    @Nullable private PaymentDetailsModifier getModifier(@Nullable PaymentInstrument instrument) {
+    @Nullable
+    private PaymentDetailsModifier getModifier(@Nullable PaymentInstrument instrument) {
         if (mModifiers == null || instrument == null) return null;
         // Makes a copy to ensure it is modifiable.
         Set<String> methodNames = new HashSet<>(instrument.getInstrumentMethodNames());
@@ -862,7 +873,7 @@
     /**
      * Converts a list of payment items and returns their parsed representation.
      *
-     * @param items     The payment items to parse. Can be null.
+     * @param items The payment items to parse. Can be null.
      * @return A list of valid line items.
      */
     private List<LineItem> getLineItems(@Nullable PaymentItem[] items) {
@@ -884,7 +895,7 @@
     /**
      * Converts a list of shipping options and returns their parsed representation.
      *
-     * @param options   The raw shipping options to parse. Can be null.
+     * @param options The raw shipping options to parse. Can be null.
      * @return The UI representation of the shipping options.
      */
     private SectionInformation getShippingOptions(@Nullable PaymentShippingOption[] options) {
@@ -1266,8 +1277,8 @@
         PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod;
         mPaymentAppRunning = true;
 
-        PaymentOption selectedContact = mContactSection != null ? mContactSection.getSelectedItem()
-                : null;
+        PaymentOption selectedContact =
+                mContactSection != null ? mContactSection.getSelectedItem() : null;
         mPaymentResponseHelper = new PaymentResponseHelper(
                 selectedShippingAddress, selectedShippingOption, selectedContact, this);
 
@@ -1477,31 +1488,28 @@
         if (mClient == null) return;
         mPendingApps.remove(app);
 
-        // Place the instruments into either "autofill" or "non-autofill" list to be displayed when
-        // all apps have responded.
         if (instruments != null) {
-            List<PaymentInstrument> nonAutofillInstruments = new ArrayList<>();
             for (int i = 0; i < instruments.size(); i++) {
                 PaymentInstrument instrument = instruments.get(i);
-                Set<String> instrumentMethodNames = new HashSet<>(
-                        instrument.getInstrumentMethodNames());
+                Set<String> instrumentMethodNames =
+                        new HashSet<>(instrument.getInstrumentMethodNames());
                 instrumentMethodNames.retainAll(mMethodData.keySet());
                 if (!instrumentMethodNames.isEmpty()) {
                     mHideServerAutofillInstruments |=
                             instrument.isServerAutofillInstrumentReplacement();
-                    if (instrument.isAutofillInstrument()) {
-                        mPendingAutofillInstruments.add(instrument);
-                    } else {
-                        nonAutofillInstruments.add(instrument);
-                    }
+                    mCanMakePayment |= instrument.canMakePayment();
+                    mPendingInstruments.add(instrument);
                 } else {
                     instrument.dismissInstrument();
                 }
             }
-            if (!nonAutofillInstruments.isEmpty()) {
-                Collections.sort(nonAutofillInstruments, INSTRUMENT_FRECENCY_COMPARATOR);
-                mPendingInstruments.add(nonAutofillInstruments);
-            }
+        }
+
+        int additionalTextResourceId = app.getAdditionalAppTextResourceId();
+        if (additionalTextResourceId != 0) {
+            assert mPaymentMethodsSectionAdditionalTextResourceId == 0;
+            assert app instanceof AutofillPaymentApp;
+            mPaymentMethodsSectionAdditionalTextResourceId = additionalTextResourceId;
         }
 
         // Some payment apps still have not responded. Continue waiting for them.
@@ -1510,61 +1518,41 @@
         if (disconnectIfNoPaymentMethodsSupported()) return;
 
         if (mHideServerAutofillInstruments) {
-            List<PaymentInstrument> localAutofillInstruments = new ArrayList<>();
-            for (int i = 0; i < mPendingAutofillInstruments.size(); i++) {
-                if (!mPendingAutofillInstruments.get(i).isServerAutofillInstrument()) {
-                    localAutofillInstruments.add(mPendingAutofillInstruments.get(i));
+            List<PaymentInstrument> nonServerAutofillInstruments = new ArrayList<>();
+            for (int i = 0; i < mPendingInstruments.size(); i++) {
+                if (!mPendingInstruments.get(i).isServerAutofillInstrument()) {
+                    nonServerAutofillInstruments.add(mPendingInstruments.get(i));
                 }
             }
-            mPendingAutofillInstruments = localAutofillInstruments;
+            mPendingInstruments = nonServerAutofillInstruments;
         }
 
         // Load the validation rules for each unique region code in the credit card billing
         // addresses and check for validity.
         Set<String> uniqueCountryCodes = new HashSet<>();
-        for (int i = 0; i < mPendingAutofillInstruments.size(); ++i) {
-            assert mPendingAutofillInstruments.get(i) instanceof AutofillPaymentInstrument;
-            AutofillPaymentInstrument creditCard =
-                    (AutofillPaymentInstrument) mPendingAutofillInstruments.get(i);
-
-            String countryCode = AutofillAddress.getCountryCode(creditCard.getBillingAddress());
-            if (!uniqueCountryCodes.contains(countryCode)) {
+        for (int i = 0; i < mPendingInstruments.size(); ++i) {
+            @Nullable
+            String countryCode = mPendingInstruments.get(i).getCountryCode();
+            if (countryCode != null && !uniqueCountryCodes.contains(countryCode)) {
                 uniqueCountryCodes.add(countryCode);
                 PersonalDataManager.getInstance().loadRulesForAddressNormalization(countryCode);
             }
-
-            // If there's a card on file with a valid number and a name, then
-            // PaymentRequest.canMakePayment() returns true.
-            mCanMakePayment |= creditCard.isValidCard();
         }
 
-        // List order:
-        // > Non-autofill instruments.
-        // > Complete autofill instruments.
-        // > Incomplete autofill instruments.
-        Collections.sort(mPendingAutofillInstruments, COMPLETENESS_COMPARATOR);
-        Collections.sort(mPendingInstruments, APP_FRECENCY_COMPARATOR);
-        if (!mPendingAutofillInstruments.isEmpty()) {
-            mPendingInstruments.add(mPendingAutofillInstruments);
-        }
+        Collections.sort(mPendingInstruments, PAYMENT_INSTRUMENT_COMPARATOR);
 
         // Log the number of suggested credit cards.
+        int numberOfAutofillInstruments = 0;
+        for (int i = 0; i < mPendingInstruments.size(); i++) {
+            if (mPendingInstruments.get(i).isAutofillInstrument()) numberOfAutofillInstruments++;
+        }
         mJourneyLogger.setNumberOfSuggestionsShown(
-                Section.CREDIT_CARDS, mPendingAutofillInstruments.size());
+                Section.CREDIT_CARDS, numberOfAutofillInstruments);
 
         // Possibly pre-select the first instrument on the list.
-        int selection = SectionInformation.NO_SELECTION;
-        if (!mPendingInstruments.isEmpty()) {
-            PaymentInstrument first = mPendingInstruments.get(0).get(0);
-            if (first instanceof AutofillPaymentInstrument) {
-                AutofillPaymentInstrument creditCard = (AutofillPaymentInstrument) first;
-                if (creditCard.isComplete()) selection = 0;
-            } else {
-                // If a payment app is available, then PaymentRequest.canMakePayment() returns true.
-                mCanMakePayment = true;
-                selection = 0;
-            }
-        }
+        int selection = !mPendingInstruments.isEmpty() && mPendingInstruments.get(0).canPreselect()
+                ? 0
+                : SectionInformation.NO_SELECTION;
 
         CanMakePaymentQuery query = sCanMakePaymentQueries.get(mPaymentRequestOrigin);
         if (query != null && query.matchesPaymentMethods(mMethodData)) {
@@ -1572,12 +1560,15 @@
         }
 
         // The list of payment instruments is ready to display.
-        List<PaymentInstrument> sortedInstruments = new ArrayList<>();
-        for (List<PaymentInstrument> a : mPendingInstruments) {
-            sortedInstruments.addAll(a);
+        mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PAYMENT_METHODS,
+                selection, new ArrayList<>(mPendingInstruments));
+        if (mPaymentMethodsSectionAdditionalTextResourceId != 0) {
+            Context context = ChromeActivity.fromWebContents(mWebContents);
+            if (context != null) {
+                mPaymentMethodsSection.setAdditionalText(
+                        context.getString(mPaymentMethodsSectionAdditionalTextResourceId));
+            }
         }
-        mPaymentMethodsSection = new SectionInformation(
-                PaymentRequestUI.TYPE_PAYMENT_METHODS, selection, sortedInstruments);
 
         mPendingInstruments.clear();
 
@@ -1597,8 +1588,8 @@
     private boolean disconnectIfNoPaymentMethodsSupported() {
         if (!isFinishedQueryingPaymentApps() || !mIsCurrentPaymentRequestShowing) return false;
 
-        boolean foundPaymentMethods = mPaymentMethodsSection != null
-                && !mPaymentMethodsSection.isEmpty();
+        boolean foundPaymentMethods =
+                mPaymentMethodsSection != null && !mPaymentMethodsSection.isEmpty();
         boolean userCanAddCreditCard = mMerchantSupportsAutofillPaymentInstruments
                 && !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD_ABORT);
 
@@ -1688,8 +1679,8 @@
         if (mShippingAddressesSection.getSelectedItem() == null) return;
 
         assert mShippingAddressesSection.getSelectedItem() instanceof AutofillAddress;
-        AutofillAddress selectedAddress = (AutofillAddress) mShippingAddressesSection
-                .getSelectedItem();
+        AutofillAddress selectedAddress =
+                (AutofillAddress) mShippingAddressesSection.getSelectedItem();
 
         // The label should only include the country if the view is focused.
         if (willFocus) {
@@ -1726,8 +1717,10 @@
         onAddressNormalized(profile);
     }
 
-    /** Starts the normalization of the new shipping address. Will call back into either
-     * onAddressNormalized or onCouldNotNormalize which will send the result to the merchant. */
+    /**
+     * Starts the normalization of the new shipping address. Will call back into either
+     * onAddressNormalized or onCouldNotNormalize which will send the result to the merchant.
+     */
     private void startShippingAddressChangeNormalization(AutofillAddress address) {
         PersonalDataManager.getInstance().normalizeAddress(
                 address.getProfile(), AutofillAddress.getCountryCode(address.getProfile()), this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java
index fedac13..7a73a7e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java
@@ -75,4 +75,9 @@
     public String getAppIdentifier() {
         return "Chrome_Service_Worker_Payment_App";
     }
+
+    @Override
+    public int getAdditionalAppTextResourceId() {
+        return 0;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index 8ff4cd7..658f0e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -1127,23 +1127,27 @@
 
     @Override
     public String getAdditionalText(PaymentRequestSection section) {
-        if (section != mShippingAddressSection) return null;
+        if (section == mShippingAddressSection) {
+            int selectedItemIndex = mShippingAddressSectionInformation.getSelectedItemIndex();
+            if (selectedItemIndex != SectionInformation.NO_SELECTION
+                    && selectedItemIndex != SectionInformation.INVALID_SELECTION) {
+                return null;
+            }
 
-        int selectedItemIndex = mShippingAddressSectionInformation.getSelectedItemIndex();
-        if (selectedItemIndex != SectionInformation.NO_SELECTION
-                && selectedItemIndex != SectionInformation.INVALID_SELECTION) {
+            String customErrorMessage = mShippingAddressSectionInformation.getErrorMessage();
+            if (selectedItemIndex == SectionInformation.INVALID_SELECTION
+                    && !TextUtils.isEmpty(customErrorMessage)) {
+                return customErrorMessage;
+            }
+
+            return mContext.getString(selectedItemIndex == SectionInformation.NO_SELECTION
+                            ? mShippingStrings.getSelectPrompt()
+                            : mShippingStrings.getUnsupported());
+        } else if (section == mPaymentMethodSection) {
+            return mPaymentMethodSectionInformation.getAdditionalText();
+        } else {
             return null;
         }
-
-        String customErrorMessage = mShippingAddressSectionInformation.getErrorMessage();
-        if (selectedItemIndex == SectionInformation.INVALID_SELECTION
-                && !TextUtils.isEmpty(customErrorMessage)) {
-            return customErrorMessage;
-        }
-
-        return mContext.getString(selectedItemIndex == SectionInformation.NO_SELECTION
-                        ? mShippingStrings.getSelectPrompt()
-                        : mShippingStrings.getUnsupported());
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java
index 2096ca3..6e3e93a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java
@@ -33,6 +33,8 @@
     protected ArrayList<PaymentOption> mItems;
     private int mSelectedItem;
     public String mErrorMessage;
+    @Nullable
+    public String mAddditionalText;
 
     /**
      * Builds an empty section without selection.
@@ -209,6 +211,17 @@
         return mErrorMessage;
     }
 
+    /** @param text The optional additional text to display in this section. */
+    public void setAdditionalText(String text) {
+        mAddditionalText = text;
+    }
+
+    /** @return The optional additional text to display in this section. */
+    @Nullable
+    public String getAdditionalText() {
+        return mAddditionalText;
+    }
+
     /**
      * Returns all the items in the section. Used for testing.
      *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
index 56454e9f..a9385c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
@@ -19,6 +19,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
@@ -184,7 +185,7 @@
                 cardNumber, "" /* obfuscatedNumber */,
                 String.valueOf(mExpirationMonth.getSelectedItemPosition() + 1),
                 (String) mExpirationYear.getSelectedItem(), "" /* basicCardPaymentType */,
-                0 /* issuerIconDrawableId */,
+                0 /* issuerIconDrawableId */, CardType.UNKNOWN,
                 ((AutofillProfile) mBillingAddress.getSelectedItem()).getGUID() /* billing */,
                 "" /* serverId */);
         personalDataManager.setCreditCard(card);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
index ba82c24..d67b0aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
@@ -22,6 +22,8 @@
 import org.chromium.chrome.browser.contextmenu.TabularContextMenuViewPager;
 import org.chromium.content.browser.RenderCoordinates;
 
+import javax.annotation.Nullable;
+
 /**
  * ContextMenuDialog is a subclass of AlwaysDismissedDialog that ensures that the proper scale
  * animation is played upon calling {@link #show()} and {@link #dismiss()}.
@@ -49,10 +51,11 @@
      * @param touchPointXPx The x-coordinate of the touch that triggered the context menu.
      * @param touchPointYPx The y-coordinate of the touch that triggered the context menu.
      * @param contentView The The {@link TabularContextMenuViewPager} to display on the dialog.
-     * @param renderCoordinates The render coordinates to get the y offset of the window.
+     * @param renderCoordinates The render coordinates to get the y offset of the window. This could
+     *                          be null if ContentViewCore is not available.
      */
     public ContextMenuDialog(Activity ownerActivity, int theme, float touchPointXPx,
-            float touchPointYPx, View contentView, RenderCoordinates renderCoordinates) {
+            float touchPointYPx, View contentView, @Nullable RenderCoordinates renderCoordinates) {
         super(ownerActivity, theme);
         mActivity = ownerActivity;
         mTouchPointXPx = touchPointXPx;
@@ -95,7 +98,9 @@
         window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
 
         float xOffsetPx = rectangle.left;
-        float yOffsetPx = rectangle.top + mRenderCoordinates.getContentOffsetYPix();
+        float contentOffsetYPx =
+                mRenderCoordinates != null ? mRenderCoordinates.getContentOffsetYPix() : 0;
+        float yOffsetPx = rectangle.top + contentOffsetYPx;
 
         int[] currentLocationOnScreenPx = new int[2];
         mContentView.getLocationOnScreen(currentLocationOnScreenPx);
@@ -159,8 +164,14 @@
         float fromY = fromX;
         float toY = toX;
 
-        ScaleAnimation animation = new ScaleAnimation(
-                fromX, toX, fromY, toY, Animation.ABSOLUTE, pivotX, Animation.ABSOLUTE, pivotY);
+        ScaleAnimation animation;
+        if (mRenderCoordinates == null) {
+            animation = new ScaleAnimation(fromX, toX, fromY, toY, Animation.RELATIVE_TO_SELF, 0.5f,
+                    Animation.RELATIVE_TO_SELF, 0.5f);
+        } else {
+            animation = new ScaleAnimation(
+                    fromX, toX, fromY, toY, Animation.ABSOLUTE, pivotX, Animation.ABSOLUTE, pivotY);
+        }
 
         long duration = isEnterAnimation ? ENTER_ANIMATION_DURATION_MS : EXIT_ANIMATION_DURATION_MS;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 322123d..dd7f609e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -30,6 +30,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -52,6 +53,7 @@
 import org.chromium.chrome.browser.widget.FadingBackgroundView;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController.ContentType;
 import org.chromium.chrome.browser.widget.textbubble.ViewAnchoredTextBubble;
+import org.chromium.content.browser.BrowserStartupController;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.UiUtils;
 
@@ -222,7 +224,7 @@
     private BottomToolbarPhone mDefaultToolbarView;
 
     /** Whether the {@link BottomSheet} and its children should react to touch events. */
-    private boolean mIsTouchEnabled = true;
+    private boolean mIsTouchEnabled;
 
     /** Whether the sheet is currently open. */
     private boolean mIsSheetOpen;
@@ -462,6 +464,17 @@
 
         mMetrics = new BottomSheetMetrics();
         addObserver(mMetrics);
+
+        BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                .addStartupCompletedObserver(new BrowserStartupController.StartupCallback() {
+                    @Override
+                    public void onSuccess(boolean alreadyStarted) {
+                        mIsTouchEnabled = true;
+                    }
+
+                    @Override
+                    public void onFailure() {}
+                });
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java
index 1e6c6d3..5201fba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java
@@ -166,8 +166,6 @@
 
         mIsShowingNewTabUi = false;
 
-        showTabSwitcherToolbarIfNecessary();
-
         if (mLayoutManager.overviewVisible()
                 && mTabModelSelector.isIncognitoSelected() != mSelectIncognitoModelOnClose
                 && (!mSelectIncognitoModelOnClose
@@ -178,16 +176,22 @@
             mBottomSheet.endTransitionAnimations();
         }
 
+        mHideOverviewOnClose = mHideOverviewOnClose
+                && mTabModelSelector.getCurrentModel().getCount() > 0
+                && mLayoutManager.overviewVisible();
+
         mTabModelSelector.getModel(false).setIsPendingTabAdd(false);
         mTabModelSelector.getModel(true).setIsPendingTabAdd(false);
 
         // Hide the overview after setting pendingTabAdd to false so that the StackLayout animation
         // knows which tab index is being selected and animates the tab stacks correctly.
-        if (mLayoutManager.overviewVisible() && mHideOverviewOnClose) {
+        if (mHideOverviewOnClose) {
             // TODO(twellington): Ideally we would start hiding the overview sooner. Modifications
             // are needed for the StackLayout to know which tab will be selected before the sheet is
             // closed so that it can animate properly.
             mLayoutManager.hideOverview(true);
+        } else {
+            showTabSwitcherToolbarIfNecessary();
         }
 
         mHideOverviewOnClose = false;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 9760b7e3..94f2e2b 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -328,8 +328,8 @@
       <message name="IDS_PAYMENT_APPS_USAGE_MESSAGE" desc="Message to explain the usage of the listed payment apps.">
         On some websites, you can pay with above supported payment apps on your device.
       </message>
-      <message name="IDS_AUTOFILL_CREDIT_CARDS_TITLE" desc="Title of the preference to list the user's credit cards that can be automatically filled into web page forms. [CHAR-LIMIT=32]">
-        Credit cards
+      <message name="IDS_AUTOFILL_CREDIT_CARDS_TITLE" desc="Title of the preference to list the user's cards that can be automatically filled into web page forms. These can be either credit, debit, or prepaid cards. [CHAR-LIMIT=32]">
+        Cards
       </message>
       <message name="IDS_AUTOFILL_CREATE_PROFILE" desc="Button that allows the user to create a new profile (which contains the user's name, address, etc) that will be automatically filled into web page forms. [CHAR-LIMIT=32]">
         Add address
@@ -337,11 +337,11 @@
       <message name="IDS_AUTOFILL_EDIT_PROFILE" desc="Button that allows the user to edit a profile (which contains the user's name, address, etc) that can be automatically filled into web page forms. [CHAR-LIMIT=32]">
         Edit address
       </message>
-      <message name="IDS_AUTOFILL_CREATE_CREDIT_CARD" desc="Button that allows the user to add a new credit card that will be automatically filled into web page forms. [CHAR-LIMIT=32]">
-        Add credit card
+      <message name="IDS_AUTOFILL_CREATE_CREDIT_CARD" desc="Button that allows the user to add a new card that will be automatically filled into web page forms. This can be either credit, debit, or prepaid card. [CHAR-LIMIT=32]">
+        Add card
       </message>
-      <message name="IDS_AUTOFILL_EDIT_CREDIT_CARD" desc="Button that allows the user to edit a credit card that can be automatically filled into web page forms. [CHAR-LIMIT=32]">
-        Edit credit card
+      <message name="IDS_AUTOFILL_EDIT_CREDIT_CARD" desc="Button that allows the user to edit a card that can be automatically filled into web page forms. This can be either credit, debit, or prepaid card. [CHAR-LIMIT=32]">
+        Edit card
       </message>
      <message name="IDS_AUTOFILL_PROFILE_EDITOR_COUNTRY" desc="Label for a spinner input field containing a list of countries or regions [CHAR-LIMIT=32]">
         Country/Region
@@ -355,8 +355,8 @@
       <message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_NAME" desc="Label for text input field containing the name on a credit card. [CHAR-LIMIT=32]">
         Name on card
       </message>
-      <message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_NUMBER" desc="Label for text input field containing a credit card number. [CHAR-LIMIT=32]">
-        Credit card number
+      <message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_NUMBER" desc="Label for text input field containing a card number. This can be a credit, debit, or prepaid card. [CHAR-LIMIT=32]">
+        Card number
       </message>
       <message name="IDS_AUTOFILL_CREDIT_CARD_EDITOR_EXPIRATION_DATE" desc="Label for text input field containing a credit card expiration date. [CHAR-LIMIT=32]">
         Expiration date
@@ -1344,7 +1344,7 @@
         Settings
       </message>
       <message name="IDS_PAYMENTS_INTEGRATION" desc="Title for preference which enables import of Google Payments data for Autofill.">
-        Credit cards and addresses using Google Payments
+        Cards and addresses using Google Payments
       </message>
       <message name="IDS_SYNC_ENCRYPTION" desc="Preference category name for sync encryption. [CHAR-LIMT=32]">
         Encryption
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index a13900f..a9bc2666 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1533,6 +1533,8 @@
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestLongIdTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDataUrlTest.java",
+  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java",
+  "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingMultipleAddressesTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
index ea160c7..6417f5a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -401,13 +401,13 @@
         // Create a local card and an identical server card.
         CreditCard card1 = new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
                 true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5",
-                "2020", "Visa", 0 /* issuerIconDrawableId */, "" /* billingAddressId */,
-                "" /* serverId */);
+                "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
+                "" /* billingAddressId */, "" /* serverId */);
 
         CreditCard card2 = new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
                 false /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5",
-                "2020", "Visa", 0 /* issuerIconDrawableId */, "" /* billingAddressId */,
-                "" /* serverId */);
+                "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
+                "" /* billingAddressId */, "" /* serverId */);
 
         mHelper.setCreditCard(card1);
         mHelper.addServerCreditCard(card2);
@@ -447,9 +447,9 @@
             throws InterruptedException, ExecutionException, TimeoutException {
         String guid = mHelper.setCreditCard(
                 new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                    true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "",
-                    "5", "2020", "Visa", 0 /* issuerIconDrawableId */, "" /* billingAddressId */,
-                    "" /* serverId */));
+                        true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234",
+                        "", "5", "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
+                        "" /* billingAddressId */, "" /* serverId */));
 
         // Make sure the credit card does not have the specific use stats form the start.
         Assert.assertTrue(1234 != mHelper.getCreditCardUseCountForTesting(guid));
@@ -496,11 +496,10 @@
     public void testRecordAndLogCreditCardUse()
             throws InterruptedException, ExecutionException, TimeoutException {
         String guid = mHelper.setCreditCard(
-                    new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                            true /* isLocal */, false /* isCached */, "John Doe",
-                            "1234123412341234", "", "5", "2020", "Visa",
-                            0 /* issuerIconDrawableId */, "" /* billingAddressId */,
-                            "" /* serverId */));
+                new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
+                        true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234",
+                        "", "5", "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
+                        "" /* billingAddressId */, "" /* serverId */));
 
         // Set specific use stats for the credit card.
         mHelper.setCreditCardUseStatsForTesting(guid, 1234, 1234);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java
index 2a32f46..6171127a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelperTest.java
@@ -19,6 +19,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.locale.LocaleManager.SearchEnginePromoType;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl;
 import org.chromium.chrome.browser.widget.RadioButtonLayout;
@@ -156,6 +157,7 @@
     @Test
     @SmallTest
     @UiThreadTest
+    @RetryOnFailure
     public void testListRandomization() {
         final int maxAttempts = 3;
         boolean succeeded = false;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
index 77e62fb..452d4fc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestAbortTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -47,7 +48,7 @@
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** If the user has not clicked "Pay" yet, then merchant's abort will succeed. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java
index ae6adbd..92882c1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBasicCardTest.java
@@ -10,6 +10,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 
@@ -35,7 +36,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
index 80a5ecf1..ee71e459 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -59,8 +60,8 @@
                 "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US",
                 "650-253-0000", "jon.doe@gmail.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
-                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card, profile1,
-                "" /* serverId */));
+                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
+                CardType.UNKNOWN, profile1, "" /* serverId */));
         String profile2 = helper.setProfile(new AutofillProfile("", "https://example.com", true,
                 "Rob Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "", "US",
                 "650-253-0000", "jon.doe@gmail.com", "en-US"));
@@ -94,8 +95,8 @@
 
         // This card has no billing address selected.
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jane Doe",
-                "4242424242424242", "1111", "12", "2050", "visa", R.drawable.visa_card, profile6,
-                "" /* serverId */));
+                "4242424242424242", "1111", "12", "2050", "visa", R.drawable.visa_card,
+                CardType.UNKNOWN, profile6, "" /* serverId */));
 
         // Assign use stats so that incomplete profiles have the highest frecency, profile2 has the
         // highest frecency and profile3 has the lowest among the complete profiles, and profile8
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
index ecbb6da3..c7626906 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestBillingAddressWithoutPhoneTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -61,7 +62,7 @@
                 "Los Angeles", "", "90291", "", "US", "", "jon.doe@gmail.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                address_without_phone, "" /* serverId */));
+                CardType.UNKNOWN, address_without_phone, "" /* serverId */));
         String address_with_phone = helper.setProfile(new AutofillProfile("", "https://example.com",
                 true, "Rob Phone", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
                 "US", "310-310-6000", "jon.doe@gmail.com", "en-US"));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
index 362acde..a2501ec 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryNoCardTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -47,9 +48,10 @@
             TimeoutException {
         // The user has an incomplete credit card on file. This is not sufficient for
         // canMakePayment() to return true.
-        new AutofillTestHelper().setCreditCard(new CreditCard("", "https://example.com", true, true,
-                "" /* nameOnCard */, "4111111111111111", "1111", "12", "2050", "visa",
-                R.drawable.visa_card, "" /* billingAddressId */, "" /* serverId */));
+        new AutofillTestHelper().setCreditCard(
+                new CreditCard("", "https://example.com", true, true, "" /* nameOnCard */,
+                        "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
+                        CardType.UNKNOWN, "" /* billingAddressId */, "" /* serverId */));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
index 139c647..e56f8490 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCanMakePaymentQueryTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -49,7 +50,7 @@
         // for canMakePayment() to return true.
         new AutofillTestHelper().setCreditCard(new CreditCard("", "https://example.com", true, true,
                 "Jon Doe", "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                "" /* billingAddressId */, "" /* serverId */));
+                CardType.UNKNOWN, "" /* billingAddressId */, "" /* serverId */));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
index 65adf11..54bf1ae 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCardEditorAutoAdvanceTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -54,7 +55,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "1", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java
index 2188897b..472e3a3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryNoCardTest.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -42,9 +43,10 @@
             TimeoutException {
         // The user has an incomplete credit card on file. This is not sufficient for
         // canMakePayment() to return true.
-        new AutofillTestHelper().setCreditCard(new CreditCard("", "https://example.com", true, true,
-                "" /* nameOnCard */, "4111111111111111", "1111", "12", "2050", "visa",
-                R.drawable.visa_card, "" /* billingAddressId */, "" /* serverId */));
+        new AutofillTestHelper().setCreditCard(
+                new CreditCard("", "https://example.com", true, true, "" /* nameOnCard */,
+                        "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
+                        CardType.UNKNOWN, "" /* billingAddressId */, "" /* serverId */));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryTest.java
index 9e98dbe..ee504c9e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestCcCanMakePaymentQueryTest.java
@@ -9,6 +9,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 
 import java.util.concurrent.ExecutionException;
@@ -31,7 +32,7 @@
         // for canMakePayment() to return true.
         new AutofillTestHelper().setCreditCard(new CreditCard("", "https://example.com", true, true,
                 "Jon Doe", "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                "" /* billingAddressId */, "" /* serverId */));
+                CardType.UNKNOWN, "" /* billingAddressId */, "" /* serverId */));
     }
 
     @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
index 2dd0dea..c85923c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -52,7 +53,7 @@
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java
new file mode 100644
index 0000000..e750d92
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDebitTest.java
@@ -0,0 +1,100 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A payment integration test for a merchant that requests debit card payment. The user has a debit
+ * card on file.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({
+        ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG,
+})
+public class PaymentRequestDebitTest implements MainActivityStartCallback {
+    @Rule
+    public PaymentRequestTestRule mPaymentRequestTestRule =
+            new PaymentRequestTestRule("payment_request_debit_test.html", this);
+
+    @Override
+    public void onMainActivityStarted()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        AutofillTestHelper helper = new AutofillTestHelper();
+        String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
+                true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
+                "US", "555-555-5555", "jon.doe@google.com", "en-US"));
+
+        // Should be pre-selected:
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
+                CardType.DEBIT, billingAddressId, "server-id-1"));
+
+        // Should be available, but never pre-selected:
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "6011111111111117", "1117", "12", "2050", "discover", R.drawable.discover_card,
+                CardType.UNKNOWN, billingAddressId, "server-id-2"));
+
+        // Should not be available:
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "378282246310005", "0005", "12", "2050", "amex", R.drawable.amex_card,
+                CardType.CREDIT, billingAddressId, "server-id-3"));
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "5555555555554444", "4444", "12", "2050", "mastercard", R.drawable.mc_card,
+                CardType.PREPAID, billingAddressId, "server-id-4"));
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testDebitCardTypeIsPreselectedAndUnknownCardTypeIsAvailable()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay());
+
+        Assert.assertTrue(mPaymentRequestTestRule.getPaymentInstrumentLabel(0).contains("Visa"));
+
+        mPaymentRequestTestRule.clickInPaymentMethodAndWait(
+                R.id.payments_section, mPaymentRequestTestRule.getReadyToPay());
+        Assert.assertEquals(2, mPaymentRequestTestRule.getNumberOfPaymentInstruments());
+
+        Assert.assertTrue(mPaymentRequestTestRule.getPaymentInstrumentLabel(0).contains("Visa"));
+        Assert.assertTrue(
+                mPaymentRequestTestRule.getPaymentInstrumentLabel(1).contains("Discover"));
+
+        mPaymentRequestTestRule.clickAndWait(
+                R.id.close_button, mPaymentRequestTestRule.getDismissed());
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testCanMakePaymentWithDebitCard()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        mPaymentRequestTestRule.openPageAndClickNodeAndWait(
+                "canMakePayment", mPaymentRequestTestRule.getCanMakePaymentQueryResponded());
+        mPaymentRequestTestRule.expectResultContains(new String[] {"true"});
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java
new file mode 100644
index 0000000..4c860723
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDontHaveDebitTest.java
@@ -0,0 +1,96 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.support.test.filters.MediumTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A payment integration test for a merchant that requests debit card payment. The user does not
+ * have a debit card on file, but has one card that has "unknown" card type, which should not be
+ * pre-selected, but should be available for the user to select.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({
+        ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG,
+})
+public class PaymentRequestDontHaveDebitTest implements MainActivityStartCallback {
+    @Rule
+    public PaymentRequestTestRule mPaymentRequestTestRule =
+            new PaymentRequestTestRule("payment_request_debit_test.html", this);
+
+    @Override
+    public void onMainActivityStarted()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        AutofillTestHelper helper = new AutofillTestHelper();
+        String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
+                true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
+                "US", "555-555-5555", "jon.doe@google.com", "en-US"));
+
+        // Should be available, but never pre-selected:
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "6011111111111117", "1117", "12", "2050", "discover", R.drawable.discover_card,
+                CardType.UNKNOWN, billingAddressId, "server-id-2"));
+
+        // Should not be available:
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "378282246310005", "0005", "12", "2050", "amex", R.drawable.amex_card,
+                CardType.CREDIT, billingAddressId, "server-id-3"));
+        helper.addServerCreditCard(new CreditCard("", "https://example.com", false, true, "Jon Doe",
+                "5555555555554444", "4444", "12", "2050", "mastercard", R.drawable.mc_card,
+                CardType.PREPAID, billingAddressId, "server-id-4"));
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testUnknownCardTypeIsNotPreselectedButAvailable()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyForInput());
+
+        Assert.assertTrue(
+                mPaymentRequestTestRule.getPaymentInstrumentLabel(0).contains("Discover"));
+
+        mPaymentRequestTestRule.clickInPaymentMethodAndWait(
+                R.id.payments_section, mPaymentRequestTestRule.getReadyForInput());
+        Assert.assertEquals(1, mPaymentRequestTestRule.getNumberOfPaymentInstruments());
+
+        Assert.assertTrue(
+                mPaymentRequestTestRule.getPaymentInstrumentLabel(0).contains("Discover"));
+
+        mPaymentRequestTestRule.clickAndWait(
+                R.id.close_button, mPaymentRequestTestRule.getDismissed());
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testCanMakePaymentWithUnknownCardType()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        mPaymentRequestTestRule.openPageAndClickNodeAndWait(
+                "canMakePayment", mPaymentRequestTestRule.getCanMakePaymentQueryResponded());
+        mPaymentRequestTestRule.expectResultContains(new String[] {"true"});
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
index 172a934..a8cca016 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestDynamicShippingSingleAddressTest.java
@@ -19,6 +19,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -53,7 +54,7 @@
                 "US", "650-253-0000", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** The shipping address should not be selected in UI by default. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
index f97a45ae..a6d3f75 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestEmailAndFreeShippingTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -51,7 +52,7 @@
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** Submit the email and the shipping address to the merchant when the user clicks "Pay." */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
index 5288dc5..cda6b1c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExpiredLocalCardTest.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -54,7 +55,7 @@
         // Create an expired credit card
         mCreditCardId = mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true,
                 "Jon Doe", "4111111111111111", "1111", "1", "2016", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
index 8fbf9afe..d84ac5db 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestExtraShippingOptionsTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -48,7 +49,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
index b206d0e..72fafb8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFailCompleteTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -47,7 +48,7 @@
                 "US", "310-310-6000", "jon.doe@gmail.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
index f9f9d8c2..ef3af9a01 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -52,7 +53,7 @@
                 "US", "650-253-0000", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** Submit the shipping address to the merchant when the user clicks "Pay." */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
index 330687e4..a48656ef 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIdTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -48,7 +49,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
index 9b48730a..39599e07 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteServerCardTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -49,7 +50,8 @@
                 "US", "310-310-6000", "jon.doe@gmail.com", "en-US"));
         helper.addServerCreditCard(new CreditCard("", "https://example.com", false /* isLocal */,
                 true /* isCached */, "Jon Doe", "4111111111111111", "1111", "12", "2050", "visa",
-                R.drawable.visa_card, "" /* billing address */, "" /* serverId */));
+                R.drawable.visa_card, CardType.UNKNOWN, "" /* billing address */,
+                "" /* serverId */));
     }
 
     /** Click [PAY] and dismiss the card unmask dialog. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
index 3366756..475fe80 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestJourneyLoggerTest.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -53,14 +54,14 @@
                 "US", "650-253-0000", "", "en-US"));
         mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                mBillingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, mBillingAddressId, "" /* serverId */));
         // The user also has an incomplete address and an incomplete card saved.
         String mIncompleteAddressId = mHelper.setProfile(new AutofillProfile("",
                 "https://example.com", true, "In Complete", "Google", "344 Main St", "CA", "", "",
                 "90291", "", "US", "650-253-0000", "", "en-US"));
         mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "",
                 "4111111111111111", "1111", "18", "2075", "visa", R.drawable.visa_card,
-                mIncompleteAddressId, "" /* serverId */));
+                CardType.UNKNOWN, mIncompleteAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
index 3b5e81b84..3970e5f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
@@ -28,6 +28,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -61,7 +62,7 @@
                 "US", "650-253-0000", "", "en-US"));
         mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                mBillingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, mBillingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
index 0012910..dd203f5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -51,7 +52,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** Submit the payer name and shipping address to the merchant when the user clicks "Pay." */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
index d218179..f0c71a38 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -50,7 +51,7 @@
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
 
         // Add the same profile but with a different address.
         helper.setProfile(new AutofillProfile("", "https://example.com", true, "", "Google",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
index 5403a37..159270f1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java
@@ -25,6 +25,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -56,7 +57,7 @@
                 "US", "650-253-0000", "jon.doe@gmail.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** Click [X] to cancel payment. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
index 85673cc..f370f2c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndBasicCardWithModifiersTest.java
@@ -23,6 +23,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.test.ChromeActivityTestRule;
@@ -56,11 +57,11 @@
         // Mastercard card without a billing address.
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "5454545454545454", "", "12", "2050", "mastercard", R.drawable.mc_card,
-                "" /* billingAddressId */, "" /* serverId */));
+                CardType.UNKNOWN, "" /* billingAddressId */, "" /* serverId */));
         // Visa card with complete set of information.
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
index 67d311f..98cf15c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -54,11 +55,11 @@
         // Mastercard card without a billing address.
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "5454545454545454", "", "12", "2050", "mastercard", R.drawable.mc_card,
-                "" /* billingAddressId */, "" /* serverId */));
+                CardType.UNKNOWN, "" /* billingAddressId */, "" /* serverId */));
         // Visa card with complete set of information.
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
index 07b0d79..556da561 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java
@@ -28,7 +28,6 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.content_public.browser.WebContents;
 
-import java.util.Arrays;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -96,8 +95,7 @@
     @Feature({"Payments"})
     public void testPaymentWithInstrumentsAppResponseAfterDismissShouldNotCrash()
             throws InterruptedException, ExecutionException, TimeoutException {
-        final TestPay app = new TestPay(
-                Arrays.asList("https://bobpay.com"), HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
+        final TestPay app = new TestPay("https://bobpay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
         PaymentAppFactory.getInstance().addAdditionalFactory(new PaymentAppFactoryAddition() {
             @Override
             public void create(WebContents webContents, Set<String> methodNames,
@@ -127,8 +125,7 @@
     @Feature({"Payments"})
     public void testPaymentAppNoInstrumentsResponseAfterDismissShouldNotCrash()
             throws InterruptedException, ExecutionException, TimeoutException {
-        final TestPay app = new TestPay(
-                Arrays.asList("https://bobpay.com"), NO_INSTRUMENTS, IMMEDIATE_RESPONSE);
+        final TestPay app = new TestPay("https://bobpay.com", NO_INSTRUMENTS, IMMEDIATE_RESPONSE);
         PaymentAppFactory.getInstance().addAdditionalFactory(new PaymentAppFactoryAddition() {
             @Override
             public void create(WebContents webContents, Set<String> methodNames,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
index d969128..54ea441 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppsSortingTest.java
@@ -19,6 +19,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppCreatedCallback;
@@ -29,7 +30,6 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.content_public.browser.WebContents;
 
-import java.util.Arrays;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
@@ -56,7 +56,7 @@
         // behind non-autofill payment instruments in payment request.
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     @Test
@@ -67,43 +67,42 @@
         // Install a payment app with Bob Pay and Alice Pay, and another payment app with Charlie
         // Pay.
         final TestPay appA =
-                new TestPay(Arrays.asList("https://alicepay.com", "https://bobpay.com"),
-                        HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
-        final TestPay appB = new TestPay(
-                Arrays.asList("https://charliepay.com"), HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
+                new TestPay("https://alicepay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
+        final TestPay appB =
+                new TestPay("https://bobpay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
+        final TestPay appC =
+                new TestPay("https://charliepay.com", HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
         PaymentAppFactory.getInstance().addAdditionalFactory(new PaymentAppFactoryAddition() {
             @Override
             public void create(WebContents webContents, Set<String> methodNames,
                     PaymentAppCreatedCallback callback) {
                 callback.onPaymentAppCreated(appA);
                 callback.onPaymentAppCreated(appB);
+                callback.onPaymentAppCreated(appC);
                 callback.onAllPaymentAppsCreated();
             }
         });
-        String appAAlicePayId = appA.getAppIdentifier() + "https://alicepay.com";
-        String appABobPayId = appA.getAppIdentifier() + "https://bobpay.com";
-        String appBCharliePayId = appB.getAppIdentifier() + "https://charliepay.com";
+        String alicePayId = appA.getAppIdentifier() + "https://alicepay.com";
+        String bobPayId = appB.getAppIdentifier() + "https://bobpay.com";
+        String charliePayId = appC.getAppIdentifier() + "https://charliepay.com";
 
         // The initial records for all payment methods are zeroes.
-        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId));
-        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId));
+        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(alicePayId));
+        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(bobPayId));
+        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(charliePayId));
+        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(alicePayId));
+        Assert.assertEquals(0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(bobPayId));
         Assert.assertEquals(
-                0, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId));
-        Assert.assertEquals(
-                0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId));
-        Assert.assertEquals(
-                0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId));
-        Assert.assertEquals(
-                0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId));
+                0, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(charliePayId));
 
         // Sets Alice Pay use count and use date to 5. Sets Bob Pay use count and use date to 10.
         // Sets Charlie Pay use count and use date to 15.
-        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(appAAlicePayId, 5);
-        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(appAAlicePayId, 5);
-        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(appABobPayId, 10);
-        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(appABobPayId, 10);
-        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(appBCharliePayId, 15);
-        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(appBCharliePayId, 15);
+        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(alicePayId, 5);
+        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(alicePayId, 5);
+        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(bobPayId, 10);
+        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(bobPayId, 10);
+        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(charliePayId, 15);
+        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(charliePayId, 15);
 
         mPaymentRequestTestRule.triggerUIAndWait(mPaymentRequestTestRule.getReadyToPay());
         mPaymentRequestTestRule.clickInPaymentMethodAndWait(
@@ -126,20 +125,17 @@
                 R.id.button_secondary, mPaymentRequestTestRule.getDismissed());
 
         // Checks the records for all payment instruments haven't been changed.
-        Assert.assertEquals(5, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId));
-        Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId));
+        Assert.assertEquals(5, PaymentPreferencesUtil.getPaymentInstrumentUseCount(alicePayId));
+        Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(bobPayId));
+        Assert.assertEquals(15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(charliePayId));
+        Assert.assertEquals(5, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(alicePayId));
+        Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(bobPayId));
         Assert.assertEquals(
-                15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId));
-        Assert.assertEquals(
-                5, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId));
-        Assert.assertEquals(
-                10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId));
-        Assert.assertEquals(
-                15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId));
+                15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(charliePayId));
 
         // Sets Alice Pay use count and use date to 20.
-        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(appAAlicePayId, 20);
-        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(appAAlicePayId, 20);
+        PaymentPreferencesUtil.setPaymentInstrumentUseCountForTest(alicePayId, 20);
+        PaymentPreferencesUtil.setPaymentInstrumentLastUseDate(alicePayId, 20);
 
         mPaymentRequestTestRule.reTriggerUIAndWait("buy", mPaymentRequestTestRule.getReadyToPay());
         mPaymentRequestTestRule.clickInPaymentMethodAndWait(
@@ -151,9 +147,9 @@
         Assert.assertEquals(
                 "https://alicepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(0));
         Assert.assertEquals(
-                "https://bobpay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(1));
+                "https://charliepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(1));
         Assert.assertEquals(
-                "https://charliepay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(2));
+                "https://bobpay.com", mPaymentRequestTestRule.getPaymentInstrumentLabel(2));
         Assert.assertEquals(
                 "Visa\u0020\u0020\u2022\u2006\u2022\u2006\u2022\u2006\u2022\u20061111\nJon Doe",
                 mPaymentRequestTestRule.getPaymentInstrumentLabel(3));
@@ -166,16 +162,12 @@
 
         // Checks Alice Pay use count is increased by one after completing a payment request with
         // it.
+        Assert.assertEquals(21, PaymentPreferencesUtil.getPaymentInstrumentUseCount(alicePayId));
+        Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(bobPayId));
+        Assert.assertEquals(15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(charliePayId));
+        Assert.assertTrue(PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(alicePayId) > 20);
+        Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(bobPayId));
         Assert.assertEquals(
-                21, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appAAlicePayId));
-        Assert.assertEquals(10, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appABobPayId));
-        Assert.assertEquals(
-                15, PaymentPreferencesUtil.getPaymentInstrumentUseCount(appBCharliePayId));
-        Assert.assertTrue(
-                PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appAAlicePayId) > 20);
-        Assert.assertEquals(
-                10, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appABobPayId));
-        Assert.assertEquals(
-                15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(appBCharliePayId));
+                15, PaymentPreferencesUtil.getPaymentInstrumentLastUseDate(charliePayId));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
index 3015894..81b4ffb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneAndFreeShippingTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -51,7 +52,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** Submit the phone number and shipping address to the merchant when the user clicks "Pay." */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
index 4f35fb7a..92aaa94 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -54,7 +55,7 @@
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Alice",
                 "4111111111111111", "1111", "1", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
         helper.deleteProfile(billingAddressId);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
index 44ee6d60..b264337 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServerCardTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -48,7 +49,7 @@
         helper.addServerCreditCard(new CreditCard("4754d21d-8773-40b6-b4be-5f7486be834f",
                 "https://example.com", false /* isLocal */, true /* isCached */, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** Click [PAY] and dismiss the card unmask dialog. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
index 903ebe6d..45045e47 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressAndOptionTest.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -48,7 +49,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                firstAddressId, "" /* serverId */));
+                CardType.UNKNOWN, firstAddressId, "" /* serverId */));
 
         // The user has a second address.
         String secondAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
index 611230f..70288d17 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShippingAddressChangeTest.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -47,7 +48,7 @@
                 "", "US", "650-253-0000", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
index 5796c98..5f4d632 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestShowTwiceTest.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -48,7 +49,7 @@
                 "US", "555-555-5555", "", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
index 1ff76c0..b51c625e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTabTest.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -54,7 +55,7 @@
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
         helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
                 "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                billingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, billingAddressId, "" /* serverId */));
     }
 
     /** If the user switches tabs somehow, the dialog is dismissed. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
index 725fa4e..9bc4fc2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -15,7 +15,6 @@
 import org.chromium.chrome.browser.payments.ui.PaymentRequestUI;
 import org.chromium.chrome.test.ChromeActivityTestCaseBase;
 
-import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
@@ -457,7 +456,6 @@
         mTestCommon.onCardUnmaskPromptValidationDone(prompt);
     }
 
-
     /**
      * Installs a payment app for testing.
      *
@@ -499,12 +497,6 @@
         mTestCommon.installPaymentApp(methodName, instrumentPresence, responseSpeed, creationSpeed);
     }
 
-    protected void installPaymentApp(final List<String> appMethodNames,
-            final int instrumentPresence, final int responseSpeed, final int creationSpeed) {
-        mTestCommon.installPaymentApp(
-                appMethodNames, instrumentPresence, responseSpeed, creationSpeed);
-    }
-
     @Override
     public void startMainActivityWithURL(String url) throws InterruptedException {
         super.startMainActivityWithURL(url);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java
index 7d845bf3..e1c8ceb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.payments;
 
-import static java.util.Arrays.asList;
-
 import android.os.Handler;
 import android.view.KeyEvent;
 import android.view.View;
@@ -132,8 +130,9 @@
         mViewCoreRef = new AtomicReference<>();
         mWebContentsRef = new AtomicReference<>();
         mTestFilePath = testFileName.startsWith("data:")
-                ? testFileName : UrlUtils.getIsolatedTestFilePath(
-                        String.format("chrome/test/data/payments/%s", testFileName));
+                ? testFileName
+                : UrlUtils.getIsolatedTestFilePath(
+                          String.format("chrome/test/data/payments/%s", testFileName));
     }
 
     public void startMainActivity() throws InterruptedException {
@@ -900,18 +899,13 @@
         installPaymentApp(methodName, instrumentPresence, responseSpeed, IMMEDIATE_CREATION);
     }
 
-    void installPaymentApp(
-            String methodName, int instrumentPresence, int responseSpeed, int creationSpeed) {
-        installPaymentApp(asList(methodName), instrumentPresence, responseSpeed, creationSpeed);
-    }
-
-    void installPaymentApp(final List<String> appMethodNames,
-            final int instrumentPresence, final int responseSpeed, final int creationSpeed) {
+    void installPaymentApp(final String appMethodName, final int instrumentPresence,
+            final int responseSpeed, final int creationSpeed) {
         PaymentAppFactory.getInstance().addAdditionalFactory(new PaymentAppFactoryAddition() {
             @Override
             public void create(WebContents webContents, Set<String> methodNames,
                     final PaymentAppFactory.PaymentAppCreatedCallback callback) {
-                final TestPay app = new TestPay(appMethodNames, instrumentPresence, responseSpeed);
+                final TestPay app = new TestPay(appMethodName, instrumentPresence, responseSpeed);
                 if (creationSpeed == IMMEDIATE_CREATION) {
                     callback.onPaymentAppCreated(app);
                     callback.onAllPaymentAppsCreated();
@@ -930,13 +924,13 @@
 
     /** A payment app implementation for test. */
     static class TestPay implements PaymentApp {
-        private final List<String> mMethodNames;
+        private final String mDefaultMethodName;
         private final int mInstrumentPresence;
         private final int mResponseSpeed;
         private InstrumentsCallback mCallback;
 
-        TestPay(List<String> methodNames, int instrumentPresence, int responseSpeed) {
-            mMethodNames = methodNames;
+        TestPay(String defaultMethodName, int instrumentPresence, int responseSpeed) {
+            mDefaultMethodName = defaultMethodName;
             mInstrumentPresence = instrumentPresence;
             mResponseSpeed = responseSpeed;
         }
@@ -952,10 +946,8 @@
         void respond() {
             final List<PaymentInstrument> instruments = new ArrayList<>();
             if (mInstrumentPresence == HAVE_INSTRUMENTS) {
-                for (String methodName : mMethodNames) {
-                    instruments.add(
-                            new TestPayInstrument(getAppIdentifier(), methodName, methodName));
-                }
+                instruments.add(new TestPayInstrument(
+                        getAppIdentifier(), mDefaultMethodName, mDefaultMethodName));
             }
             Runnable instrumentsReady = new Runnable() {
                 @Override
@@ -973,9 +965,9 @@
 
         @Override
         public Set<String> getAppMethodNames() {
-            Set<String> methodNames = new HashSet<>();
-            methodNames.addAll(mMethodNames);
-            return methodNames;
+            Set<String> result = new HashSet<>();
+            result.add(mDefaultMethodName);
+            return result;
         }
 
         @Override
@@ -990,21 +982,26 @@
         public String getAppIdentifier() {
             return TestPay.this.toString();
         }
+
+        @Override
+        public int getAdditionalAppTextResourceId() {
+            return 0;
+        }
     }
 
     /** A payment instrument implementation for test. */
     private static class TestPayInstrument extends PaymentInstrument {
-        private final String mMethodName;
+        private final String mDefaultMethodName;
 
-        TestPayInstrument(String appId, String methodName, String label) {
-            super(appId + methodName, label, null, null);
-            mMethodName = methodName;
+        TestPayInstrument(String appId, String defaultMethodName, String label) {
+            super(appId + defaultMethodName, label, null, null);
+            mDefaultMethodName = defaultMethodName;
         }
 
         @Override
         public Set<String> getInstrumentMethodNames() {
             Set<String> result = new HashSet<>();
-            result.add(mMethodName);
+            result.add(mDefaultMethodName);
             return result;
         }
 
@@ -1014,8 +1011,7 @@
                 Map<String, PaymentMethodData> methodData, PaymentItem total,
                 List<PaymentItem> displayItems, Map<String, PaymentDetailsModifier> modifiers,
                 InstrumentDetailsCallback detailsCallback) {
-            detailsCallback.onInstrumentDetailsReady(
-                    mMethodName, "{\"transaction\": 1337}");
+            detailsCallback.onInstrumentDetailsReady(mDefaultMethodName, "{\"transaction\": 1337}");
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
index 97dc44dc..d3bf11a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -18,7 +18,6 @@
 import org.chromium.chrome.browser.payments.ui.PaymentRequestUI;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 
-import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
@@ -537,12 +536,6 @@
         mTestCommon.installPaymentApp(methodName, instrumentPresence, responseSpeed, creationSpeed);
     }
 
-    protected void installPaymentApp(final List<String> appMethodNames,
-            final int instrumentPresence, final int responseSpeed, final int creationSpeed) {
-        mTestCommon.installPaymentApp(
-                appMethodNames, instrumentPresence, responseSpeed, creationSpeed);
-    }
-
     @Override
     public void onMainActivityStarted()
             throws InterruptedException, ExecutionException, TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
index 4991fc1a..fa3db8b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUseStatsTest.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.payments.PaymentRequestTestRule.MainActivityStartCallback;
@@ -54,7 +55,7 @@
                 "US", "555-555-5555", "", "en-US"));
         mCreditCardId = mHelper.setCreditCard(new CreditCard("", "https://example.com", true, true,
                 "Jon Doe", "4111111111111111", "1111", "12", "2050", "visa", R.drawable.visa_card,
-                mBillingAddressId, "" /* serverId */));
+                CardType.UNKNOWN, mBillingAddressId, "" /* serverId */));
         // Set specific use stats for the profile and credit card.
         mHelper.setProfileUseStatsForTesting(mBillingAddressId, 20, 5000);
         mHelper.setCreditCardUseStatsForTesting(mCreditCardId, 1, 5000);
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
index 5d16701..d068de3 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
@@ -21,6 +21,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.preferences.Preferences;
@@ -740,7 +741,7 @@
                 boolean isLocal = false;
                 PersonalDataManager.getInstance().addServerCreditCardForTest(new CreditCard("",
                         "https://example.com", isLocal, false, "Jon Doe", "4111111111111111",
-                        "1111", "11", "20", "visa", 0, "" /* billingAddressId */,
+                        "1111", "11", "20", "visa", 0, CardType.UNKNOWN, "" /* billingAddressId */,
                         "025eb937c022489eb8dc78cbaa969218" /* serverId */));
             }
         });
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 80911310..d2d49d2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5456,8 +5456,8 @@
         </message>
       </if>
       <if expr="use_titlecase">
-        <message name="IDS_TOOLTIP_SAVE_CREDIT_CARD" desc="In Title Case: The tooltip for the icon that shows the save credit card bubble">
-          Save Credit Card
+        <message name="IDS_TOOLTIP_SAVE_CREDIT_CARD" desc="In Title Case: The tooltip for the icon that shows the save card bubble">
+          Save Card
         </message>
        </if>
       <message name="IDS_TOOLTIP_TRANSLATE" desc="The tooltip for translate">
@@ -6456,6 +6456,9 @@
         <message name="IDS_CHROME_CLEANUP_WEBUI_TITLE_RESTART" desc="A status message, appearing on the Chrome Cleanup web page, that the cleanup of unwanted software initiated by the user was performed but isn't finished. User must take additional action to finish the cleanup. 'Restart' is imperative. Short for 'To finish removing harmful software...'">
           To finish removing harmful software, restart your computer
         </message>
+        <message name="IDS_CHROME_CLEANUP_LOGS_PERMISSION" desc="A checkbox label, appearing on both the Chrome Cleanup dialog and web page, asking the user for permission to send some system information to Google in order to help with detection of harmful software. The word 'settings' refers to the user's operating system settings. The word 'applications' refers to any software that is installed or runs on the user's computer.">
+          Send information about your system and applications to Google to help detect harmful software
+        </message>
       </if>
 
       <!-- Settings reset prompt dialog messages -->
@@ -7584,8 +7587,8 @@
         <message name="IDS_AUTOFILL_ADDRESSES_GROUP_NAME" desc="The name of the Addresses group of the Autofill dialog.">
           Addresses
         </message>
-        <message name="IDS_AUTOFILL_CREDITCARDS_GROUP_NAME" desc="IThe name of the Credit Cards group of the Autofill dialog.">
-          Credit cards
+        <message name="IDS_AUTOFILL_CREDITCARDS_GROUP_NAME" desc="The name of the Cards group of the Autofill dialog.">
+          Cards
         </message>
         <message name="IDS_AUTOFILL_EDIT_ADDRESS_CAPTION" desc="The caption on the edit Autofill address dialog.">
           Edit address
@@ -7596,14 +7599,14 @@
         <message name="IDS_AUTOFILL_ADD_CONTACT_CAPTION" desc="The caption on the edit Autofill contact dialog for the new entry.">
           Add a contact
         </message>
-        <message name="IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION" desc="The caption on the edit Autofill credit card dialog.">
-          Edit credit card
+        <message name="IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION" desc="The caption on the edit Autofill card dialog. The card can be either credit, debit, or prepaid.">
+          Edit card
         </message>
-        <message name="IDS_AUTOFILL_ADD_CREDITCARD_CAPTION" desc="The caption on the edit Autofill credit card dialog the new entry.">
-          Add a credit card
+        <message name="IDS_AUTOFILL_ADD_CREDITCARD_CAPTION" desc="The caption on the edit Autofill card dialog the new entry. The card can be either credit, debit, or prepaid.">
+          Add a card
         </message>
         <message name="IDS_AUTOFILL_USE_PAYMENTS_DATA" desc="The text for the checkbox that controls the Autofill/Payments integration feature.">
-          Credit cards and addresses using Google Payments
+          Cards and addresses using Google Payments
         </message>
 
         <message name="IDS_AUTOFILL_FIELD_LABEL_EMAIL" desc="The label of the Email entry.">
@@ -7615,8 +7618,8 @@
         <message name="IDS_AUTOFILL_FIELD_LABEL_NAME_ON_CARD" desc="The label of the Name on card entry.">
           Name on card
         </message>
-        <message name="IDS_AUTOFILL_FIELD_LABEL_CREDIT_CARD_NUMBER" desc="The label of the Credit card number entry.">
-          Credit card number
+        <message name="IDS_AUTOFILL_FIELD_LABEL_CREDIT_CARD_NUMBER" desc="The label of the card number entry. This can be either credit, debit, or prepaid card.">
+          Card number
         </message>
         <message name="IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_DATE" desc="The label of the Expiration date entry.">
           Expiration date
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index f4ba64d..b918158 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -425,17 +425,17 @@
   <message name="IDS_SETTINGS_CREDIT_CARD_CLEAR" desc="Label for a context menu item clears the locally cached credit card that is also saved on Google Payments. Clicking this will NOT remove the credit card from Google Payments.">
    Clear copy
   </message>
-  <message name="IDS_SETTINGS_EDIT_CREDIT_CARD_TITLE" desc="The title for the dialog that's shown when editing a credit card.">
-    Edit credit card
+  <message name="IDS_SETTINGS_EDIT_CREDIT_CARD_TITLE" desc="The title for the dialog that's shown when editing a card. This can be either credit, debit, or prepaid card..">
+    Edit card
   </message>
-  <message name="IDS_SETTINGS_ADD_CREDIT_CARD_TITLE" desc="The title for the dialog that's shown when entering the information for a new credit card.">
-    Add credit card
+  <message name="IDS_SETTINGS_ADD_CREDIT_CARD_TITLE" desc="The title for the dialog that's shown when entering the information for a new card. This can be either credit, debit, or prepaid card.">
+    Add card
   </message>
   <message name="IDS_SETTINGS_NAME_ON_CREDIT_CARD" desc="The title for the input that lets users modify the name on the credit card.">
     Name on card
   </message>
-  <message name="IDS_SETTINGS_CREDIT_CARD_NUMBER" desc="The title for the input that lets users modify the credit card number for a credit card.">
-    Credit card number
+  <message name="IDS_SETTINGS_CREDIT_CARD_NUMBER" desc="The title for the input that lets users modify the number for a card. This can be either credit, debit, or prepaid card.">
+    Card number
   </message>
   <message name="IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE" desc="Label for the expiration date fields of a credit card that has been or is being saved.">
     Expiration date
@@ -446,8 +446,8 @@
   <message name="IDS_SETTINGS_CREDIT_CARD_EXPIRATION_YEAR" desc="Accessibility label on the year drop down to let users know the field corresponds to the expiration year">
     Expiration year
   </message>
-  <message name="IDS_SETTINGS_CREDIT_CARD_EXPIRED" desc="The error message that is shown when user attempts to enter or save an expired credit card.">
-    Your credit card is expired
+  <message name="IDS_SETTINGS_CREDIT_CARD_EXPIRED" desc="The error message that is shown when user attempts to enter or save an expired card.">
+    Your card is expired
   </message>
   <message name="IDS_SETTINGS_PASSWORDS" desc="Name for the password section and toggle">
     Manage passwords
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index 1427a83..2a27f7e 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -30,6 +30,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/common/referrer.h"
+#include "device/vr/features/features.h"
 #include "jni/DownloadController_jni.h"
 #include "net/base/filename_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -37,6 +38,10 @@
 #include "ui/android/window_android.h"
 #include "ui/base/page_transition_types.h"
 
+#if BUILDFLAG(ENABLE_VR)
+#include "chrome/browser/android/vr_shell/vr_tab_helper.h"
+#endif  // BUILDFLAG(ENABLE_VR)
+
 using base::android::ConvertUTF8ToJavaString;
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
@@ -218,6 +223,12 @@
     const DownloadControllerBase::AcquireFileAccessPermissionCallback& cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+#if BUILDFLAG(ENABLE_VR)
+  WebContents* web_contents = web_contents_getter.Run();
+  if (vr_shell::VrTabHelper::IsInVr(web_contents))
+    return;
+#endif
+
   if (HasFileAccessPermission()) {
     BrowserThread::PostTask(
         BrowserThread::UI, FROM_HERE, base::Bind(cb, true));
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index b8c6cc5..dec6059f4 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -3930,7 +3930,7 @@
                         WebViewScrollGuestContentTest,
                         testing::Values(false));
 
-#if defined(OS_WIN) || defined(OS_LINUX)
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
 #define MAYBE_ScrollGuestContent DISABLED_ScrollGuestContent
 #else
 #define MAYBE_ScrollGuestContent ScrollGuestContent
diff --git a/chrome/browser/autofill/android/personal_data_manager_android.cc b/chrome/browser/autofill/android/personal_data_manager_android.cc
index 875e77d..aaa36496 100644
--- a/chrome/browser/autofill/android/personal_data_manager_android.cc
+++ b/chrome/browser/autofill/android/personal_data_manager_android.cc
@@ -43,16 +43,16 @@
 #include "third_party/libaddressinput/chromium/chrome_metadata_source.h"
 #include "third_party/libaddressinput/chromium/chrome_storage_impl.h"
 
-using base::android::ConvertJavaStringToUTF8;
-using base::android::ConvertUTF16ToJavaString;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::JavaParamRef;
-using base::android::ScopedJavaGlobalRef;
-using base::android::ScopedJavaLocalRef;
-
 namespace autofill {
 namespace {
 
+using ::base::android::ConvertJavaStringToUTF8;
+using ::base::android::ConvertUTF16ToJavaString;
+using ::base::android::ConvertUTF8ToJavaString;
+using ::base::android::JavaParamRef;
+using ::base::android::ScopedJavaGlobalRef;
+using ::base::android::ScopedJavaLocalRef;
+
 Profile* GetProfile() {
   return ProfileManager::GetActiveUserProfile()->GetOriginalProfile();
 }
@@ -95,10 +95,9 @@
     profile->SetRawInfo(type, ConvertJavaStringToUTF16(jstr));
 }
 
-void PopulateNativeProfileFromJava(
-    const JavaParamRef<jobject>& jprofile,
-    JNIEnv* env,
-    AutofillProfile* profile) {
+void PopulateNativeProfileFromJava(const JavaParamRef<jobject>& jprofile,
+                                   JNIEnv* env,
+                                   AutofillProfile* profile) {
   profile->set_origin(
       ConvertJavaStringToUTF8(Java_AutofillProfile_getOrigin(env, jprofile)));
   profile->SetInfo(
@@ -153,14 +152,13 @@
       ConvertUTF8ToJavaString(env,
                               payment_request_data.basic_card_issuer_network),
       ResourceMapper::MapFromChromiumId(payment_request_data.icon_resource_id),
-      ConvertUTF8ToJavaString(env, card.billing_address_id()),
+      card.card_type(), ConvertUTF8ToJavaString(env, card.billing_address_id()),
       ConvertUTF8ToJavaString(env, card.server_id()));
 }
 
-void PopulateNativeCreditCardFromJava(
-    const jobject& jcard,
-    JNIEnv* env,
-    CreditCard* card) {
+void PopulateNativeCreditCardFromJava(const jobject& jcard,
+                                      JNIEnv* env,
+                                      CreditCard* card) {
   card->set_origin(
       ConvertJavaStringToUTF8(Java_CreditCard_getOrigin(env, jcard)));
   card->SetRawInfo(
@@ -180,6 +178,11 @@
   card->set_server_id(
       ConvertJavaStringToUTF8(Java_CreditCard_getServerId(env, jcard)));
 
+  jint card_type = Java_CreditCard_getCardType(env, jcard);
+  DCHECK_GE(CreditCard::CARD_TYPE_PREPAID, card_type);
+  DCHECK_LE(CreditCard::CARD_TYPE_UNKNOWN, card_type);
+  card->set_card_type(static_cast<CreditCard::CardType>(card_type));
+
   // Only set the guid if it is an existing card (java guid not empty).
   // Otherwise, keep the generated one.
   std::string guid =
@@ -374,8 +377,7 @@
     const JavaParamRef<jobject>& unused_obj,
     const JavaParamRef<jobject>& jprofile) {
   std::string guid = ConvertJavaStringToUTF8(
-      env,
-      Java_AutofillProfile_getGUID(env, jprofile).obj());
+      env, Java_AutofillProfile_getGUID(env, jprofile).obj());
 
   AutofillProfile profile;
   PopulateNativeProfileFromJava(jprofile, env, &profile);
@@ -499,7 +501,7 @@
     const JavaParamRef<jobject>& unused_obj,
     const JavaParamRef<jstring>& jguid) {
   CreditCard* card = personal_data_manager_->GetCreditCardByGUID(
-          ConvertJavaStringToUTF8(env, jguid));
+      ConvertJavaStringToUTF8(env, jguid));
   if (!card)
     return ScopedJavaLocalRef<jobject>();
 
@@ -520,9 +522,8 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& unused_obj,
     const JavaParamRef<jobject>& jcard) {
-  std::string guid = ConvertJavaStringToUTF8(
-       env,
-       Java_CreditCard_getGUID(env, jcard).obj());
+  std::string guid =
+      ConvertJavaStringToUTF8(env, Java_CreditCard_getGUID(env, jcard).obj());
 
   CreditCard card;
   PopulateNativeCreditCardFromJava(jcard, env, &card);
@@ -568,7 +569,7 @@
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& unused_obj,
     const base::android::JavaParamRef<jobject>& jcard) {
-  std::unique_ptr<CreditCard> card(new CreditCard);
+  std::unique_ptr<CreditCard> card = base::MakeUnique<CreditCard>();
   PopulateNativeCreditCardFromJava(jcard, env, card.get());
   card->set_record_type(CreditCard::MASKED_SERVER_CARD);
   personal_data_manager_->AddServerCreditCardForTest(std::move(card));
@@ -596,11 +597,11 @@
     const JavaParamRef<jobject>& jweb_contents,
     const JavaParamRef<jobject>& jcard,
     const JavaParamRef<jobject>& jdelegate) {
-  std::unique_ptr<CreditCard> card(new CreditCard);
+  std::unique_ptr<CreditCard> card = base::MakeUnique<CreditCard>();
   PopulateNativeCreditCardFromJava(jcard, env, card.get());
   // Self-deleting object.
-  (new FullCardRequester())->GetFullCard(
-      env, jweb_contents, jdelegate, std::move(card));
+  (new FullCardRequester())
+      ->GetFullCard(env, jweb_contents, jdelegate, std::move(card));
 }
 
 void PersonalDataManagerAndroid::OnPersonalDataChanged() {
@@ -815,7 +816,7 @@
   std::unique_ptr<std::vector<ServerFieldType>> suggested_fields;
   size_t minimal_fields_shown = 2;
   if (address_only) {
-    suggested_fields.reset(new std::vector<ServerFieldType>);
+    suggested_fields = base::MakeUnique<std::vector<ServerFieldType>>();
     if (include_name_in_label)
       suggested_fields->push_back(NAME_FULL);
     if (include_organization_in_label)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 91a86f0..4282bfe 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -611,47 +611,6 @@
   return true;
 }
 
-// Handles rewriting Web UI URLs.
-bool HandleWebUI(GURL* url, content::BrowserContext* browser_context) {
-  // Rewrite chrome://help and chrome://chrome to chrome://settings/help.
-  if (url->host() == chrome::kChromeUIHelpHost ||
-      (url->host() == chrome::kChromeUIUberHost &&
-       (url->path().empty() || url->path() == "/"))) {
-    *url = ReplaceURLHostAndPath(*url, chrome::kChromeUISettingsHost,
-                                 chrome::kChromeUIHelpHost);
-    return true;  // Return true to update the displayed URL.
-  }
-
-  if (!ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
-          browser_context, *url)) {
-    return false;
-  }
-
-#if defined(OS_CHROMEOS)
-  // Special case : in ChromeOS in Guest mode bookmarks and history are
-  // disabled for security reasons. New tab page explains the reasons, so
-  // we redirect user to new tab page.
-  if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) {
-    if (url->SchemeIs(content::kChromeUIScheme) &&
-        (url->DomainIs(chrome::kChromeUIBookmarksHost) ||
-         url->DomainIs(chrome::kChromeUIHistoryHost))) {
-      // Rewrite with new tab URL
-      *url = GURL(chrome::kChromeUINewTabURL);
-    }
-  }
-#endif
-
-  return true;
-}
-
-// Reverse URL handler for Web UI. Maps "chrome://chrome/foo/" to
-// "chrome://foo/".
-bool HandleWebUIReverse(GURL* url, content::BrowserContext* browser_context) {
-  // No need to actually reverse-rewrite the URL, but return true to update the
-  // displayed URL when rewriting chrome://help to chrome://settings/help.
-  return url->host() == chrome::kChromeUISettingsHost;
-}
-
 bool CertMatchesFilter(const net::X509Certificate& cert,
                        const base::DictionaryValue& filter) {
   // TODO(markusheintz): This is the minimal required filter implementation.
@@ -2670,7 +2629,8 @@
 #endif
 
   // chrome: & friends.
-  handler->AddHandlerPair(&HandleWebUI, &HandleWebUIReverse);
+  handler->AddHandlerPair(&ChromeContentBrowserClient::HandleWebUI,
+                          &ChromeContentBrowserClient::HandleWebUIReverse);
 }
 
 base::FilePath ChromeContentBrowserClient::GetDefaultDownloadDirectory() {
@@ -3466,6 +3426,53 @@
   return result;
 }
 
+// Static; handles rewriting Web UI URLs.
+bool ChromeContentBrowserClient::HandleWebUI(
+    GURL* url,
+    content::BrowserContext* browser_context) {
+  // Rewrite chrome://help and chrome://chrome to chrome://settings/help.
+  if (url->SchemeIs(content::kChromeUIScheme) &&
+      (url->host() == chrome::kChromeUIHelpHost ||
+       (url->host() == chrome::kChromeUIUberHost &&
+        (url->path().empty() || url->path() == "/")))) {
+    *url = ReplaceURLHostAndPath(*url, chrome::kChromeUISettingsHost,
+                                 chrome::kChromeUIHelpHost);
+    return true;  // Return true to update the displayed URL.
+  }
+
+  if (!ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
+          browser_context, *url)) {
+    return false;
+  }
+
+#if defined(OS_CHROMEOS)
+  // Special case : in ChromeOS in Guest mode bookmarks and history are
+  // disabled for security reasons. New tab page explains the reasons, so
+  // we redirect user to new tab page.
+  if (user_manager::UserManager::Get()->IsLoggedInAsGuest()) {
+    if (url->SchemeIs(content::kChromeUIScheme) &&
+        (url->DomainIs(chrome::kChromeUIBookmarksHost) ||
+         url->DomainIs(chrome::kChromeUIHistoryHost))) {
+      // Rewrite with new tab URL
+      *url = GURL(chrome::kChromeUINewTabURL);
+    }
+  }
+#endif
+
+  return true;
+}
+
+// Static; reverse URL handler for Web UI. Maps "chrome://chrome/foo/" to
+// "chrome://foo/".
+bool ChromeContentBrowserClient::HandleWebUIReverse(
+    GURL* url,
+    content::BrowserContext* browser_context) {
+  // No need to actually reverse-rewrite the URL, but return true to update the
+  // displayed URL when rewriting chrome://help to chrome://settings/help.
+  return url->SchemeIs(content::kChromeUIScheme) &&
+         url->host() == chrome::kChromeUISettingsHost;
+}
+
 // static
 void ChromeContentBrowserClient::SetDefaultQuotaSettingsForTesting(
     const storage::QuotaSettings* settings) {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index df9919aa..045c17c 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -328,6 +328,11 @@
   CreateURLLoaderThrottles(
       const base::Callback<content::WebContents*()>& wc_getter) override;
 
+ protected:
+  static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context);
+  static bool HandleWebUIReverse(GURL* url,
+                                 content::BrowserContext* browser_context);
+
  private:
   friend class DisableWebRtcEncryptionFlagTest;
   friend class InProcessBrowserTest;
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 53548f6..30df99e 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -350,3 +350,32 @@
   base::FilePath log_file_name;
   EXPECT_FALSE(client.GetLoggingFileName().empty());
 }
+
+class TestChromeContentBrowserClient : public ChromeContentBrowserClient {
+ public:
+  using ChromeContentBrowserClient::HandleWebUI;
+  using ChromeContentBrowserClient::HandleWebUIReverse;
+};
+
+TEST(ChromeContentBrowserClientTest, HandleWebUI) {
+  TestChromeContentBrowserClient test_content_browser_client;
+  const GURL http_help("http://help/");
+  GURL should_not_redirect = http_help;
+  test_content_browser_client.HandleWebUI(&should_not_redirect, nullptr);
+  EXPECT_EQ(http_help, should_not_redirect);
+
+  const GURL chrome_help("chrome://help/");
+  GURL should_redirect = chrome_help;
+  test_content_browser_client.HandleWebUI(&should_redirect, nullptr);
+  EXPECT_NE(chrome_help, should_redirect);
+}
+
+TEST(ChromeContentBrowserClientTest, HandleWebUIReverse) {
+  TestChromeContentBrowserClient test_content_browser_client;
+  GURL http_settings("http://settings/");
+  EXPECT_FALSE(
+      test_content_browser_client.HandleWebUIReverse(&http_settings, nullptr));
+  GURL chrome_settings("chrome://settings/");
+  EXPECT_TRUE(test_content_browser_client.HandleWebUIReverse(&chrome_settings,
+                                                             nullptr));
+}
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 9517024b..2e9944c6c 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -420,8 +420,8 @@
 
   NotifyAccessibilityStatusChanged(details);
 
-  ash::Shell::Get()->cursor_manager()->SetCursorSet(
-      enabled ? ui::CURSOR_SET_LARGE : ui::CURSOR_SET_NORMAL);
+  ash::Shell::Get()->cursor_manager()->SetCursorSize(
+      enabled ? ui::CursorSize::kLarge : ui::CursorSize::kNormal);
   ash::Shell::Get()->SetLargeCursorSizeInDip(large_cursor_size_in_dip);
   ash::Shell::Get()->SetCursorCompositingEnabled(
       ShouldEnableCursorCompositing());
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
index 5900062..277e8a18 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -35,8 +35,8 @@
     }
     aura::Window* GetActiveWindow() const override { return nullptr; }
     aura::Window* GetFocusedWindow() const override { return nullptr; }
-    ui::CursorSetType GetCursorSet() const override {
-      return ui::CursorSetType::CURSOR_SET_NORMAL;
+    ui::CursorSize GetCursorSize() const override {
+      return ui::CursorSize::kNormal;
     }
     const display::Display& GetCursorDisplay() const override {
       static const display::Display display;
diff --git a/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc b/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
index 7edc472..0368cd6 100644
--- a/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
+++ b/chrome/browser/ntp_tiles/chrome_popular_sites_factory.cc
@@ -6,23 +6,17 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/path_service.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/common/chrome_paths.h"
 #include "components/ntp_tiles/popular_sites_impl.h"
 #include "components/safe_json/safe_json_parser.h"
 #include "content/public/browser/browser_thread.h"
 
 std::unique_ptr<ntp_tiles::PopularSites>
 ChromePopularSitesFactory::NewForProfile(Profile* profile) {
-  base::FilePath directory;  // remains empty if PathService::Get() fails.
-  PathService::Get(chrome::DIR_USER_DATA, &directory);
   return base::MakeUnique<ntp_tiles::PopularSitesImpl>(
-      content::BrowserThread::GetBlockingPool(), profile->GetPrefs(),
-      TemplateURLServiceFactory::GetForProfile(profile),
+      profile->GetPrefs(), TemplateURLServiceFactory::GetForProfile(profile),
       g_browser_process->variations_service(), profile->GetRequestContext(),
-      directory, base::Bind(safe_json::SafeJsonParser::Parse));
+      base::Bind(safe_json::SafeJsonParser::Parse));
 }
diff --git a/chrome/browser/previews/previews_infobar_delegate.cc b/chrome/browser/previews/previews_infobar_delegate.cc
index 110f2088..3f87c2c 100644
--- a/chrome/browser/previews/previews_infobar_delegate.cc
+++ b/chrome/browser/previews/previews_infobar_delegate.cc
@@ -7,6 +7,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -34,6 +35,11 @@
 
 namespace {
 
+const char kMinStalenessParamName[] = "min_staleness_in_minutes";
+const char kMaxStalenessParamName[] = "max_staleness_in_minutes";
+const int kMinStalenessParamDefaultValue = 2;
+const int kMaxStalenessParamDefaultValue = 1440;
+
 void RecordPreviewsInfoBarAction(
     previews::PreviewsType previews_type,
     PreviewsInfoBarDelegate::PreviewsInfoBarAction action) {
@@ -47,6 +53,11 @@
       ->Add(static_cast<int32_t>(action));
 }
 
+void RecordStaleness(PreviewsInfoBarDelegate::PreviewsInfoBarTimestamp value) {
+  UMA_HISTOGRAM_ENUMERATION("Previews.InfoBarTimestamp", value,
+                            PreviewsInfoBarDelegate::TIMESTAMP_INDEX_BOUNDARY);
+}
+
 // Sends opt out information to the pingback service based on a key value in the
 // infobar tab helper. Sending this information in the case of a navigation that
 // should not send a pingback (or is not a server preview) will not alter the
@@ -245,14 +256,16 @@
   }
 
   int min_staleness_in_minutes = base::GetFieldTrialParamByFeatureAsInt(
-      previews::features::kStalePreviewsTimestamp, "min_staleness_in_minutes",
-      0);
+      previews::features::kStalePreviewsTimestamp, kMinStalenessParamName,
+      kMinStalenessParamDefaultValue);
   int max_staleness_in_minutes = base::GetFieldTrialParamByFeatureAsInt(
-      previews::features::kStalePreviewsTimestamp, "max_staleness_in_minutes",
-      0);
+      previews::features::kStalePreviewsTimestamp, kMaxStalenessParamName,
+      kMaxStalenessParamDefaultValue);
 
-  if (min_staleness_in_minutes == 0 || max_staleness_in_minutes == 0)
+  if (min_staleness_in_minutes <= 0 || max_staleness_in_minutes <= 0) {
+    NOTREACHED();
     return base::string16();
+  }
 
   base::Time network_time;
   if (g_browser_process->network_time_tracker()->GetNetworkTime(&network_time,
@@ -263,12 +276,22 @@
     network_time = base::Time::Now();
   }
 
+  if (network_time < previews_freshness_) {
+    RecordStaleness(TIMESTAMP_NOT_SHOWN_STALENESS_NEGATIVE);
+    return base::string16();
+  }
+
   int staleness_in_minutes = (network_time - previews_freshness_).InMinutes();
-  // TODO(megjablon): record metrics for out of bounds staleness.
-  if (staleness_in_minutes < min_staleness_in_minutes)
+  if (staleness_in_minutes < min_staleness_in_minutes) {
+    RecordStaleness(TIMESTAMP_NOT_SHOWN_PREVIEW_NOT_STALE);
     return base::string16();
-  if (staleness_in_minutes > max_staleness_in_minutes)
+  }
+  if (staleness_in_minutes > max_staleness_in_minutes) {
+    RecordStaleness(TIMESTAMP_NOT_SHOWN_STALENESS_GREATER_THAN_MAX);
     return base::string16();
+  }
+
+  RecordStaleness(TIMESTAMP_SHOWN);
 
   if (staleness_in_minutes < 60) {
     return l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/previews/previews_infobar_delegate.h b/chrome/browser/previews/previews_infobar_delegate.h
index 47245ea..09ccb493 100644
--- a/chrome/browser/previews/previews_infobar_delegate.h
+++ b/chrome/browser/previews/previews_infobar_delegate.h
@@ -35,6 +35,17 @@
     INFOBAR_INDEX_BOUNDARY
   };
 
+  // Values of the UMA Previews.InfoBarTimestamp histogram. This enum must
+  // remain synchronized with the enum of the same name in
+  // metrics/histograms/histograms.xml.
+  enum PreviewsInfoBarTimestamp {
+    TIMESTAMP_SHOWN = 0,
+    TIMESTAMP_NOT_SHOWN_PREVIEW_NOT_STALE = 1,
+    TIMESTAMP_NOT_SHOWN_STALENESS_NEGATIVE = 2,
+    TIMESTAMP_NOT_SHOWN_STALENESS_GREATER_THAN_MAX = 3,
+    TIMESTAMP_INDEX_BOUNDARY
+  };
+
   ~PreviewsInfoBarDelegate() override;
 
   // Creates a preview infobar and corresponding delegate and adds the infobar
diff --git a/chrome/browser/previews/previews_infobar_delegate_unittest.cc b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
index 107da1d9..49b3b0f 100644
--- a/chrome/browser/previews/previews_infobar_delegate_unittest.cc
+++ b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/previews/previews_infobar_delegate.h"
 
+#include <map>
 #include <memory>
 #include <string>
 
@@ -12,8 +13,10 @@
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_param_associator.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/optional.h"
+#include "base/strings/string16.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -71,6 +74,9 @@
 const char kUMAPreviewsInfoBarActionLitePage[] =
     "Previews.InfoBarAction.LitePage";
 
+// Key of the UMA Previews.InfoBarTimestamp histogram.
+const char kUMAPreviewsInfoBarTimestamp[] = "Previews.InfoBarTimestamp";
+
 class TestPreviewsWebContentsObserver
     : public content::WebContentsObserver,
       public content::WebContentsUserData<TestPreviewsWebContentsObserver> {
@@ -120,7 +126,8 @@
 class PreviewsInfoBarDelegateUnitTest : public ChromeRenderViewHostTestHarness {
  protected:
   PreviewsInfoBarDelegateUnitTest()
-      : field_trial_list_(new base::FieldTrialList(nullptr)) {}
+      : field_trial_list_(new base::FieldTrialList(nullptr)),
+        tester_(new base::HistogramTester()) {}
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
@@ -178,14 +185,15 @@
         infobar_service->infobar_at(0)->delegate());
   }
 
-  void EnableStalePreviewsTimestamp() {
+  void EnableStalePreviewsTimestamp(
+      const std::map<std::string, std::string>& variation_params) {
+    field_trial_list_.reset();
+    field_trial_list_.reset(new base::FieldTrialList(nullptr));
+    base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+
     const std::string kTrialName = "TrialName";
     const std::string kGroupName = "GroupName";
 
-    std::map<std::string, std::string> variation_params;
-    variation_params["min_staleness_in_minutes"] = "2";
-    variation_params["max_staleness_in_minutes"] = "1440";
-
     base::AssociateFieldTrialParams(kTrialName, kGroupName, variation_params);
     base::FieldTrial* field_trial =
         base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
@@ -197,6 +205,23 @@
     scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
   }
 
+  void TestStalePreviews(
+      int staleness_in_minutes,
+      base::string16 expected_timestamp,
+      PreviewsInfoBarDelegate::PreviewsInfoBarTimestamp expected_bucket) {
+    PreviewsInfoBarDelegate* infobar = CreateInfoBar(
+        previews::PreviewsType::LITE_PAGE,
+        base::Time::Now() - base::TimeDelta::FromMinutes(staleness_in_minutes),
+        true /* is_data_saver_user */);
+    EXPECT_EQ(expected_timestamp, infobar->GetTimestampText());
+    tester_->ExpectBucketCount(kUMAPreviewsInfoBarTimestamp, expected_bucket,
+                               1);
+    // Dismiss the infobar.
+    InfoBarService::FromWebContents(web_contents())->RemoveAllInfoBars(false);
+    PreviewsInfoBarTabHelper::FromWebContents(web_contents())
+        ->set_displayed_preview_infobar(false);
+  }
+
   void OnDismissPreviewsInfobar(bool user_opt_out) {
     user_opt_out_ = user_opt_out;
   }
@@ -211,11 +236,10 @@
   base::Optional<bool> user_opt_out_;
   std::unique_ptr<base::FieldTrialList> field_trial_list_;
   base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<base::HistogramTester> tester_;
 };
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, InfobarTestNavigationDismissal) {
-  base::HistogramTester tester;
-
   CreateInfoBar(previews::PreviewsType::LOFI, base::Time(),
                 true /* is_data_saver_user */);
 
@@ -232,7 +256,7 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   EXPECT_FALSE(user_opt_out_.value());
 
-  tester.ExpectBucketCount(
+  tester_->ExpectBucketCount(
       kUMAPreviewsInfoBarActionLoFi,
       PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_NAVIGATION, 1);
   EXPECT_EQ(0, drp_test_context_->pref_service()->GetInteger(
@@ -240,8 +264,6 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, InfobarTestReloadDismissal) {
-  base::HistogramTester tester;
-
   // Navigate to test URL, so we can reload later.
   NavigateAndCommit(GURL(kTestUrl));
 
@@ -264,9 +286,9 @@
   EXPECT_EQ(0U, infobar_service()->infobar_count());
   EXPECT_FALSE(user_opt_out_.value());
 
-  tester.ExpectBucketCount(kUMAPreviewsInfoBarActionLoFi,
-                           PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_RELOAD,
-                           1);
+  tester_->ExpectBucketCount(
+      kUMAPreviewsInfoBarActionLoFi,
+      PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_RELOAD, 1);
   EXPECT_EQ(0, drp_test_context_->pref_service()->GetInteger(
                    data_reduction_proxy::prefs::kLoFiLoadImagesPerSession));
 
@@ -280,8 +302,6 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, InfobarTestUserDismissal) {
-  base::HistogramTester tester;
-
   ConfirmInfoBarDelegate* infobar =
       CreateInfoBar(previews::PreviewsType::LOFI, base::Time(),
                     true /* is_data_saver_user */);
@@ -291,17 +311,15 @@
   infobar_service()->infobar_at(0)->RemoveSelf();
   EXPECT_EQ(0U, infobar_service()->infobar_count());
 
-  tester.ExpectBucketCount(kUMAPreviewsInfoBarActionLoFi,
-                           PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_USER,
-                           1);
+  tester_->ExpectBucketCount(kUMAPreviewsInfoBarActionLoFi,
+                             PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_USER,
+                             1);
   EXPECT_EQ(0, drp_test_context_->pref_service()->GetInteger(
                    data_reduction_proxy::prefs::kLoFiLoadImagesPerSession));
   EXPECT_FALSE(user_opt_out_.value());
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, InfobarTestTabClosedDismissal) {
-  base::HistogramTester tester;
-
   CreateInfoBar(previews::PreviewsType::LOFI, base::Time(),
                 true /* is_data_saver_user */);
 
@@ -309,7 +327,7 @@
   infobar_service()->infobar_at(0)->RemoveSelf();
   EXPECT_EQ(0U, infobar_service()->infobar_count());
 
-  tester.ExpectBucketCount(
+  tester_->ExpectBucketCount(
       kUMAPreviewsInfoBarActionLoFi,
       PreviewsInfoBarDelegate::INFOBAR_DISMISSED_BY_TAB_CLOSURE, 1);
   EXPECT_EQ(0, drp_test_context_->pref_service()->GetInteger(
@@ -325,6 +343,7 @@
       {true}, {false},
   };
   for (const auto test : tests) {
+    tester_.reset(new base::HistogramTester());
     drp_test_context_->config()->ResetLoFiStatusForTest();
     field_trial_list_.reset();
     field_trial_list_.reset(new base::FieldTrialList(nullptr));
@@ -332,7 +351,7 @@
       base::FieldTrialList::CreateFieldTrial(
           "DataReductionProxyPreviewsBlackListTransition", "Enabled_");
     }
-    base::HistogramTester tester;
+
     // Call Reload and CommitPendingNavigation to force DidFinishNavigation.
     web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
     content::WebContentsTester::For(web_contents())->CommitPendingNavigation();
@@ -346,7 +365,7 @@
       infobar_service()->infobar_at(0)->RemoveSelf();
     EXPECT_EQ(0U, infobar_service()->infobar_count());
 
-    tester.ExpectBucketCount(
+    tester_->ExpectBucketCount(
         kUMAPreviewsInfoBarActionLoFi,
         PreviewsInfoBarDelegate::INFOBAR_LOAD_ORIGINAL_CLICKED, 1);
     EXPECT_EQ(test.using_previews_blacklist ? 0 : 1,
@@ -364,8 +383,6 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, InfobarTestClickLinkLitePage) {
-  base::HistogramTester tester;
-
   NavigateAndCommit(GURL(kTestUrl));
 
   ConfirmInfoBarDelegate* infobar =
@@ -377,7 +394,7 @@
     infobar_service()->infobar_at(0)->RemoveSelf();
   EXPECT_EQ(0U, infobar_service()->infobar_count());
 
-  tester.ExpectBucketCount(
+  tester_->ExpectBucketCount(
       kUMAPreviewsInfoBarActionLitePage,
       PreviewsInfoBarDelegate::INFOBAR_LOAD_ORIGINAL_CLICKED, 1);
 
@@ -421,14 +438,12 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, LoFiInfobarTest) {
-  base::HistogramTester tester;
-
   ConfirmInfoBarDelegate* infobar =
       CreateInfoBar(previews::PreviewsType::LOFI, base::Time(),
                     true /* is_data_saver_user */);
 
-  tester.ExpectUniqueSample(kUMAPreviewsInfoBarActionLoFi,
-                            PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
+  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionLoFi,
+                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
   EXPECT_EQ(1, drp_test_context_->pref_service()->GetInteger(
                    data_reduction_proxy::prefs::kLoFiUIShownPerSession));
 
@@ -445,14 +460,12 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTest) {
-  base::HistogramTester tester;
-
   PreviewsInfoBarDelegate* infobar =
       CreateInfoBar(previews::PreviewsType::LITE_PAGE, base::Time(),
                     true /* is_data_saver_user */);
 
-  tester.ExpectUniqueSample(kUMAPreviewsInfoBarActionLitePage,
-                            PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
+  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionLitePage,
+                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
   EXPECT_EQ(1, drp_test_context_->pref_service()->GetInteger(
                    data_reduction_proxy::prefs::kLoFiUIShownPerSession));
 
@@ -471,14 +484,12 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, OfflineInfobarNonDataSaverUserTest) {
-  base::HistogramTester tester;
-
   PreviewsInfoBarDelegate* infobar =
       CreateInfoBar(previews::PreviewsType::OFFLINE, base::Time(),
                     false /* is_data_saver_user */);
 
-  tester.ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
-                            PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
+  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
+                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
   EXPECT_EQ(0, drp_test_context_->pref_service()->GetInteger(
                    data_reduction_proxy::prefs::kLoFiUIShownPerSession));
 
@@ -497,14 +508,12 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, OfflineInfobarDataSaverUserTest) {
-  base::HistogramTester tester;
-
   PreviewsInfoBarDelegate* infobar =
       CreateInfoBar(previews::PreviewsType::OFFLINE, base::Time(),
                     true /* is_data_saver_user */);
 
-  tester.ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
-                            PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
+  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
+                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
   EXPECT_EQ(0, drp_test_context_->pref_service()->GetInteger(
                    data_reduction_proxy::prefs::kLoFiUIShownPerSession));
 
@@ -523,8 +532,6 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, OfflineInfobarDisablesLoFi) {
-  base::HistogramTester tester;
-
   TestPreviewsWebContentsObserver::FromWebContents(web_contents())
       ->set_should_have_page_id(false);
 
@@ -534,8 +541,8 @@
       CreateInfoBar(previews::PreviewsType::OFFLINE, base::Time(),
                     true /* is_data_saver_user */);
 
-  tester.ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
-                            PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
+  tester_->ExpectUniqueSample(kUMAPreviewsInfoBarActionOffline,
+                              PreviewsInfoBarDelegate::INFOBAR_SHOWN, 1);
 
   // Simulate clicking the infobar link.
   if (infobar->LinkClicked(WindowOpenDisposition::CURRENT_TAB))
@@ -558,8 +565,6 @@
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, PingbackClientClearedTabClosed) {
-  base::HistogramTester tester;
-
   NavigateAndCommit(GURL(kTestUrl));
 
   ConfirmInfoBarDelegate* infobar =
@@ -571,7 +576,7 @@
     infobar_service()->infobar_at(0)->RemoveSelf();
   EXPECT_EQ(0U, infobar_service()->infobar_count());
 
-  tester.ExpectBucketCount(
+  tester_->ExpectBucketCount(
       kUMAPreviewsInfoBarActionLitePage,
       PreviewsInfoBarDelegate::INFOBAR_LOAD_ORIGINAL_CLICKED, 1);
 
@@ -608,47 +613,73 @@
                     ->OptOutsSizeForTesting());
 }
 
-TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTimestampMintuesTest) {
-  EnableStalePreviewsTimestamp();
-
+TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTimestampMinutesTest) {
+  // Use default params.
+  std::map<std::string, std::string> variation_params;
+  EnableStalePreviewsTimestamp(variation_params);
   int staleness_in_minutes = 5;
 
-  PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LITE_PAGE,
-      base::Time::Now() - base::TimeDelta::FromMinutes(staleness_in_minutes),
-      true /* is_data_saver_user */);
-
-  ASSERT_EQ(
+  TestStalePreviews(
+      staleness_in_minutes,
       l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES,
                                  base::IntToString16(staleness_in_minutes)),
-      infobar->GetTimestampText());
+      PreviewsInfoBarDelegate::TIMESTAMP_SHOWN);
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTimestampHourTest) {
-  EnableStalePreviewsTimestamp();
-
+  // Use default variation_params.
+  std::map<std::string, std::string> variation_params;
+  EnableStalePreviewsTimestamp(variation_params);
   int staleness_in_minutes = 65;
 
-  PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LITE_PAGE,
-      base::Time::Now() - base::TimeDelta::FromMinutes(staleness_in_minutes),
-      true /* is_data_saver_user */);
-
-  ASSERT_EQ(l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_ONE_HOUR),
-            infobar->GetTimestampText());
+  TestStalePreviews(
+      staleness_in_minutes,
+      l10n_util::GetStringUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_ONE_HOUR),
+      PreviewsInfoBarDelegate::TIMESTAMP_SHOWN);
 }
 
 TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTimestampHoursTest) {
-  EnableStalePreviewsTimestamp();
-
+  // Use default variation_params.
+  std::map<std::string, std::string> variation_params;
+  EnableStalePreviewsTimestamp(variation_params);
   int staleness_in_hours = 2;
 
-  PreviewsInfoBarDelegate* infobar = CreateInfoBar(
-      previews::PreviewsType::LITE_PAGE,
-      base::Time::Now() - base::TimeDelta::FromHours(staleness_in_hours),
-      true /* is_data_saver_user */);
+  TestStalePreviews(
+      staleness_in_hours * 60,
+      l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_HOURS,
+                                 base::IntToString16(staleness_in_hours)),
+      PreviewsInfoBarDelegate::TIMESTAMP_SHOWN);
+}
 
-  ASSERT_EQ(l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_HOURS,
-                                       base::IntToString16(staleness_in_hours)),
-            infobar->GetTimestampText());
+TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTimestampFinchParamsUMA) {
+  std::map<std::string, std::string> variation_params;
+  variation_params["min_staleness_in_minutes"] = "1";
+  variation_params["max_staleness_in_minutes"] = "5";
+  EnableStalePreviewsTimestamp(variation_params);
+
+  TestStalePreviews(
+      1,
+      l10n_util::GetStringFUTF16(IDS_PREVIEWS_INFOBAR_TIMESTAMP_MINUTES,
+                                 base::IntToString16(1)),
+      PreviewsInfoBarDelegate::TIMESTAMP_SHOWN);
+
+  TestStalePreviews(
+      6, base::string16(),
+      PreviewsInfoBarDelegate::TIMESTAMP_NOT_SHOWN_STALENESS_GREATER_THAN_MAX);
+}
+
+TEST_F(PreviewsInfoBarDelegateUnitTest, PreviewInfobarTimestampUMA) {
+  // Use default params.
+  std::map<std::string, std::string> variation_params;
+  EnableStalePreviewsTimestamp(variation_params);
+
+  TestStalePreviews(
+      1, base::string16(),
+      PreviewsInfoBarDelegate::TIMESTAMP_NOT_SHOWN_PREVIEW_NOT_STALE);
+  TestStalePreviews(
+      -1, base::string16(),
+      PreviewsInfoBarDelegate::TIMESTAMP_NOT_SHOWN_STALENESS_NEGATIVE);
+  TestStalePreviews(
+      1441, base::string16(),
+      PreviewsInfoBarDelegate::TIMESTAMP_NOT_SHOWN_STALENESS_GREATER_THAN_MAX);
 }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
index 7142a0e7..1f3f614f 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -445,9 +445,14 @@
         var target = newNode.firstChild;
         var length = 0;
         while (target && length < newIndex) {
-          if (length <= newIndex && newIndex < (length + target.name.length))
+          var newLength = length + target.name.length;
+
+          // Either |newIndex| falls between target's text or |newIndex| is the
+          // total length of all sibling text content.
+          if ((length <= newIndex && newIndex < newLength) ||
+              (newIndex == newLength && !target.nextSibling))
             break;
-          length += target.name.length;
+          length = newLength;
           target = target.nextSibling;
         }
         if (target) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
index fd8243ce..f0b8a9e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -462,3 +462,54 @@
     assertFalse(inlineTextBoxRange.contentEquals(rootRange));
   });
 });
+
+TEST_F('CursorsTest', 'DeepEquivalency', function() {
+  this.runWithLoadedTree(function() {/*!
+    <p style="word-spacing:100000px">this is a test</p>
+  */}, function(root) {
+    var textNode = root.find({role: RoleType.STATIC_TEXT});
+
+    var text = new cursors.Cursor(textNode, 2);
+    deep = text.deepEquivalent;
+    assertEquals('this ', deep.node.name);
+    assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+    assertEquals(2, deep.index);
+
+    text = new cursors.Cursor(textNode, 5);
+    deep = text.deepEquivalent;
+    assertEquals('is ', deep.node.name);
+    assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+    assertEquals(0, deep.index);
+
+    text = new cursors.Cursor(textNode, 7);
+    deep = text.deepEquivalent;
+    assertEquals('is ', deep.node.name);
+    assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+    assertEquals(2, deep.index);
+
+    text = new cursors.Cursor(textNode, 8);
+    deep = text.deepEquivalent;
+    assertEquals('a ', deep.node.name);
+    assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+    assertEquals(0, deep.index);
+
+    text = new cursors.Cursor(textNode, 11);
+    deep = text.deepEquivalent;
+    assertEquals('test', deep.node.name);
+    assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+    assertEquals(1, deep.index);
+
+    // This is the only selection that can be placed at the length of the node's
+    // text. This only happens at the end of a line.
+    text = new cursors.Cursor(textNode, 14);
+    deep = text.deepEquivalent;
+    assertEquals('test', deep.node.name);
+    assertEquals(RoleType.INLINE_TEXT_BOX, deep.node.role);
+    assertEquals(4, deep.index);
+
+    // However, any offset larger is invalid.
+    text = new cursors.Cursor(textNode, 15);
+    deep = text.deepEquivalent;
+    assertTrue(text.equals(deep));
+  });
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
index 4a729cb..fdaae352 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
@@ -391,9 +391,13 @@
 
   /** @override */
   describeSelectionChanged: function(evt) {
-    // Ignore end of text announcements.
-    if ((this.start + 1) == evt.start && evt.start == this.value.length)
+    // Note that since Chrome allows for selection to be placed immediately at
+    // the end of a line (i.e. end == value.length) and since we try to describe
+    // the character to the right, just describe it as a new line.
+    if ((this.start + 1) == evt.start && evt.start == this.value.length) {
+      this.speak('\n', evt.triggeredByUser);
       return;
+    }
 
     cvox.ChromeVoxEditableTextBase.prototype.describeSelectionChanged.call(
         this, evt);
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
index d743aa2..23bc7d14 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing_test.extjs
@@ -373,6 +373,43 @@
   });
 });
 
+TEST_F('EditingTest', 'RichTextMoveByCharacterEndOfLine', function() {
+  editing.useRichText = true;
+  var mockFeedback = this.createMockFeedback();
+  this.runWithLoadedTree(function() {/*!
+    <div id="go" role="textbox" contenteditable>Test</div>
+
+    <script>
+      document.getElementById('go').addEventListener('click', function() {
+        var sel = getSelection();
+        sel.modify('move', 'forward', 'character');
+      }, true);
+    </script>
+  */}, function(root) {
+    var input = root.find({role: RoleType.TEXT_FIELD});
+    var moveByChar = input.doDefault.bind(input);
+    var lineText = 'Test';
+
+    this.listenOnce(input, 'focus', function() {
+      mockFeedback.call(moveByChar)
+          .expectSpeech('e')
+          .expectBraille(lineText, { startIndex: 1, endIndex: 1 })
+          .call(moveByChar)
+          .expectSpeech('s')
+          .expectBraille(lineText, { startIndex: 2, endIndex: 2 })
+          .call(moveByChar)
+          .expectSpeech('t')
+          .expectBraille(lineText, { startIndex: 3, endIndex: 3 })
+          .call(moveByChar)
+          .expectSpeech('\n')
+          .expectBraille(lineText, { startIndex: 4, endIndex: 4 })
+
+          .replay();
+    });
+    input.focus();
+  });
+});
+
 TEST_F('EditingTest', 'EditableLineOneStaticText', function() {
   this.runWithLoadedTree(function() {/*!
     <p contenteditable style="word-spacing:100000px">this is a test</p>
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
index 46784e4..3cdefdf 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/live_regions.js
@@ -182,10 +182,25 @@
     else
       output.withQueueMode(cvox.QueueMode.QUEUE);
 
-    this.liveRegionNodeSet_.add(node);
+    // We also have to add recursively the children of this live region node
+    // since all children could potentially get described and we don't want to
+    // describe their tree changes especially during page load within the
+    // LiveRegions.LIVE_REGION_MIN_SAME_NODE_MS to prevent excessive chatter.
+    this.addNodeToNodeSetRecursive_(node);
+    window.prev = output;
     output.go();
     this.lastLiveRegionTime_ = currentTime;
   },
+
+  /**
+   * @param {AutomationNode} root
+   * @private
+   */
+  addNodeToNodeSetRecursive_: function(root) {
+    this.liveRegionNodeSet_.add(root);
+    for (var child = root.firstChild; child; child = child.nextSibling)
+      this.addNodeToNodeSetRecursive_(child);
+  },
 };
 
 });  // goog.scope
diff --git a/chrome/browser/thumbnails/thumbnail_service.h b/chrome/browser/thumbnails/thumbnail_service.h
index cf8290f..1fd87de 100644
--- a/chrome/browser/thumbnails/thumbnail_service.h
+++ b/chrome/browser/thumbnails/thumbnail_service.h
@@ -7,6 +7,7 @@
 
 #include "components/history/core/common/thumbnail_score.h"
 #include "components/keyed_service/core/refcounted_keyed_service.h"
+#include "ui/base/page_transition_types.h"
 #include "ui/gfx/image/image.h"
 
 class GURL;
@@ -56,7 +57,8 @@
   virtual void AddForcedURL(const GURL& url) = 0;
 
   // Returns true if the page thumbnail should be updated.
-  virtual bool ShouldAcquirePageThumbnail(const GURL& url) = 0;
+  virtual bool ShouldAcquirePageThumbnail(const GURL& url,
+                                          ui::PageTransition transition) = 0;
 
  protected:
   ~ThumbnailService() override {}
diff --git a/chrome/browser/thumbnails/thumbnail_service_impl.cc b/chrome/browser/thumbnails/thumbnail_service_impl.cc
index 603c1a21..fc4bc8c6 100644
--- a/chrome/browser/thumbnails/thumbnail_service_impl.cc
+++ b/chrome/browser/thumbnails/thumbnail_service_impl.cc
@@ -4,12 +4,14 @@
 
 #include "chrome/browser/thumbnails/thumbnail_service_impl.h"
 
+#include "base/feature_list.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/time/time.h"
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/history/top_sites_factory.h"
 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h"
 #include "chrome/browser/thumbnails/thumbnailing_context.h"
+#include "chrome/common/chrome_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
 
@@ -67,7 +69,6 @@
   if (!local_ptr)
     return;
 
-  // Adding
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                           base::Bind(AddForcedURLOnUIThread, local_ptr, url));
 }
@@ -77,7 +78,9 @@
   return new SimpleThumbnailCrop(gfx::Size(kThumbnailWidth, kThumbnailHeight));
 }
 
-bool ThumbnailServiceImpl::ShouldAcquirePageThumbnail(const GURL& url) {
+bool ThumbnailServiceImpl::ShouldAcquirePageThumbnail(
+    const GURL& url,
+    ui::PageTransition transition) {
   scoped_refptr<history::TopSites> local_ptr(top_sites_);
 
   if (!local_ptr)
@@ -86,20 +89,42 @@
   // Skip if the given URL is not appropriate for history.
   if (!CanAddURLToHistory(url))
     return false;
-  // Skip if the top sites list is full, and the URL is not known.
-  if (local_ptr->IsNonForcedFull() && !local_ptr->IsKnownURL(url))
-    return false;
-  // Skip if we don't have to udpate the existing thumbnail.
+  // If the URL is not known (i.e. not a top site yet), do some extra checks.
+  if (!local_ptr->IsKnownURL(url)) {
+    // Skip if the top sites list is full - no point in taking speculative
+    // thumbnails.
+    if (local_ptr->IsNonForcedFull())
+      return false;
+
+    if (base::FeatureList::IsEnabled(
+            features::kCaptureThumbnailDependingOnTransitionType)) {
+      // Skip if the transition type is not interesting:
+      // Only new segments (roughly "initial navigations", e.g. not clicks on a
+      // link) can end up in TopSites (see HistoryBackend::UpdateSegments).
+      // Note that for pages that are already in TopSites, we don't care about
+      // the transition type, since for those we know we'll need the thumbnail.
+      if (!ui::PageTransitionCoreTypeIs(transition,
+                                        ui::PAGE_TRANSITION_TYPED) &&
+          !ui::PageTransitionCoreTypeIs(transition,
+                                        ui::PAGE_TRANSITION_AUTO_BOOKMARK)) {
+        return false;
+      }
+    }
+  }
+
+  // Skip if we don't have to update the existing thumbnail.
   ThumbnailScore current_score;
   if (local_ptr->GetPageThumbnailScore(url, &current_score) &&
-      !current_score.ShouldConsiderUpdating())
+      !current_score.ShouldConsiderUpdating()) {
     return false;
+  }
   // Skip if we don't have to udpate the temporary thumbnail (i.e. the one
   // not yet saved).
   ThumbnailScore temporary_score;
   if (local_ptr->GetTemporaryPageThumbnailScore(url, &temporary_score) &&
-      !temporary_score.ShouldConsiderUpdating())
+      !temporary_score.ShouldConsiderUpdating()) {
     return false;
+  }
 
   return true;
 }
diff --git a/chrome/browser/thumbnails/thumbnail_service_impl.h b/chrome/browser/thumbnails/thumbnail_service_impl.h
index 19b29727..708ed16 100644
--- a/chrome/browser/thumbnails/thumbnail_service_impl.h
+++ b/chrome/browser/thumbnails/thumbnail_service_impl.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/thumbnails/thumbnail_service.h"
 #include "components/history/core/browser/top_sites.h"
+#include "ui/base/page_transition_types.h"
 
 namespace base {
 class RefCountedMemory;
@@ -31,7 +32,8 @@
                         bool prefix_match,
                         scoped_refptr<base::RefCountedMemory>* bytes) override;
   void AddForcedURL(const GURL& url) override;
-  bool ShouldAcquirePageThumbnail(const GURL& url) override;
+  bool ShouldAcquirePageThumbnail(const GURL& url,
+                                  ui::PageTransition transition) override;
 
   // Implementation of RefcountedKeyedService.
   void ShutdownOnUIThread() override;
diff --git a/chrome/browser/thumbnails/thumbnail_service_unittest.cc b/chrome/browser/thumbnails/thumbnail_service_unittest.cc
index 46423052..414bfee 100644
--- a/chrome/browser/thumbnails/thumbnail_service_unittest.cc
+++ b/chrome/browser/thumbnails/thumbnail_service_unittest.cc
@@ -9,8 +9,10 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/history/history_utils.h"
 #include "chrome/browser/history/top_sites_factory.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/history/core/browser/top_sites_impl.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -91,23 +93,35 @@
 
 }  // namespace
 
-TEST_F(ThumbnailServiceTest, ShouldUpdateThumbnail) {
+TEST_F(ThumbnailServiceTest, ShouldAcquireThumbnailOnlyForGoodUrl) {
   const GURL kGoodURL("http://www.google.com/");
   const GURL kBadURL("chrome://newtab");
+  const ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
 
   // Set up the mock profile along with mock top sites.
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   MockProfile profile;
 
   scoped_refptr<thumbnails::ThumbnailService> thumbnail_service(
       new thumbnails::ThumbnailServiceImpl(&profile));
 
   // Should be false because it's a bad URL.
-  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(kBadURL));
+  EXPECT_FALSE(
+      thumbnail_service->ShouldAcquirePageThumbnail(kBadURL, transition));
 
   // Should be true, as it's a good URL.
-  EXPECT_TRUE(thumbnail_service->ShouldAcquirePageThumbnail(kGoodURL));
+  EXPECT_TRUE(
+      thumbnail_service->ShouldAcquirePageThumbnail(kGoodURL, transition));
+}
+
+TEST_F(ThumbnailServiceTest, ShouldUpdateThumbnail) {
+  const GURL kGoodURL("http://www.google.com/");
+  const ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+
+  // Set up the mock profile along with mock top sites.
+  MockProfile profile;
+
+  scoped_refptr<thumbnails::ThumbnailService> thumbnail_service(
+      new thumbnails::ThumbnailServiceImpl(&profile));
 
   // Not checking incognito mode since the service wouldn't have been created
   // in that case anyway.
@@ -123,10 +137,12 @@
   // Should be false, as the top sites data is full, and the new URL is
   // not known.
   const GURL kAnotherGoodURL("http://www.youtube.com/");
-  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(kAnotherGoodURL));
+  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(kAnotherGoodURL,
+                                                             transition));
 
   // Should be true, as the existing thumbnail is bad (i.e. need a better one).
-  EXPECT_TRUE(thumbnail_service->ShouldAcquirePageThumbnail(kGoodURL));
+  EXPECT_TRUE(
+      thumbnail_service->ShouldAcquirePageThumbnail(kGoodURL, transition));
 
   // Replace the thumbnail score with a really good one.
   ThumbnailScore good_score;
@@ -139,5 +155,53 @@
 
   // Should be false, as the existing thumbnail is good enough (i.e. don't
   // need to replace the existing thumbnail which is new and good).
-  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(kGoodURL));
+  EXPECT_FALSE(
+      thumbnail_service->ShouldAcquirePageThumbnail(kGoodURL, transition));
+}
+
+TEST_F(ThumbnailServiceTest,
+       ShouldAcquireTempThumbnailDependingOnTransitionType) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(
+      features::kCaptureThumbnailDependingOnTransitionType);
+
+  const GURL kUnknownURL("http://www.google.com/");
+  const ui::PageTransition interesting_transition = ui::PAGE_TRANSITION_TYPED;
+  const ui::PageTransition uninteresting_transition = ui::PAGE_TRANSITION_LINK;
+
+  // Set up the mock profile along with mock top sites.
+  MockProfile profile;
+
+  scoped_refptr<thumbnails::ThumbnailService> thumbnail_service(
+      new thumbnails::ThumbnailServiceImpl(&profile));
+
+  // Top sites isn't full. We should acquire thumbnails of unknown URLs if they
+  // have an interesting page transition type.
+  EXPECT_TRUE(thumbnail_service->ShouldAcquirePageThumbnail(
+      kUnknownURL, interesting_transition));
+  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(
+      kUnknownURL, uninteresting_transition));
+
+  // Add a known URL. This makes the top sites data full.
+  const GURL kKnownURL("http://www.known.com/");
+  ThumbnailScore bad_score;
+  bad_score.time_at_snapshot = base::Time::UnixEpoch();  // Ancient time stamp.
+  profile.AddKnownURL(kKnownURL, bad_score);
+  scoped_refptr<history::TopSites> top_sites =
+      TopSitesFactory::GetForProfile(&profile);
+  ASSERT_TRUE(top_sites->IsNonForcedFull());
+
+  // Now top sites is full, so we shouldn't acquire any thumbnails of unknown
+  // URLs anymore, regardless of the transition type.
+  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(
+      kUnknownURL, interesting_transition));
+  EXPECT_FALSE(thumbnail_service->ShouldAcquirePageThumbnail(
+      kUnknownURL, uninteresting_transition));
+
+  // We should still take thumbnails of known URLs though, regardless of the
+  // transition type.
+  EXPECT_TRUE(thumbnail_service->ShouldAcquirePageThumbnail(
+      kKnownURL, interesting_transition));
+  EXPECT_TRUE(thumbnail_service->ShouldAcquirePageThumbnail(
+      kKnownURL, uninteresting_transition));
 }
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
index 118d51c..a2075b76 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/thumbnails/thumbnailing_algorithm.h"
 #include "chrome/common/chrome_features.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
@@ -35,7 +36,7 @@
 //    current tab is closed or another tab is clicked), update the
 //    thumbnail for the tab rendered by the renderer, if needed. The
 //    heuristics to judge whether or not to update the thumbnail is
-//    implemented in ShouldUpdateThumbnail().
+//    implemented in ThumbnailService::ShouldAcquirePageThumbnail().
 //    If features::kCaptureThumbnailOnLoadFinished is enabled, then a thumbnail
 //    may also be captured when a page load finishes (subject to the same
 //    heuristics).
@@ -47,6 +48,7 @@
     : content::WebContentsObserver(contents),
       capture_on_load_finished_(base::FeatureList::IsEnabled(
           features::kCaptureThumbnailOnLoadFinished)),
+      page_transition_(ui::PAGE_TRANSITION_LINK),
       load_interrupted_(false),
       weak_factory_(this) {
   // Even though we deal in RenderWidgetHosts, we only care about its
@@ -93,6 +95,28 @@
   }
 }
 
+void ThumbnailTabHelper::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsInMainFrame() ||
+      navigation_handle->IsSameDocument()) {
+    return;
+  }
+  // Reset the page transition to some uninteresting type, since the actual
+  // type isn't available at this point. We'll get it in DidFinishNavigation
+  // (if that happens, which isn't guaranteed).
+  page_transition_ = ui::PAGE_TRANSITION_LINK;
+}
+
+void ThumbnailTabHelper::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->HasCommitted() ||
+      !navigation_handle->IsInMainFrame() ||
+      navigation_handle->IsSameDocument()) {
+    return;
+  }
+  page_transition_ = navigation_handle->GetPageTransition();
+}
+
 void ThumbnailTabHelper::DidStartLoading() {
   load_interrupted_ = false;
 }
@@ -135,8 +159,8 @@
       ThumbnailServiceFactory::GetForProfile(profile);
 
   // Skip if we don't need to update the thumbnail.
-  if (thumbnail_service.get() == NULL ||
-      !thumbnail_service->ShouldAcquirePageThumbnail(url)) {
+  if (!thumbnail_service.get() ||
+      !thumbnail_service->ShouldAcquirePageThumbnail(url, page_transition_)) {
     return;
   }
 
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.h b/chrome/browser/thumbnails/thumbnail_tab_helper.h
index 1ea55e6..f48af331 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.h
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.h
@@ -14,8 +14,10 @@
 #include "content/public/browser/readback_types.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
+#include "ui/base/page_transition_types.h"
 
 namespace content {
+class NavigationHandle;
 class RenderViewHost;
 class RenderWidgetHost;
 }
@@ -38,6 +40,10 @@
 
   // content::WebContentsObserver overrides.
   void RenderViewDeleted(content::RenderViewHost* render_view_host) override;
+  void DidStartNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
   void DidStartLoading() override;
   void DidStopLoading() override;
   void NavigationStopped() override;
@@ -73,6 +79,7 @@
 
   content::NotificationRegistrar registrar_;
 
+  ui::PageTransition page_transition_;
   bool load_interrupted_;
 
   scoped_refptr<thumbnails::ThumbnailingContext> thumbnailing_context_;
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc
index 0d677d1e..efc1d4d 100644
--- a/chrome/browser/ui/android/context_menu_helper.cc
+++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -13,6 +13,7 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "chrome/browser/android/download/download_controller_base.h"
+#include "chrome/browser/image_decoder.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/common/thumbnail_capturer.mojom.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
@@ -24,6 +25,7 @@
 #include "jni/ContextMenuParams_jni.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/WebKit/public/web/WebContextMenuData.h"
+#include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -39,13 +41,54 @@
 
 namespace {
 
-void OnRetrieveImage(chrome::mojom::ThumbnailCapturerPtr thumbnail_capturer,
-                     const base::android::JavaRef<jobject>& jcallback,
-                     const std::vector<uint8_t>& thumbnail_data,
-                     const gfx::Size& original_size) {
+class ContextMenuHelperImageRequest : public ImageDecoder::ImageRequest {
+ public:
+  static void Start(const base::android::JavaRef<jobject>& jcallback,
+                    const std::vector<uint8_t>& thumbnail_data) {
+    ContextMenuHelperImageRequest* request =
+        new ContextMenuHelperImageRequest(jcallback);
+    ImageDecoder::Start(request, thumbnail_data);
+  }
+
+ protected:
+  void OnImageDecoded(const SkBitmap& decoded_image) override {
+    base::android::RunCallbackAndroid(jcallback_,
+                                      gfx::ConvertToJavaBitmap(&decoded_image));
+    delete this;
+  }
+
+  void OnDecodeImageFailed() override {
+    base::android::ScopedJavaLocalRef<jobject> j_bitmap;
+    base::android::RunCallbackAndroid(jcallback_, j_bitmap);
+    delete this;
+  }
+
+ private:
+  ContextMenuHelperImageRequest(
+      const base::android::JavaRef<jobject>& jcallback)
+      : jcallback_(jcallback) {}
+
+  const base::android::ScopedJavaGlobalRef<jobject> jcallback_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ContextMenuHelperImageRequest);
+};
+
+void OnRetrieveImageForShare(
+    chrome::mojom::ThumbnailCapturerPtr thumbnail_capturer,
+    const base::android::JavaRef<jobject>& jcallback,
+    const std::vector<uint8_t>& thumbnail_data,
+    const gfx::Size& original_size) {
   base::android::RunCallbackAndroid(jcallback, thumbnail_data);
 }
 
+void OnRetrieveImageForContextMenu(
+    chrome::mojom::ThumbnailCapturerPtr thumbnail_capturer,
+    const base::android::JavaRef<jobject>& jcallback,
+    const std::vector<uint8_t>& thumbnail_data,
+    const gfx::Size& original_size) {
+  ContextMenuHelperImageRequest::Start(jcallback, thumbnail_data);
+}
+
 }  // namespace
 
 ContextMenuHelper::ContextMenuHelper(content::WebContents* web_contents)
@@ -161,10 +204,29 @@
       render_frame_host, context_menu_params_.src_url);
 }
 
-void ContextMenuHelper::RetrieveImage(JNIEnv* env,
-                                      const JavaParamRef<jobject>& obj,
-                                      const JavaParamRef<jobject>& jcallback,
-                                      jint max_dimen_px) {
+void ContextMenuHelper::RetrieveImageForShare(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& jcallback,
+    jint max_dimen_px) {
+  RetrieveImageInternal(env, base::Bind(&OnRetrieveImageForShare), jcallback,
+                        max_dimen_px);
+}
+
+void ContextMenuHelper::RetrieveImageForContextMenu(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& jcallback,
+    jint max_dimen_px) {
+  RetrieveImageInternal(env, base::Bind(&OnRetrieveImageForContextMenu),
+                        jcallback, max_dimen_px);
+}
+
+void ContextMenuHelper::RetrieveImageInternal(
+    JNIEnv* env,
+    const ImageRetrieveCallback& retrieve_callback,
+    const JavaParamRef<jobject>& jcallback,
+    jint max_dimen_px) {
   content::RenderFrameHost* render_frame_host =
       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
   if (!render_frame_host)
@@ -172,12 +234,12 @@
 
   chrome::mojom::ThumbnailCapturerPtr thumbnail_capturer;
   render_frame_host->GetRemoteInterfaces()->GetInterface(&thumbnail_capturer);
-  // Bind the InterfacePtr into the callback so that it's kept alive until
-  // there's either a connection error or a response.
+  // Bind the InterfacePtr into the callback so that it's kept alive
+  // until there's either a connection error or a response.
   auto* thumbnail_capturer_proxy = thumbnail_capturer.get();
   thumbnail_capturer_proxy->RequestThumbnailForContextNode(
       0, gfx::Size(max_dimen_px, max_dimen_px),
-      base::Bind(&OnRetrieveImage, base::Passed(&thumbnail_capturer),
+      base::Bind(retrieve_callback, base::Passed(&thumbnail_capturer),
                  base::android::ScopedJavaGlobalRef<jobject>(env, jcallback)));
 }
 
diff --git a/chrome/browser/ui/android/context_menu_helper.h b/chrome/browser/ui/android/context_menu_helper.h
index 040e5bd..2d6b5b4 100644
--- a/chrome/browser/ui/android/context_menu_helper.h
+++ b/chrome/browser/ui/android/context_menu_helper.h
@@ -12,6 +12,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
+#include "chrome/common/thumbnail_capturer.mojom.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "content/public/common/context_menu_params.h"
 
@@ -23,6 +24,13 @@
 
 class ContextMenuHelper
     : public content::WebContentsUserData<ContextMenuHelper> {
+ protected:
+  using ImageRetrieveCallback = base::Callback<void(
+      chrome::mojom::ThumbnailCapturerPtr thumbnail_capturer_ptr,
+      const base::android::JavaRef<jobject>& jcallback,
+      const std::vector<uint8_t>& thumbnail_data,
+      const gfx::Size& max_dimen_px)>;
+
  public:
   ~ContextMenuHelper() override;
 
@@ -42,10 +50,21 @@
                        const base::android::JavaParamRef<jobject>& obj,
                        jboolean jis_link,
                        jboolean jis_data_reduction_proxy_enabled);
-  void RetrieveImage(JNIEnv* env,
-                     const base::android::JavaParamRef<jobject>& obj,
-                     const base::android::JavaParamRef<jobject>& jcallback,
-                     jint max_dimen_px);
+  void RetrieveImageForShare(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& jcallback,
+      jint max_dimen_px);
+  void RetrieveImageForContextMenu(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& jcallback,
+      jint max_dimen_px);
+  void RetrieveImageInternal(
+      JNIEnv* env,
+      const ImageRetrieveCallback& retrieve_callback,
+      const base::android::JavaParamRef<jobject>& jcallback,
+      jint max_dimen_px);
   void SearchForImage(JNIEnv* env,
                       const base::android::JavaParamRef<jobject>& obj);
 
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index 7841f9b4..6cb6c1e 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -35,6 +35,7 @@
 #include "components/payments/content/payment_request_spec.h"
 #include "components/payments/content/payment_request_state.h"
 #include "components/payments/core/payment_request_data_util.h"
+#include "components/payments/core/strings_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/insets.h"
@@ -186,8 +187,8 @@
   view->SetLayoutManager(layout);
 
   // "Cards accepted" label is "hint" grey.
-  view->AddChildView(CreateHintLabel(l10n_util::GetStringUTF16(
-                                         IDS_PAYMENTS_ACCEPTED_CARDS_LABEL))
+  view->AddChildView(CreateHintLabel(GetAcceptedCardTypesText(
+                                         spec()->supported_card_types_set()))
                          .release());
 
   // 8dp padding is required between icons.
diff --git a/chrome/browser/ui/views/payments/order_summary_view_controller.cc b/chrome/browser/ui/views/payments/order_summary_view_controller.cc
index 42ff50a..c1fed0e4 100644
--- a/chrome/browser/ui/views/payments/order_summary_view_controller.cc
+++ b/chrome/browser/ui/views/payments/order_summary_view_controller.cc
@@ -61,7 +61,7 @@
   row->SetLayoutManager(layout);
 
   views::ColumnSet* columns = layout->AddColumnSet(0);
-  // The first column has resize_percent = 1 so that it streches all the way
+  // The first column has resize_percent = 1 so that it stretches all the way
   // across the row up to the amount label. This way the first label elides as
   // required.
   columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 1,
@@ -83,6 +83,10 @@
     currency_text = CreateHintLabel(currency);
     amount_text = base::MakeUnique<views::Label>(amount);
   }
+  // Strings from the website may not match the locale of the device, so align
+  // them according to the language of the text. This will result, for example,
+  // in "he" labels being right-aligned in a browser that's using "en" locale.
+  label_text->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
   amount_text->set_id(static_cast<int>(amount_label_id));
   amount_text->SetMultiLine(true);
   amount_text->SetAllowCharacterBreak(true);
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
index 8ed67f7..bd161ce 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -22,12 +22,14 @@
 #include "components/payments/content/payment_request_state.h"
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/payment_instrument.h"
+#include "components/payments/core/strings_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/border.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/layout/box_layout.h"
@@ -39,8 +41,8 @@
 
 namespace {
 
-constexpr int kFirstTagValue = static_cast<int>(
-    payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX);
+constexpr int kFirstTagValue =
+    static_cast<int>(PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX);
 
 enum class PaymentMethodViewControllerTags : int {
   // The tag for the button that triggers the "add card" flow. Starts at
@@ -50,7 +52,7 @@
   MAX_TAG,
 };
 
-class PaymentMethodListItem : public payments::PaymentRequestItemList::Item {
+class PaymentMethodListItem : public PaymentRequestItemList::Item {
  public:
   // Does not take ownership of |instrument|, which should not be null and
   // should outlive this object. |list| is the PaymentRequestItemList object
@@ -61,11 +63,11 @@
                         PaymentRequestItemList* list,
                         PaymentRequestDialogView* dialog,
                         bool selected)
-      : payments::PaymentRequestItemList::Item(spec,
-                                               state,
-                                               list,
-                                               selected,
-                                               /*show_edit_button=*/true),
+      : PaymentRequestItemList::Item(spec,
+                                     state,
+                                     list,
+                                     selected,
+                                     /*show_edit_button=*/true),
         instrument_(instrument),
         dialog_(dialog) {}
   ~PaymentMethodListItem() override {}
@@ -90,7 +92,7 @@
     NOTREACHED();
   }
 
-  // payments::PaymentRequestItemList::Item:
+  // PaymentRequestItemList::Item:
   std::unique_ptr<views::View> CreateExtraView() override {
     std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView(
         instrument_->icon_resource_id(), instrument_->GetLabel());
@@ -101,14 +103,12 @@
   std::unique_ptr<views::View> CreateContentView(
       base::string16* accessible_content) override {
     DCHECK(accessible_content);
-    std::unique_ptr<views::View> card_info_container =
-        base::MakeUnique<views::View>();
+    auto card_info_container = base::MakeUnique<views::View>();
     card_info_container->set_can_process_events_within_subtree(false);
 
-    std::unique_ptr<views::BoxLayout> box_layout =
-        base::MakeUnique<views::BoxLayout>(
-            views::BoxLayout::kVertical,
-            gfx::Insets(kPaymentRequestRowVerticalInsets, 0));
+    auto box_layout = base::MakeUnique<views::BoxLayout>(
+        views::BoxLayout::kVertical,
+        gfx::Insets(kPaymentRequestRowVerticalInsets, 0));
     box_layout->set_cross_axis_alignment(
         views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
     card_info_container->SetLayoutManager(box_layout.release());
@@ -122,9 +122,8 @@
     base::string16 missing_info;
     if (!instrument_->IsCompleteForPayment()) {
       missing_info = instrument_->GetMissingInfoLabel();
-      std::unique_ptr<views::Label> missing_info_label =
-          base::MakeUnique<views::Label>(missing_info,
-                                         CONTEXT_DEPRECATED_SMALL);
+      auto missing_info_label = base::MakeUnique<views::Label>(
+          missing_info, CONTEXT_DEPRECATED_SMALL);
       missing_info_label->SetEnabledColor(
           missing_info_label->GetNativeTheme()->GetSystemColor(
               ui::NativeTheme::kColorId_LinkEnabled));
@@ -166,6 +165,16 @@
   DISALLOW_COPY_AND_ASSIGN(PaymentMethodListItem);
 };
 
+std::unique_ptr<views::View> CreateHeaderView(const base::string16& text) {
+  auto label = base::MakeUnique<views::Label>(text);
+  label->SetMultiLine(true);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetBorder(views::CreateEmptyBorder(
+      kPaymentRequestRowVerticalInsets, kPaymentRequestRowHorizontalInsets, 0,
+      kPaymentRequestRowHorizontalInsets));
+  return std::move(label);
+}
+
 }  // namespace
 
 PaymentMethodViewController::PaymentMethodViewController(
@@ -175,12 +184,10 @@
     : PaymentRequestSheetController(spec, state, dialog) {
   const std::vector<std::unique_ptr<PaymentInstrument>>& available_instruments =
       state->available_instruments();
-  for (const std::unique_ptr<PaymentInstrument>& instrument :
-       available_instruments) {
-    std::unique_ptr<PaymentMethodListItem> item =
-        base::MakeUnique<PaymentMethodListItem>(
-            instrument.get(), spec, state, &payment_method_list_, dialog,
-            instrument.get() == state->selected_instrument());
+  for (const auto& instrument : available_instruments) {
+    auto item = base::MakeUnique<PaymentMethodListItem>(
+        instrument.get(), spec, state, &payment_method_list_, dialog,
+        instrument.get() == state->selected_instrument());
     payment_method_list_.AddItem(std::move(item));
   }
 }
@@ -193,7 +200,17 @@
 }
 
 void PaymentMethodViewController::FillContentView(views::View* content_view) {
-  content_view->SetLayoutManager(new views::FillLayout);
+  auto layout = base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical);
+  layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
+  content_view->SetLayoutManager(layout.release());
+
+  base::string16 sub_header =
+      GetCardTypesAreAcceptedText(spec()->supported_card_types_set());
+  if (!sub_header.empty())
+    content_view->AddChildView(CreateHeaderView(sub_header).release());
+
   std::unique_ptr<views::View> list_view =
       payment_method_list_.CreateListView();
   list_view->set_id(
@@ -203,7 +220,7 @@
 
 std::unique_ptr<views::View>
 PaymentMethodViewController::CreateExtraFooterView() {
-  std::unique_ptr<views::View> extra_view = base::MakeUnique<views::View>();
+  auto extra_view = base::MakeUnique<views::View>();
 
   extra_view->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kHorizontal, gfx::Insets(),
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
index 4dc2c35..98dfb427 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -28,7 +28,7 @@
 namespace autofill {
 class AutofillProfile;
 class CreditCard;
-}
+}  // namespace autofill
 
 namespace content {
 class WebContents;
diff --git a/chrome/browser/ui/views/payments/payment_request_debit_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_debit_browsertest.cc
new file mode 100644
index 0000000..eca18710
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_debit_browsertest.cc
@@ -0,0 +1,116 @@
+// 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 "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/views/payments/payment_request_browsertest_base.h"
+#include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "content/public/test/browser_test_utils.h"
+
+namespace payments {
+
+constexpr auto CREDIT = ::autofill::CreditCard::CardType::CARD_TYPE_CREDIT;
+constexpr auto DEBIT = ::autofill::CreditCard::CardType::CARD_TYPE_DEBIT;
+constexpr auto PREPAID = ::autofill::CreditCard::CardType::CARD_TYPE_PREPAID;
+constexpr auto UNKNOWN = ::autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN;
+
+// Tests for a merchant that requests a debit card.
+class PaymentRequestDebitTest : public PaymentRequestBrowserTestBase {
+ protected:
+  PaymentRequestDebitTest()
+      : PaymentRequestBrowserTestBase("/payment_request_debit_test.html") {}
+
+  const std::string& GetOrCreateBillingAddressId() {
+    if (billing_address_id_.empty()) {
+      autofill::AutofillProfile billing_address =
+          autofill::test::GetFullProfile();
+      billing_address_id_ = billing_address.guid();
+      AddAutofillProfile(billing_address);
+    }
+    return billing_address_id_;
+  }
+
+  void AddServerCardWithType(autofill::CreditCard::CardType card_type) {
+    autofill::CreditCard card = autofill::test::GetMaskedServerCard();
+    card.set_card_type(card_type);
+    card.set_billing_address_id(GetOrCreateBillingAddressId());
+    AddCreditCard(card);
+  }
+
+  void CallCanMakePayment() {
+    ResetEventObserver(DialogEvent::CAN_MAKE_PAYMENT_CALLED);
+    ASSERT_TRUE(
+        content::ExecuteScript(GetActiveWebContents(), "canMakePayment();"));
+    WaitForObservedEvent();
+  }
+
+ private:
+  std::string billing_address_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestDebitTest);
+};
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestDebitTest, CanMakePaymentWithDebitCard) {
+  AddServerCardWithType(DEBIT);
+  CallCanMakePayment();
+  ExpectBodyContains({"true"});
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestDebitTest,
+                       CanMakePaymentWithUnknownCardType) {
+  AddServerCardWithType(UNKNOWN);
+  CallCanMakePayment();
+  ExpectBodyContains({"true"});
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestDebitTest,
+                       CannotMakePaymentWithCreditAndPrepaidCard) {
+  AddServerCardWithType(CREDIT);
+  AddServerCardWithType(PREPAID);
+  CallCanMakePayment();
+  ExpectBodyContains({"false"});
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestDebitTest, DebitCardIsPreselected) {
+  AddServerCardWithType(DEBIT);
+  CallCanMakePayment();
+  InvokePaymentRequestUI();
+  EXPECT_TRUE(IsPayButtonEnabled());
+  ClickOnCancel();
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestDebitTest,
+                       UnknownCardTypeIsNotPreselected) {
+  AddServerCardWithType(UNKNOWN);
+  InvokePaymentRequestUI();
+  EXPECT_FALSE(IsPayButtonEnabled());
+  ClickOnCancel();
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestDebitTest, PayWithLocalCard) {
+  // All local cards have "unknown" card type by design.
+  autofill::CreditCard card = autofill::test::GetCreditCard();
+  card.set_billing_address_id(GetOrCreateBillingAddressId());
+  AddCreditCard(card);
+  InvokePaymentRequestUI();
+
+  // The local card of "unknown" type is not pre-selected.
+  EXPECT_FALSE(IsPayButtonEnabled());
+
+  // Select the local card and click the "Pay" button.
+  OpenPaymentMethodScreen();
+  ResetEventObserver(DialogEvent::BACK_NAVIGATION);
+  ClickOnChildInListViewAndWait(/*child_index=*/0, /*num_children=*/1,
+                                DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW);
+  EXPECT_TRUE(IsPayButtonEnabled());
+
+  // Type in the CVC number and verify that it's sent to the page.
+  ResetEventObserver(DialogEvent::DIALOG_CLOSED);
+  PayWithCreditCardAndWait(base::ASCIIToUTF16("012"));
+  ExpectBodyContains({"\"cardSecurityCode\": \"012\""});
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
index 01623a9..07df8d9 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
@@ -51,7 +51,7 @@
   // The following are Label objects.
   SHIPPING_OPTION_DESCRIPTION,
   SHIPPING_OPTION_AMOUNT,
-  SHIPPING_ADDRESS_OPTION_ERROR,
+  SHIPPING_ADDRESS_SECTION_HEADER_LABEL,
 
   // Used in profile labels to annotate each line of the grouping.
   PROFILE_LABEL_LINE_1,
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index 2bfa4797..dc8e501 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -375,7 +375,11 @@
     std::unique_ptr<views::Label> shipping_label =
         emphasize_label ? CreateMediumLabel(text)
                         : base::MakeUnique<views::Label>(text);
-    shipping_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    // Strings from the website may not match the locale of the device, so align
+    // them according to the language of the text. This will result, for
+    // example, in "he" labels being right-aligned in a browser that's using
+    // "en" locale.
+    shipping_label->SetHorizontalAlignment(gfx::ALIGN_TO_HEAD);
     shipping_label->set_id(
         static_cast<int>(DialogViewID::SHIPPING_OPTION_DESCRIPTION));
     container->AddChildView(shipping_label.release());
diff --git a/chrome/browser/ui/views/payments/profile_list_view_controller.cc b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
index 9be4e98..a0ae9f3 100644
--- a/chrome/browser/ui/views/payments/profile_list_view_controller.cc
+++ b/chrome/browser/ui/views/payments/profile_list_view_controller.cc
@@ -31,8 +31,8 @@
 
 namespace {
 
-constexpr int kFirstTagValue = static_cast<int>(
-    payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX);
+constexpr int kFirstTagValue =
+    static_cast<int>(PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX);
 
 enum class PaymentMethodViewControllerTags : int {
   // The tag for the button that triggers the "add address" flow. Starts at
@@ -56,17 +56,17 @@
               ProfileListViewController* controller,
               PaymentRequestDialogView* dialog,
               bool selected)
-      : payments::PaymentRequestItemList::Item(spec,
-                                               state,
-                                               parent_list,
-                                               selected,
-                                               /*show_edit_button=*/true),
+      : PaymentRequestItemList::Item(spec,
+                                     state,
+                                     parent_list,
+                                     selected,
+                                     /*show_edit_button=*/true),
         controller_(controller),
         profile_(profile) {}
   ~ProfileItem() override {}
 
  private:
-  // payments::PaymentRequestItemList::Item:
+  // PaymentRequestItemList::Item:
   std::unique_ptr<views::View> CreateContentView(
       base::string16* accessible_content) override {
     DCHECK(profile_);
@@ -165,39 +165,54 @@
     return DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW;
   }
 
+  // Creates a warning message when address is not valid or an informational
+  // message when the user has not selected their shipping address yet. The
+  // warning icon is displayed only for warning messages.
+  // ---------------------------------------------
+  // | Warning icon | Warning message            |
+  // ---------------------------------------------
   std::unique_ptr<views::View> CreateHeaderView() override {
-    if (spec()->selected_shipping_option_error().empty())
+    if (!spec()->details().shipping_options.empty())
       return nullptr;
 
-    std::unique_ptr<views::View> header_view = base::MakeUnique<views::View>();
-    // 8 pixels between the warning icon view and the text.
+    auto header_view = base::MakeUnique<views::View>();
+    // 8 pixels between the warning icon view (if present) and the text.
     constexpr int kRowHorizontalSpacing = 8;
-    views::BoxLayout* layout = new views::BoxLayout(
+    auto layout = base::MakeUnique<views::BoxLayout>(
         views::BoxLayout::kHorizontal,
-        gfx::Insets(0, payments::kPaymentRequestRowHorizontalInsets),
+        gfx::Insets(0, kPaymentRequestRowHorizontalInsets),
         kRowHorizontalSpacing);
     layout->set_main_axis_alignment(
         views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
     layout->set_cross_axis_alignment(
         views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
-    header_view->SetLayoutManager(layout);
+    header_view->SetLayoutManager(layout.release());
 
-    std::unique_ptr<views::ImageView> warning_icon =
-        base::MakeUnique<views::ImageView>();
-    warning_icon->set_can_process_events_within_subtree(false);
-    warning_icon->SetImage(gfx::CreateVectorIcon(
-        ui::kWarningIcon, 16,
-        warning_icon->GetNativeTheme()->GetSystemColor(
-            ui::NativeTheme::kColorId_AlertSeverityHigh)));
-    header_view->AddChildView(warning_icon.release());
-
-    std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
-        spec()->selected_shipping_option_error());
+    auto label = base::MakeUnique<views::Label>(
+        spec()->selected_shipping_option_error().empty()
+            ? GetShippingAddressSelectorInfoMessage(spec()->shipping_type())
+            : spec()->selected_shipping_option_error());
+    // If the warning message comes from the websites, then align label
+    // according to the language of the website's text.
+    label->SetHorizontalAlignment(
+        spec()->selected_shipping_option_error().empty() ? gfx::ALIGN_LEFT
+                                                         : gfx::ALIGN_TO_HEAD);
     label->set_id(
-        static_cast<int>(DialogViewID::SHIPPING_ADDRESS_OPTION_ERROR));
-    label->SetEnabledColor(label->GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_AlertSeverityHigh));
+        static_cast<int>(DialogViewID::SHIPPING_ADDRESS_SECTION_HEADER_LABEL));
     label->SetMultiLine(true);
+
+    if (!spec()->selected_shipping_option_error().empty()) {
+      auto warning_icon = base::MakeUnique<views::ImageView>();
+      warning_icon->set_can_process_events_within_subtree(false);
+      warning_icon->SetImage(gfx::CreateVectorIcon(
+          ui::kWarningIcon, 16,
+          warning_icon->GetNativeTheme()->GetSystemColor(
+              ui::NativeTheme::kColorId_AlertSeverityHigh)));
+      header_view->AddChildView(warning_icon.release());
+      label->SetEnabledColor(label->GetNativeTheme()->GetSystemColor(
+          ui::NativeTheme::kColorId_AlertSeverityHigh));
+    }
+
     header_view->AddChildView(label.release());
     return header_view;
   }
@@ -369,11 +384,11 @@
 }
 
 void ProfileListViewController::FillContentView(views::View* content_view) {
-  views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kVertical);
+  auto layout = base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical);
   layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
-  content_view->SetLayoutManager(layout);
+  content_view->SetLayoutManager(layout.release());
   std::unique_ptr<views::View> header_view = CreateHeaderView();
   if (header_view)
     content_view->AddChildView(header_view.release());
@@ -384,7 +399,7 @@
 
 std::unique_ptr<views::View>
 ProfileListViewController::CreateExtraFooterView() {
-  std::unique_ptr<views::View> extra_view = base::MakeUnique<views::View>();
+  auto extra_view = base::MakeUnique<views::View>();
 
   extra_view->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kHorizontal, gfx::Insets(),
diff --git a/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
index 28b9b73..83ca2241 100644
--- a/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/shipping_option_view_controller_browsertest.cc
@@ -51,10 +51,9 @@
 
   // Go to the shipping address screen and select the first address (MI state).
   OpenShippingAddressSectionScreen();
-  // There is no error at the top of this screen, because no address has been
-  // selected yet.
-  EXPECT_EQ(nullptr, dialog_view()->GetViewByID(static_cast<int>(
-                         DialogViewID::SHIPPING_ADDRESS_OPTION_ERROR)));
+  EXPECT_EQ(base::ASCIIToUTF16(
+                "To see shipping methods and requirements, select an address"),
+            GetLabelText(DialogViewID::SHIPPING_ADDRESS_SECTION_HEADER_LABEL));
 
   ResetEventObserverForSequence(std::list<DialogEvent>{
       DialogEvent::SPEC_DONE_UPDATING, DialogEvent::BACK_NAVIGATION});
@@ -99,7 +98,7 @@
 
   // The address selector has this error.
   EXPECT_EQ(base::ASCIIToUTF16("We do not ship to this address"),
-            GetLabelText(DialogViewID::SHIPPING_ADDRESS_OPTION_ERROR));
+            GetLabelText(DialogViewID::SHIPPING_ADDRESS_SECTION_HEADER_LABEL));
 
   // There is no a longer shipping option section, because no shipping options
   // are available for Canada.
@@ -108,7 +107,6 @@
   EXPECT_EQ(nullptr,
             dialog_view()->GetViewByID(static_cast<int>(
                 DialogViewID::PAYMENT_SHEET_SHIPPING_OPTION_SECTION_BUTTON)));
-
 }
 
 }  // namespace payments
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 9ebee9b9..a74348f0 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -94,6 +94,13 @@
 #endif
 };
 
+// If enabled, we'll only take thumbnails of unknown URLs (i.e. URLs that are
+// not (yet) part of TopSites) if they have an interesting transition type, i.e.
+// one that qualifies for inclusion in TopSites.
+const base::Feature kCaptureThumbnailDependingOnTransitionType{
+    "CaptureThumbnailDependingOnTransitionType",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Whether to capture page thumbnails when the page load finishes (in addition
 // to any other times this might happen).
 const base::Feature kCaptureThumbnailOnLoadFinished{
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 9d19efaa..d87d19b 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -56,6 +56,8 @@
 extern const base::Feature kTabStripKeyboardFocus;
 #endif  // defined(OS_MACOSX)
 
+extern const base::Feature kCaptureThumbnailDependingOnTransitionType;
+
 extern const base::Feature kCaptureThumbnailOnLoadFinished;
 
 extern const base::Feature kCheckInstallabilityForBannerOnLoad;
diff --git a/chrome/renderer/extensions/app_hooks_delegate.cc b/chrome/renderer/extensions/app_hooks_delegate.cc
index 3e3698c..d66ccded 100644
--- a/chrome/renderer/extensions/app_hooks_delegate.cc
+++ b/chrome/renderer/extensions/app_hooks_delegate.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/renderer/extensions/app_hooks_delegate.h"
 
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
 #include "extensions/renderer/script_context_set.h"
 #include "gin/converter.h"
 
diff --git a/chrome/renderer/extensions/app_hooks_delegate.h b/chrome/renderer/extensions/app_hooks_delegate.h
index 35be734..027f5e8 100644
--- a/chrome/renderer/extensions/app_hooks_delegate.h
+++ b/chrome/renderer/extensions/app_hooks_delegate.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "chrome/renderer/extensions/app_bindings_core.h"
-#include "extensions/renderer/api_binding_hooks_delegate.h"
+#include "extensions/renderer/bindings/api_binding_hooks_delegate.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 17328bc..881f5252 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -34,7 +34,7 @@
 #include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_data.h"
 #include "extensions/common/switches.h"
-#include "extensions/renderer/api_bindings_system.h"
+#include "extensions/renderer/bindings/api_bindings_system.h"
 #include "extensions/renderer/css_native_handler.h"
 #include "extensions/renderer/dispatcher.h"
 #include "extensions/renderer/i18n_custom_bindings.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7f5f64fd..cef3a792 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2066,6 +2066,7 @@
         "../browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc",
         "../browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc",
         "../browser/ui/views/payments/payment_request_data_url_browsertest.cc",
+        "../browser/ui/views/payments/payment_request_debit_browsertest.cc",
         "../browser/ui/views/payments/payment_request_journey_logger_browsertest.cc",
         "../browser/ui/views/payments/payment_request_payment_app_browsertest.cc",
         "../browser/ui/views/payments/payment_request_payment_response_browsertest.cc",
diff --git a/chrome/test/data/payments/debit.js b/chrome/test/data/payments/debit.js
new file mode 100644
index 0000000..f8f293c2c
--- /dev/null
+++ b/chrome/test/data/payments/debit.js
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/**
+ * Builds a payment request for a debit card.
+ * @return {!PaymentRequest} A payment request for a debit card.
+ * @private
+ */
+function buildPaymentRequest() {
+  return new PaymentRequest([{
+    supportedMethods: ['basic-card'],
+    data: {
+      supportedTypes: ['debit'],
+    },
+  }], {
+    total: {
+      label: 'Total',
+      amount: {
+        currency: 'USD',
+        value: '1.00',
+      },
+    },
+  });
+}
+
+/** Requests payment via a debit card. */
+function buy() { // eslint-disable-line no-unused-vars
+  try {
+    buildPaymentRequest()
+      .show()
+      .then(function(response) {
+        response.complete()
+          .then(function() {
+            print(JSON.stringify(response, undefined, 2));
+          })
+          .catch(function(error) {
+            print(error);
+          });
+      })
+      .catch(function(error) {
+        print(error);
+      });
+  } catch (error) {
+    print(error);
+  }
+}
+
+/** Checks whether payment via a debit card is possible. */
+function canMakePayment() { // eslint-disable-line no-unused-vars
+  try {
+    buildPaymentRequest()
+      .canMakePayment()
+      .then(function(result) {
+        print(result);
+      })
+      .catch(function(error) {
+        print(error);
+      });
+  } catch (error) {
+    print(error);
+  }
+}
diff --git a/chrome/test/data/payments/payment_request_debit_test.html b/chrome/test/data/payments/payment_request_debit_test.html
new file mode 100644
index 0000000..33c8ae5c
--- /dev/null
+++ b/chrome/test/data/payments/payment_request_debit_test.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<html>
+
+<head>
+  <title>Debit Test</title>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+  <link rel="stylesheet" type="text/css" href="style.css">
+</head>
+
+<body>
+  <div><button onclick="buy()" id="buy">Debit Buy Test</button></div>
+  <div><button onclick="canMakePayment()" id="canMakePayment">Debit
+      CanMakePayment Test</button></div>
+  <pre id="result"></pre>
+  <script src="util.js"></script>
+  <script src="debit.js"></script>
+</body>
+
+</html>
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index c464017..8f2697b5 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -11,6 +11,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
@@ -216,7 +217,7 @@
   const char* const switch_value;
 };
 
-DefaultCommandLineSwitch g_default_switches[] = {
+const DefaultCommandLineSwitch kDefaultSwitches[] = {
 #if defined(OS_ANDROID)
     // TODO(714676): this should probably set the no restrictions autoplay
     // policy instead.
@@ -261,16 +262,21 @@
     {switches::kEnableNetworkInformation, ""},
     // TODO(halliwell): Remove after fixing b/35422666.
     {switches::kEnableUseZoomForDSF, "false"},
-    {nullptr, nullptr},  // Termination
 };
 
 void AddDefaultCommandLineSwitches(base::CommandLine* command_line) {
-  int i = 0;
-  while (g_default_switches[i].switch_name != NULL) {
-    command_line->AppendSwitchASCII(
-        std::string(g_default_switches[i].switch_name),
-        std::string(g_default_switches[i].switch_value));
-    ++i;
+  for (const auto& default_switch : kDefaultSwitches) {
+    // Don't override existing command line switch values with these defaults.
+    // This could occur primarily (or only) on Android, where the command line
+    // is initialized in Java first.
+    std::string name(default_switch.switch_name);
+    if (!command_line->HasSwitch(name)) {
+      std::string value(default_switch.switch_value);
+      VLOG(2) << "Set default switch '" << name << "' = '" << value << "'";
+      command_line->AppendSwitchASCII(name, value);
+    } else {
+      VLOG(2) << "Skip setting default switch '" << name << "', already set";
+    }
   }
 }
 
diff --git a/chromecast/media/cma/backend/android/BUILD.gn b/chromecast/media/cma/backend/android/BUILD.gn
index cee5b01c..bd66441f 100644
--- a/chromecast/media/cma/backend/android/BUILD.gn
+++ b/chromecast/media/cma/backend/android/BUILD.gn
@@ -20,6 +20,7 @@
     "media_pipeline_backend_android.cc",
     "media_pipeline_backend_android.h",
     "volume_control_android.cc",
+    "volume_control_android.h",
   ]
 
   deps = [
diff --git a/chromecast/media/cma/backend/android/volume_control_android.cc b/chromecast/media/cma/backend/android/volume_control_android.cc
index 66beec3..7343a7a 100644
--- a/chromecast/media/cma/backend/android/volume_control_android.cc
+++ b/chromecast/media/cma/backend/android/volume_control_android.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromecast/public/volume_control.h"
+#include "chromecast/media/cma/backend/android/volume_control_android.h"
 
 #include <algorithm>
 #include <cmath>
@@ -50,16 +50,11 @@
 constexpr char kKeyLevel[] = "level";
 constexpr char kKeyDb[] = "db";
 
-struct LevelToDb {
-  float level;
-  float db;
-};
-
-const LevelToDb kDefaultVolumeMap[] = {{0.0f, kMinDbFS},
-                                       {0.01f, -58.0f},
-                                       {0.090909f, -48.0f},
-                                       {0.818182f, -8.0f},
-                                       {1.0f, 0.0f}};
+const VolumeMap::LevelToDb kDefaultVolumeMap[] = {{0.0f, kMinDbFS},
+                                                  {0.01f, -58.0f},
+                                                  {0.090909f, -48.0f},
+                                                  {0.818182f, -8.0f},
+                                                  {1.0f, 0.0f}};
 
 float DbFsToScale(float db) {
   if (db <= kMinDbFS) {
@@ -79,273 +74,249 @@
   }
 }
 
-// TODO(ckuiper): This logic is identical to the one in alsa/volume_control.cc.
-// Consolidate it.
-class VolumeMap {
- public:
-  VolumeMap() {
-    auto cast_audio_config =
-        DeserializeJsonFromFile(base::FilePath(kCastAudioConfigFilePath));
-    const base::DictionaryValue* cast_audio_dict;
-    if (!cast_audio_config ||
-        !cast_audio_config->GetAsDictionary(&cast_audio_dict)) {
-      LOG(WARNING) << "No cast audio config found; using default volume map.";
-      volume_map_.insert(volume_map_.end(), kDefaultVolumeMap,
-                         kDefaultVolumeMap + arraysize(kDefaultVolumeMap));
-      return;
-    }
-
-    const base::ListValue* volume_map_list;
-    if (!cast_audio_dict->GetList(kKeyVolumeMap, &volume_map_list)) {
-      LOG(WARNING) << "No volume map found; using default volume map.";
-      volume_map_.insert(volume_map_.end(), kDefaultVolumeMap,
-                         kDefaultVolumeMap + arraysize(kDefaultVolumeMap));
-      return;
-    }
-
-    double prev_level = -1.0;
-    for (size_t i = 0; i < volume_map_list->GetSize(); ++i) {
-      const base::DictionaryValue* volume_map_entry;
-      CHECK(volume_map_list->GetDictionary(i, &volume_map_entry));
-
-      double level;
-      CHECK(volume_map_entry->GetDouble(kKeyLevel, &level));
-      CHECK_GE(level, 0.0);
-      CHECK_LE(level, 1.0);
-      CHECK_GT(level, prev_level);
-      prev_level = level;
-
-      double db;
-      CHECK(volume_map_entry->GetDouble(kKeyDb, &db));
-      CHECK_LE(db, 0.0);
-      if (level == 1.0) {
-        CHECK_EQ(db, 0.0);
-      }
-
-      volume_map_.push_back({level, db});
-    }
-
-    if (volume_map_.empty()) {
-      LOG(FATAL) << "No entries in volume map.";
-      return;
-    }
-
-    if (volume_map_[0].level > 0.0) {
-      volume_map_.insert(volume_map_.begin(), {0.0, kMinDbFS});
-    }
-
-    if (volume_map_.rbegin()->level < 1.0) {
-      volume_map_.push_back({1.0, 0.0});
-    }
-  }
-
-  float VolumeToDbFS(float volume) {
-    if (volume <= volume_map_[0].level) {
-      return volume_map_[0].db;
-    }
-    for (size_t i = 1; i < volume_map_.size(); ++i) {
-      if (volume < volume_map_[i].level) {
-        const float x_range = volume_map_[i].level - volume_map_[i - 1].level;
-        const float y_range = volume_map_[i].db - volume_map_[i - 1].db;
-        const float x_pos = volume - volume_map_[i - 1].level;
-
-        return volume_map_[i - 1].db + x_pos * y_range / x_range;
-      }
-    }
-    return volume_map_[volume_map_.size() - 1].db;
-  }
-
-  // static
-  float DbFSToVolume(float db) {
-    if (db <= volume_map_[0].db) {
-      return volume_map_[0].level;
-    }
-    for (size_t i = 1; i < volume_map_.size(); ++i) {
-      if (db < volume_map_[i].db) {
-        const float x_range = volume_map_[i].db - volume_map_[i - 1].db;
-        const float y_range = volume_map_[i].level - volume_map_[i - 1].level;
-        const float x_pos = db - volume_map_[i - 1].db;
-
-        return volume_map_[i - 1].level + x_pos * y_range / x_range;
-      }
-    }
-    return volume_map_[volume_map_.size() - 1].level;
-  }
-
- private:
-  std::vector<LevelToDb> volume_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(VolumeMap);
-};
-
 base::LazyInstance<VolumeMap>::Leaky g_volume_map = LAZY_INSTANCE_INITIALIZER;
 
-// TODO(ckuiper): This logic is similar to the one in alsa/volume_control.cc.
-// Consolidate it.
-class VolumeControlInternal {
- public:
-  VolumeControlInternal()
-      : thread_("VolumeControl"),
-        initialize_complete_event_(
-            base::WaitableEvent::ResetPolicy::MANUAL,
-            base::WaitableEvent::InitialState::NOT_SIGNALED) {
-    // Load volume map to check that the config file is correct.
-    g_volume_map.Get();
-
-    stored_values_.SetDouble(kKeyMediaDbFS, kDefaultMediaDbFS);
-    stored_values_.SetDouble(kKeyAlarmDbFS, kDefaultAlarmDbFS);
-    stored_values_.SetDouble(kKeyCommunicationDbFS, kDefaultCommunicationDbFS);
-
-    auto types = {AudioContentType::kMedia, AudioContentType::kAlarm,
-                  AudioContentType::kCommunication};
-    double volume;
-
-    storage_path_ = base::GetHomeDir().Append("saved_volumes");
-    auto old_stored_data = DeserializeJsonFromFile(storage_path_);
-    base::DictionaryValue* old_stored_dict;
-    if (old_stored_data && old_stored_data->GetAsDictionary(&old_stored_dict)) {
-      for (auto type : types) {
-        if (old_stored_dict->GetDouble(ContentTypeToDbFSKey(type), &volume)) {
-          stored_values_.SetDouble(ContentTypeToDbFSKey(type), volume);
-        }
-      }
-    }
-
-    base::Thread::Options options;
-    options.message_loop_type = base::MessageLoop::TYPE_IO;
-    thread_.StartWithOptions(options);
-
-    thread_.task_runner()->PostTask(
-        FROM_HERE, base::Bind(&VolumeControlInternal::InitializeOnThread,
-                              base::Unretained(this)));
-    initialize_complete_event_.Wait();
-  }
-
-  ~VolumeControlInternal() {}
-
-  void AddVolumeObserver(VolumeObserver* observer) {
-    base::AutoLock lock(observer_lock_);
-    volume_observers_.push_back(observer);
-  }
-
-  void RemoveVolumeObserver(VolumeObserver* observer) {
-    base::AutoLock lock(observer_lock_);
-    volume_observers_.erase(std::remove(volume_observers_.begin(),
-                                        volume_observers_.end(), observer),
-                            volume_observers_.end());
-  }
-
-  float GetVolume(AudioContentType type) {
-    base::AutoLock lock(volume_lock_);
-    return volumes_[type];
-  }
-
-  void SetVolume(AudioContentType type, float level) {
-    level = std::max(0.0f, std::min(level, 1.0f));
-    thread_.task_runner()->PostTask(
-        FROM_HERE, base::Bind(&VolumeControlInternal::SetVolumeOnThread,
-                              base::Unretained(this), type, level));
-  }
-
-  bool IsMuted(AudioContentType type) {
-    base::AutoLock lock(volume_lock_);
-    return muted_[type];
-  }
-
-  void SetMuted(AudioContentType type, bool muted) {
-    thread_.task_runner()->PostTask(
-        FROM_HERE, base::Bind(&VolumeControlInternal::SetMutedOnThread,
-                              base::Unretained(this), type, muted));
-  }
-
-  void SetOutputLimit(AudioContentType type, float limit) {
-    limit = std::max(0.0f, std::min(limit, 1.0f));
-    AudioSinkManager::Get()->SetOutputLimit(
-        type, DbFsToScale(VolumeControl::VolumeToDbFS(limit)));
-  }
-
- private:
-  void InitializeOnThread() {
-    DCHECK(thread_.task_runner()->BelongsToCurrentThread());
-
-    double dbfs;
-    for (auto type : {AudioContentType::kMedia, AudioContentType::kAlarm,
-                      AudioContentType::kCommunication}) {
-      CHECK(stored_values_.GetDouble(ContentTypeToDbFSKey(type), &dbfs));
-      volumes_[type] = VolumeControl::DbFSToVolume(dbfs);
-      AudioSinkManager::Get()->SetVolume(type, DbFsToScale(dbfs));
-
-      // Note that mute state is not persisted across reboots.
-      muted_[type] = false;
-    }
-    initialize_complete_event_.Signal();
-  }
-
-  void SetVolumeOnThread(AudioContentType type, float level) {
-    DCHECK(thread_.task_runner()->BelongsToCurrentThread());
-    {
-      base::AutoLock lock(volume_lock_);
-      if (level == volumes_[type]) {
-        return;
-      }
-      volumes_[type] = level;
-    }
-
-    float dbfs = VolumeControl::VolumeToDbFS(level);
-    AudioSinkManager::Get()->SetVolume(type, DbFsToScale(dbfs));
-
-    {
-      base::AutoLock lock(observer_lock_);
-      for (VolumeObserver* observer : volume_observers_) {
-        observer->OnVolumeChange(type, level);
-      }
-    }
-
-    stored_values_.SetDouble(ContentTypeToDbFSKey(type), dbfs);
-    SerializeJsonToFile(storage_path_, stored_values_);
-  }
-
-  void SetMutedOnThread(AudioContentType type, bool muted) {
-    DCHECK(thread_.task_runner()->BelongsToCurrentThread());
-    {
-      base::AutoLock lock(volume_lock_);
-      if (muted == muted_[type]) {
-        return;
-      }
-      muted_[type] = muted;
-    }
-
-    AudioSinkManager::Get()->SetMuted(type, muted);
-
-    {
-      base::AutoLock lock(observer_lock_);
-      for (VolumeObserver* observer : volume_observers_) {
-        observer->OnMuteChange(type, muted);
-      }
-    }
-  }
-
-  base::FilePath storage_path_;
-  base::DictionaryValue stored_values_;
-
-  base::Lock volume_lock_;
-  std::map<AudioContentType, float> volumes_;
-  std::map<AudioContentType, bool> muted_;
-
-  base::Lock observer_lock_;
-  std::vector<VolumeObserver*> volume_observers_;
-
-  base::Thread thread_;
-  base::WaitableEvent initialize_complete_event_;
-
-  DISALLOW_COPY_AND_ASSIGN(VolumeControlInternal);
-};
-
-base::LazyInstance<VolumeControlInternal>::Leaky g_volume_control =
+base::LazyInstance<VolumeControlAndroid>::Leaky g_volume_control =
     LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
+VolumeMap::VolumeMap() {
+  auto cast_audio_config =
+      DeserializeJsonFromFile(base::FilePath(kCastAudioConfigFilePath));
+  const base::DictionaryValue* cast_audio_dict;
+  if (!cast_audio_config ||
+      !cast_audio_config->GetAsDictionary(&cast_audio_dict)) {
+    LOG(WARNING) << "No cast audio config found; using default volume map.";
+    volume_map_.insert(volume_map_.end(), kDefaultVolumeMap,
+                       kDefaultVolumeMap + arraysize(kDefaultVolumeMap));
+    return;
+  }
+
+  const base::ListValue* volume_map_list;
+  if (!cast_audio_dict->GetList(kKeyVolumeMap, &volume_map_list)) {
+    LOG(WARNING) << "No volume map found; using default volume map.";
+    volume_map_.insert(volume_map_.end(), kDefaultVolumeMap,
+                       kDefaultVolumeMap + arraysize(kDefaultVolumeMap));
+    return;
+  }
+
+  double prev_level = -1.0;
+  for (size_t i = 0; i < volume_map_list->GetSize(); ++i) {
+    const base::DictionaryValue* volume_map_entry;
+    CHECK(volume_map_list->GetDictionary(i, &volume_map_entry));
+
+    double level;
+    CHECK(volume_map_entry->GetDouble(kKeyLevel, &level));
+    CHECK_GE(level, 0.0);
+    CHECK_LE(level, 1.0);
+    CHECK_GT(level, prev_level);
+    prev_level = level;
+
+    double db;
+    CHECK(volume_map_entry->GetDouble(kKeyDb, &db));
+    CHECK_LE(db, 0.0);
+    if (level == 1.0) {
+      CHECK_EQ(db, 0.0);
+    }
+
+    volume_map_.push_back({level, db});
+  }
+
+  if (volume_map_.empty()) {
+    LOG(FATAL) << "No entries in volume map.";
+    return;
+  }
+
+  if (volume_map_[0].level > 0.0) {
+    volume_map_.insert(volume_map_.begin(), {0.0, kMinDbFS});
+  }
+
+  if (volume_map_.rbegin()->level < 1.0) {
+    volume_map_.push_back({1.0, 0.0});
+  }
+}
+
+VolumeMap::~VolumeMap() {}
+
+float VolumeMap::VolumeToDbFS(float volume) {
+  if (volume <= volume_map_[0].level) {
+    return volume_map_[0].db;
+  }
+  for (size_t i = 1; i < volume_map_.size(); ++i) {
+    if (volume < volume_map_[i].level) {
+      const float x_range = volume_map_[i].level - volume_map_[i - 1].level;
+      const float y_range = volume_map_[i].db - volume_map_[i - 1].db;
+      const float x_pos = volume - volume_map_[i - 1].level;
+
+      return volume_map_[i - 1].db + x_pos * y_range / x_range;
+    }
+  }
+  return volume_map_[volume_map_.size() - 1].db;
+}
+
+float VolumeMap::DbFSToVolume(float db) {
+  if (db <= volume_map_[0].db) {
+    return volume_map_[0].level;
+  }
+  for (size_t i = 1; i < volume_map_.size(); ++i) {
+    if (db < volume_map_[i].db) {
+      const float x_range = volume_map_[i].db - volume_map_[i - 1].db;
+      const float y_range = volume_map_[i].level - volume_map_[i - 1].level;
+      const float x_pos = db - volume_map_[i - 1].db;
+
+      return volume_map_[i - 1].level + x_pos * y_range / x_range;
+    }
+  }
+  return volume_map_[volume_map_.size() - 1].level;
+}
+
+VolumeControlAndroid::VolumeControlAndroid()
+    : thread_("VolumeControl"),
+      initialize_complete_event_(
+          base::WaitableEvent::ResetPolicy::MANUAL,
+          base::WaitableEvent::InitialState::NOT_SIGNALED) {
+  // Load volume map to check that the config file is correct.
+  g_volume_map.Get();
+
+  stored_values_.SetDouble(kKeyMediaDbFS, kDefaultMediaDbFS);
+  stored_values_.SetDouble(kKeyAlarmDbFS, kDefaultAlarmDbFS);
+  stored_values_.SetDouble(kKeyCommunicationDbFS, kDefaultCommunicationDbFS);
+
+  auto types = {AudioContentType::kMedia, AudioContentType::kAlarm,
+                AudioContentType::kCommunication};
+  double volume;
+
+  storage_path_ = base::GetHomeDir().Append("saved_volumes");
+  auto old_stored_data = DeserializeJsonFromFile(storage_path_);
+  base::DictionaryValue* old_stored_dict;
+  if (old_stored_data && old_stored_data->GetAsDictionary(&old_stored_dict)) {
+    for (auto type : types) {
+      if (old_stored_dict->GetDouble(ContentTypeToDbFSKey(type), &volume)) {
+        stored_values_.SetDouble(ContentTypeToDbFSKey(type), volume);
+      }
+    }
+  }
+
+  base::Thread::Options options;
+  options.message_loop_type = base::MessageLoop::TYPE_IO;
+  thread_.StartWithOptions(options);
+
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&VolumeControlAndroid::InitializeOnThread,
+                            base::Unretained(this)));
+  initialize_complete_event_.Wait();
+}
+
+VolumeControlAndroid::~VolumeControlAndroid() {}
+
+void VolumeControlAndroid::AddVolumeObserver(VolumeObserver* observer) {
+  base::AutoLock lock(observer_lock_);
+  volume_observers_.push_back(observer);
+}
+
+void VolumeControlAndroid::RemoveVolumeObserver(VolumeObserver* observer) {
+  base::AutoLock lock(observer_lock_);
+  volume_observers_.erase(
+      std::remove(volume_observers_.begin(), volume_observers_.end(), observer),
+      volume_observers_.end());
+}
+
+float VolumeControlAndroid::GetVolume(AudioContentType type) {
+  base::AutoLock lock(volume_lock_);
+  return volumes_[type];
+}
+
+void VolumeControlAndroid::SetVolume(AudioContentType type, float level) {
+  level = std::max(0.0f, std::min(level, 1.0f));
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&VolumeControlAndroid::SetVolumeOnThread,
+                            base::Unretained(this), type, level));
+}
+
+bool VolumeControlAndroid::IsMuted(AudioContentType type) {
+  base::AutoLock lock(volume_lock_);
+  return muted_[type];
+}
+
+void VolumeControlAndroid::SetMuted(AudioContentType type, bool muted) {
+  thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&VolumeControlAndroid::SetMutedOnThread,
+                            base::Unretained(this), type, muted));
+}
+
+void VolumeControlAndroid::SetOutputLimit(AudioContentType type, float limit) {
+  limit = std::max(0.0f, std::min(limit, 1.0f));
+  AudioSinkManager::Get()->SetOutputLimit(
+      type, DbFsToScale(VolumeControl::VolumeToDbFS(limit)));
+}
+
+void VolumeControlAndroid::InitializeOnThread() {
+  DCHECK(thread_.task_runner()->BelongsToCurrentThread());
+
+  double dbfs;
+  for (auto type : {AudioContentType::kMedia, AudioContentType::kAlarm,
+                    AudioContentType::kCommunication}) {
+    CHECK(stored_values_.GetDouble(ContentTypeToDbFSKey(type), &dbfs));
+    volumes_[type] = VolumeControl::DbFSToVolume(dbfs);
+    AudioSinkManager::Get()->SetVolume(type, DbFsToScale(dbfs));
+
+    // Note that mute state is not persisted across reboots.
+    muted_[type] = false;
+  }
+  initialize_complete_event_.Signal();
+}
+
+void VolumeControlAndroid::SetVolumeOnThread(AudioContentType type,
+                                             float level) {
+  DCHECK(thread_.task_runner()->BelongsToCurrentThread());
+  {
+    base::AutoLock lock(volume_lock_);
+    if (level == volumes_[type]) {
+      return;
+    }
+    volumes_[type] = level;
+  }
+
+  float dbfs = VolumeControl::VolumeToDbFS(level);
+  LOG(INFO) << __func__ << ": level=" << level << " -> dbfs=" << dbfs;
+  AudioSinkManager::Get()->SetVolume(type, DbFsToScale(dbfs));
+
+  {
+    base::AutoLock lock(observer_lock_);
+    for (VolumeObserver* observer : volume_observers_) {
+      observer->OnVolumeChange(type, level);
+    }
+  }
+
+  stored_values_.SetDouble(ContentTypeToDbFSKey(type), dbfs);
+  SerializeJsonToFile(storage_path_, stored_values_);
+}
+
+void VolumeControlAndroid::SetMutedOnThread(AudioContentType type, bool muted) {
+  DCHECK(thread_.task_runner()->BelongsToCurrentThread());
+  {
+    base::AutoLock lock(volume_lock_);
+    if (muted == muted_[type]) {
+      return;
+    }
+    muted_[type] = muted;
+  }
+
+  AudioSinkManager::Get()->SetMuted(type, muted);
+
+  {
+    base::AutoLock lock(observer_lock_);
+    for (VolumeObserver* observer : volume_observers_) {
+      observer->OnMuteChange(type, muted);
+    }
+  }
+}
+
+//
+// Implementation of VolumeControl as defined in public/volume_control.h
+//
+
 // static
 void VolumeControl::Initialize(const std::vector<std::string>& argv) {
   // Nothing to do.
diff --git a/chromecast/media/cma/backend/android/volume_control_android.h b/chromecast/media/cma/backend/android/volume_control_android.h
new file mode 100644
index 0000000..1c564a59
--- /dev/null
+++ b/chromecast/media/cma/backend/android/volume_control_android.h
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMECAST_MEDIA_CMA_BACKEND_ANDROID_VOLUME_CONTROL_ANDROID_H_
+#define CHROMECAST_MEDIA_CMA_BACKEND_ANDROID_VOLUME_CONTROL_ANDROID_H_
+
+#include <map>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "chromecast/media/cma/backend/android/audio_sink_manager.h"
+
+namespace chromecast {
+namespace media {
+
+// TODO(ckuiper): This logic is similar to the one in alsa/volume_control.cc.
+// Consolidate it.
+class VolumeMap {
+ public:
+  struct LevelToDb {
+    float level;
+    float db;
+  };
+
+  VolumeMap();
+  ~VolumeMap();
+
+  float VolumeToDbFS(float volume);
+  float DbFSToVolume(float db);
+
+ private:
+  std::vector<LevelToDb> volume_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(VolumeMap);
+};
+
+// TODO(ckuiper): This logic is similar to the one in alsa/volume_control.cc.
+// Consolidate it.
+class VolumeControlAndroid {
+ public:
+  VolumeControlAndroid();
+  ~VolumeControlAndroid();
+
+  void AddVolumeObserver(VolumeObserver* observer);
+  void RemoveVolumeObserver(VolumeObserver* observer);
+  float GetVolume(AudioContentType type);
+  void SetVolume(AudioContentType type, float level);
+  bool IsMuted(AudioContentType type);
+  void SetMuted(AudioContentType type, bool muted);
+  void SetOutputLimit(AudioContentType type, float limit);
+
+ private:
+  void InitializeOnThread();
+  void SetVolumeOnThread(AudioContentType type, float level);
+  void SetMutedOnThread(AudioContentType type, bool muted);
+
+  base::FilePath storage_path_;
+  base::DictionaryValue stored_values_;
+
+  base::Lock volume_lock_;
+  std::map<AudioContentType, float> volumes_;
+  std::map<AudioContentType, bool> muted_;
+
+  base::Lock observer_lock_;
+  std::vector<VolumeObserver*> volume_observers_;
+
+  base::Thread thread_;
+  base::WaitableEvent initialize_complete_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(VolumeControlAndroid);
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_MEDIA_CMA_BACKEND_ANDROID_VOLUME_CONTROL_ANDROID_H_
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index ee83a82..aeda42b6 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -103,6 +103,7 @@
 CreditCard::CreditCard(const std::string& guid, const std::string& origin)
     : AutofillDataModel(guid, origin),
       record_type_(LOCAL_CARD),
+      card_type_(CARD_TYPE_UNKNOWN),
       network_(kGenericCard),
       expiration_month_(0),
       expiration_year_(0),
@@ -490,6 +491,7 @@
     return;
 
   record_type_ = credit_card.record_type_;
+  card_type_ = credit_card.card_type_;
   number_ = credit_card.number_;
   name_on_card_ = credit_card.name_on_card_;
   network_ = credit_card.network_;
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h
index ef83a56..4a58dab6b 100644
--- a/components/autofill/core/browser/credit_card.h
+++ b/components/autofill/core/browser/credit_card.h
@@ -46,6 +46,17 @@
     OK,
   };
 
+  // The type of the card. Local cards are all CARD_TYPE_UNKNOWN. Server cards
+  // may have a more specific type.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.autofill
+  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: CardType
+  enum CardType : int {
+    CARD_TYPE_UNKNOWN,
+    CARD_TYPE_CREDIT,
+    CARD_TYPE_DEBIT,
+    CARD_TYPE_PREPAID,
+  };
+
   CreditCard(const std::string& guid, const std::string& origin);
 
   // Creates a server card.  The type must be MASKED_SERVER_CARD or
@@ -150,6 +161,11 @@
   RecordType record_type() const { return record_type_; }
   void set_record_type(RecordType rt) { record_type_ = rt; }
 
+  // Whether this is a credit, debit, or prepaid card. Known only for server
+  // cards. All local cards are CARD_TYPE_UNKNOWN.
+  CardType card_type() const { return card_type_; }
+  void set_card_type(CardType card_type) { card_type_ = card_type; }
+
   // Returns true if there are no values (field types) set.
   bool IsEmpty(const std::string& app_locale) const;
 
@@ -242,6 +258,7 @@
 
   // See enum definition above.
   RecordType record_type_;
+  CardType card_type_;
 
   // The card number. For MASKED_SERVER_CARDs, this number will just contain the
   // last four digits of the card number.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index eae7022..1f4f00e5 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -836,6 +836,27 @@
     EXPECT_EQ(0, server_cards[i].Compare(*personal_data_->GetCreditCards()[i]));
 }
 
+TEST_F(PersonalDataManagerTest, SavesServerCardType) {
+  EnableWalletCardImport();
+  std::vector<CreditCard> server_cards;
+  server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
+  test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
+                          "9012" /* Visa */, "01", "2999", "1");
+  server_cards.back().SetNetworkForMaskedCard(kVisaCard);
+
+  server_cards.back().set_card_type(CreditCard::CARD_TYPE_DEBIT);
+
+  test::SetServerCreditCards(autofill_table_, server_cards);
+  personal_data_->Refresh();
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::RunLoop().Run();
+  auto cards = personal_data_->GetCreditCards();
+  ASSERT_EQ(1U, cards.size());
+
+  EXPECT_EQ(CreditCard::CARD_TYPE_DEBIT, cards.front()->card_type());
+}
+
 TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
   AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
   test::SetProfileInfo(&profile0,
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 1cf28e6..df5890d 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -476,6 +476,9 @@
     case 73:
       *update_compatible_version = false;
       return MigrateToVersion73AddMaskedCardBankName();
+    case 74:
+      *update_compatible_version = false;
+      return MigrateToVersion74AddServerCardTypeColumn();
   }
   return true;
 }
@@ -1219,12 +1222,13 @@
       "metadata.use_count,"           // 3
       "metadata.use_date,"            // 4
       "network,"                      // 5
-      "status,"                       // 6
-      "name_on_card,"                 // 7
-      "exp_month,"                    // 8
-      "exp_year,"                     // 9
-      "metadata.billing_address_id,"  // 10
-      "bank_name "                    // 11
+      "type,"                         // 6
+      "status,"                       // 7
+      "name_on_card,"                 // 8
+      "exp_month,"                    // 9
+      "exp_year,"                     // 10
+      "metadata.billing_address_id,"  // 11
+      "bank_name "                    // 12
       "FROM masked_credit_cards masked "
       "LEFT OUTER JOIN unmasked_credit_cards USING (id) "
       "LEFT OUTER JOIN server_card_metadata metadata USING (id)"));
@@ -1261,6 +1265,12 @@
       DCHECK_EQ(CreditCard::GetCardNetwork(full_card_number), card_network);
     }
 
+    int card_type = s.ColumnInt(index++);
+    if (card_type >= CreditCard::CARD_TYPE_UNKNOWN &&
+        card_type <= CreditCard::CARD_TYPE_PREPAID) {
+      card->set_card_type(static_cast<CreditCard::CardType>(card_type));
+    }
+
     card->SetServerStatus(ServerStatusStringToEnum(s.ColumnString(index++)));
     card->SetRawInfo(CREDIT_CARD_NAME_FULL, s.ColumnString16(index++));
     card->SetRawInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(index++));
@@ -1279,25 +1289,27 @@
       db_->GetUniqueStatement("INSERT INTO masked_credit_cards("
                               "id,"            // 0
                               "network,"       // 1
-                              "status,"        // 2
-                              "name_on_card,"  // 3
-                              "last_four,"     // 4
-                              "exp_month,"     // 5
-                              "exp_year,"      // 6
-                              "bank_name)"     // 7
-                              "VALUES (?,?,?,?,?,?,?,?)"));
+                              "type,"          // 2
+                              "status,"        // 3
+                              "name_on_card,"  // 4
+                              "last_four,"     // 5
+                              "exp_month,"     // 6
+                              "exp_year,"      // 7
+                              "bank_name)"     // 8
+                              "VALUES (?,?,?,?,?,?,?,?,?)"));
   for (const CreditCard& card : credit_cards) {
     DCHECK_EQ(CreditCard::MASKED_SERVER_CARD, card.record_type());
     masked_insert.BindString(0, card.server_id());
     masked_insert.BindString(1, card.network());
-    masked_insert.BindString(2,
+    masked_insert.BindInt(2, card.card_type());
+    masked_insert.BindString(3,
                              ServerStatusEnumToString(card.GetServerStatus()));
-    masked_insert.BindString16(3, card.GetRawInfo(CREDIT_CARD_NAME_FULL));
-    masked_insert.BindString16(4, card.LastFourDigits());
-    masked_insert.BindString16(5, card.GetRawInfo(CREDIT_CARD_EXP_MONTH));
-    masked_insert.BindString16(6,
+    masked_insert.BindString16(4, card.GetRawInfo(CREDIT_CARD_NAME_FULL));
+    masked_insert.BindString16(5, card.LastFourDigits());
+    masked_insert.BindString16(6, card.GetRawInfo(CREDIT_CARD_EXP_MONTH));
+    masked_insert.BindString16(7,
                                card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
-    masked_insert.BindString(7, card.bank_name());
+    masked_insert.BindString(8, card.bank_name());
     masked_insert.Run();
     masked_insert.Reset(true);
 
@@ -1362,12 +1374,12 @@
 
 void AutofillTable::AddUnmaskedCreditCard(const std::string& id,
                                           const base::string16& full_number) {
-  sql::Statement s(db_->GetUniqueStatement(
-      "INSERT INTO unmasked_credit_cards("
-          "id,"
-          "card_number_encrypted,"
-          "unmask_date)"
-      "VALUES (?,?,?)"));
+  sql::Statement s(
+      db_->GetUniqueStatement("INSERT INTO unmasked_credit_cards("
+                              "id,"
+                              "card_number_encrypted,"
+                              "unmask_date)"
+                              "VALUES (?,?,?)"));
   s.BindString(0, id);
 
   std::string encrypted_data;
@@ -1964,7 +1976,8 @@
                       "last_four VARCHAR,"
                       "exp_month INTEGER DEFAULT 0,"
                       "exp_year INTEGER DEFAULT 0, "
-                      "bank_name VARCHAR)")) {
+                      "bank_name VARCHAR, "
+                      "type INTEGER DEFAULT 0)")) {
       NOTREACHED();
       return false;
     }
@@ -2622,4 +2635,9 @@
   return transaction.Commit();
 }
 
+bool AutofillTable::MigrateToVersion74AddServerCardTypeColumn() {
+  return db_->Execute(
+      "ALTER TABLE masked_credit_cards ADD COLUMN type INTEGER DEFAULT 0");
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index 22625148..9563441 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -162,6 +162,8 @@
 //   name_on_card
 //   network            Issuer network of the card. For example, "VISA". Renamed
 //                      from "type" in version 72.
+//   type               Card type. One of CreditCard::CardType enum values.
+//                      Added in version 74.
 //   last_four          Last four digits of the card number. For de-duping
 //                      with locally stored cards and generating descriptions.
 //   exp_month          Expiration month: 1-12
@@ -466,6 +468,7 @@
   bool MigrateToVersion71AddHasConvertedAndBillingAddressIdMetadata();
   bool MigrateToVersion72RenameCardTypeToIssuerNetwork();
   bool MigrateToVersion73AddMaskedCardBankName();
+  bool MigrateToVersion74AddServerCardTypeColumn();
 
   // Max data length saved in the table, AKA the maximum length allowed for
   // form data.
@@ -475,9 +478,8 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill);
   FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_AddChanges);
-  FRIEND_TEST_ALL_PREFIXES(
-      AutofillTableTest,
-      Autofill_GetCountOfValuesContainedBetween);
+  FRIEND_TEST_ALL_PREFIXES(AutofillTableTest,
+                           Autofill_GetCountOfValuesContainedBetween);
   FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_RemoveBetweenChanges);
   FRIEND_TEST_ALL_PREFIXES(AutofillTableTest, Autofill_UpdateDontReplace);
   FRIEND_TEST_ALL_PREFIXES(
@@ -513,10 +515,9 @@
 
   // Methods for adding autofill entries at a specified time.  For
   // testing only.
-  bool AddFormFieldValuesTime(
-      const std::vector<FormFieldData>& elements,
-      std::vector<AutofillChange>* changes,
-      base::Time time);
+  bool AddFormFieldValuesTime(const std::vector<FormFieldData>& elements,
+                              std::vector<AutofillChange>* changes,
+                              base::Time time);
   bool AddFormFieldValueTime(const FormFieldData& element,
                              std::vector<AutofillChange>* changes,
                              base::Time time);
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index af81aeaa..bbbdba8 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -35,7 +35,7 @@
   return reinterpret_cast<void*>(&user_data_key);
 }
 
-const char* CardTypeFromWalletCardType(
+const char* CardNetworkFromWalletCardType(
     sync_pb::WalletMaskedCreditCard::WalletCardType type) {
   switch (type) {
     case sync_pb::WalletMaskedCreditCard::AMEX:
@@ -60,6 +60,20 @@
   }
 }
 
+CreditCard::CardType CardTypeFromWalletCardClass(
+    sync_pb::WalletMaskedCreditCard::WalletCardClass card_class) {
+  switch (card_class) {
+    case sync_pb::WalletMaskedCreditCard::CREDIT:
+      return CreditCard::CARD_TYPE_CREDIT;
+    case sync_pb::WalletMaskedCreditCard::DEBIT:
+      return CreditCard::CARD_TYPE_DEBIT;
+    case sync_pb::WalletMaskedCreditCard::PREPAID:
+      return CreditCard::CARD_TYPE_PREPAID;
+    default:
+      return CreditCard::CARD_TYPE_UNKNOWN;
+  }
+}
+
 CreditCard::ServerStatus ServerToLocalStatus(
     sync_pb::WalletMaskedCreditCard::WalletCardStatus status) {
   switch (status) {
@@ -76,7 +90,8 @@
   CreditCard result(CreditCard::MASKED_SERVER_CARD, card.id());
   result.SetNumber(base::UTF8ToUTF16(card.last_four()));
   result.SetServerStatus(ServerToLocalStatus(card.status()));
-  result.SetNetworkForMaskedCard(CardTypeFromWalletCardType(card.type()));
+  result.SetNetworkForMaskedCard(CardNetworkFromWalletCardType(card.type()));
+  result.set_card_type(CardTypeFromWalletCardClass(card.card_class()));
   result.SetRawInfo(CREDIT_CARD_NAME_FULL,
                     base::UTF8ToUTF16(card.name_on_card()));
   result.SetExpirationMonth(card.exp_month());
@@ -99,8 +114,7 @@
   profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name()));
   profile.SetRawInfo(ADDRESS_HOME_STATE,
                      base::UTF8ToUTF16(address.address_1()));
-  profile.SetRawInfo(ADDRESS_HOME_CITY,
-                     base::UTF8ToUTF16(address.address_2()));
+  profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(address.address_2()));
   profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
                      base::UTF8ToUTF16(address.address_3()));
   // AutofillProfile doesn't support address_4 ("sub dependent locality").
@@ -193,11 +207,9 @@
 AutofillWalletSyncableService::AutofillWalletSyncableService(
     AutofillWebDataBackend* webdata_backend,
     const std::string& app_locale)
-    : webdata_backend_(webdata_backend) {
-}
+    : webdata_backend_(webdata_backend) {}
 
-AutofillWalletSyncableService::~AutofillWalletSyncableService() {
-}
+AutofillWalletSyncableService::~AutofillWalletSyncableService() {}
 
 syncer::SyncMergeResult AutofillWalletSyncableService::MergeDataAndStartSyncing(
     syncer::ModelType type,
@@ -343,10 +355,8 @@
   size_t prev_card_count = 0;
   size_t prev_address_count = 0;
   bool changed_cards = SetDataIfChanged(
-      table, wallet_cards,
-      &AutofillTable::GetServerCreditCards,
-      &AutofillTable::SetServerCreditCards,
-      &prev_card_count);
+      table, wallet_cards, &AutofillTable::GetServerCreditCards,
+      &AutofillTable::SetServerCreditCards, &prev_card_count);
   bool changed_addresses = SetDataIfChanged(
       table, wallet_addresses, &AutofillTable::GetServerProfiles,
       &AutofillTable::SetServerProfiles, &prev_address_count);
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 811f6306..5e727a3 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -195,6 +195,8 @@
       "//components/cronet/android/url_request_error.h",
       "//components/cronet/histogram_manager.cc",
       "//components/cronet/histogram_manager.h",
+      "//components/cronet/host_cache_persistence_manager.cc",
+      "//components/cronet/host_cache_persistence_manager.h",
       "//components/cronet/stale_host_resolver.cc",
       "//components/cronet/stale_host_resolver.h",
       "//components/cronet/url_request_context_config.cc",
@@ -900,6 +902,7 @@
   sources = [
     "//components/cronet/android/cert/cert_verifier_cache_serializer_unittest.cc",
     "//components/cronet/histogram_manager_unittest.cc",
+    "//components/cronet/host_cache_persistence_manager_unittest.cc",
     "//components/cronet/run_all_unittests.cc",
     "//components/cronet/stale_host_resolver_unittest.cc",
     "//components/cronet/url_request_context_config_unittest.cc",
@@ -911,6 +914,7 @@
     "//base",
     "//base/test:test_support",
     "//components/metrics",
+    "//components/prefs:test_support",
     "//net",
     "//net:test_support",
     "//net/android:net_java",
diff --git a/components/cronet/host_cache_persistence_manager.cc b/components/cronet/host_cache_persistence_manager.cc
new file mode 100644
index 0000000..4b47809
--- /dev/null
+++ b/components/cronet/host_cache_persistence_manager.cc
@@ -0,0 +1,78 @@
+// 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/cronet/host_cache_persistence_manager.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "components/prefs/pref_service.h"
+
+namespace cronet {
+
+HostCachePersistenceManager::HostCachePersistenceManager(
+    net::HostCache* cache,
+    PrefService* pref_service,
+    std::string pref_name,
+    base::TimeDelta delay)
+    : cache_(cache),
+      pref_service_(pref_service),
+      pref_name_(pref_name),
+      delay_(delay),
+      weak_factory_(this) {
+  DCHECK(cache_);
+  DCHECK(pref_service_);
+
+  // Get the initial value of the pref if it's already initialized.
+  if (pref_service_->HasPrefPath(pref_name_))
+    ReadFromDisk();
+
+  registrar_.Init(pref_service_);
+  registrar_.Add(pref_name_,
+                 base::Bind(&HostCachePersistenceManager::ReadFromDisk,
+                            weak_factory_.GetWeakPtr()));
+  cache_->set_persistence_delegate(this);
+}
+
+HostCachePersistenceManager::~HostCachePersistenceManager() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  timer_.Stop();
+  registrar_.RemoveAll();
+  cache_->set_persistence_delegate(nullptr);
+}
+
+void HostCachePersistenceManager::ReadFromDisk() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (writing_pref_)
+    return;
+
+  const base::ListValue* pref_value = pref_service_->GetList(pref_name_);
+  cache_->RestoreFromListValue(*pref_value);
+}
+
+void HostCachePersistenceManager::ScheduleWrite() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (timer_.IsRunning())
+    return;
+
+  timer_.Start(FROM_HERE, delay_,
+               base::Bind(&HostCachePersistenceManager::WriteToDisk,
+                          weak_factory_.GetWeakPtr()));
+}
+
+void HostCachePersistenceManager::WriteToDisk() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  base::ListValue value;
+  cache_->GetAsListValue(&value, false);
+  writing_pref_ = true;
+  pref_service_->Set(pref_name_, value);
+  writing_pref_ = false;
+}
+
+}  // namespace cronet
diff --git a/components/cronet/host_cache_persistence_manager.h b/components/cronet/host_cache_persistence_manager.h
new file mode 100644
index 0000000..156f96639
--- /dev/null
+++ b/components/cronet/host_cache_persistence_manager.h
@@ -0,0 +1,73 @@
+// 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_CRONET_HOST_CACHE_PERSISTENCE_MANAGER_H_
+#define COMPONENTS_CRONET_HOST_CACHE_PERSISTENCE_MANAGER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "net/dns/host_cache.h"
+
+class PrefService;
+
+namespace cronet {
+// Handles the interaction between HostCache and prefs for persistence.
+// When notified of a change in the HostCache, starts a timer, or ignores if the
+// timer is already running. When that timer expires, writes the current state
+// of the HostCache to prefs.
+//
+// Can be used with synchronous or asynchronous prefs loading. Not appropriate
+// for use outside of Cronet because its network and prefs operations run on
+// the same sequence. Must be created after and destroyed before the HostCache
+// and PrefService.
+class HostCachePersistenceManager : public net::HostCache::PersistenceDelegate {
+ public:
+  // |cache| is the HostCache whose contents will be persisted. It must be
+  // non-null and must outlive the HostCachePersistenceManager.
+  // |pref_service| is the PrefService that will be used to persist the cache
+  // contents. It must outlive the HostCachePersistenceManager.
+  // |pref_name| is the name of the pref to read and write.
+  // |delay| is the maximum time between a change in the cache and writing that
+  // change to prefs.
+  HostCachePersistenceManager(net::HostCache* cache,
+                              PrefService* pref_service,
+                              std::string pref_name,
+                              base::TimeDelta delay);
+  virtual ~HostCachePersistenceManager();
+
+  // net::HostCache::PersistenceDelegate implementation
+  void ScheduleWrite() override;
+
+ private:
+  // Gets the serialized HostCache and writes it to prefs.
+  void WriteToDisk();
+  // On initial prefs read, passes the serialized entries to the HostCache.
+  void ReadFromDisk();
+
+  net::HostCache* const cache_;
+
+  PrefChangeRegistrar registrar_;
+  PrefService* const pref_service_;
+  const std::string pref_name_;
+  bool writing_pref_;
+
+  const base::TimeDelta delay_;
+  base::OneShotTimer timer_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  base::WeakPtrFactory<HostCachePersistenceManager> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(HostCachePersistenceManager);
+};
+
+}  // namespace cronet
+
+#endif  // COMPONENTS_CRONET_HOST_CACHE_PERSISTENCE_MANAGER_H_
diff --git a/components/cronet/host_cache_persistence_manager_unittest.cc b/components/cronet/host_cache_persistence_manager_unittest.cc
new file mode 100644
index 0000000..7a8eaae
--- /dev/null
+++ b/components/cronet/host_cache_persistence_manager_unittest.cc
@@ -0,0 +1,182 @@
+// 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/cronet/host_cache_persistence_manager.h"
+
+#include "base/test/scoped_mock_time_message_loop_task_runner.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/values.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "net/base/net_errors.h"
+#include "net/dns/host_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cronet {
+
+class HostCachePersistenceManagerTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    cache_ = net::HostCache::CreateDefaultCache();
+    pref_service_ = base::MakeUnique<TestingPrefServiceSimple>();
+    pref_service_->registry()->RegisterListPref(kPrefName);
+  }
+
+  void MakePersistenceManager(base::TimeDelta delay) {
+    persistence_manager_ = base::MakeUnique<HostCachePersistenceManager>(
+        cache_.get(), pref_service_.get(), kPrefName, delay);
+  }
+
+  // Sets an entry in the HostCache in order to trigger a pref write. The
+  // caller is responsible for making sure this is a change that will trigger
+  // a write, and the HostCache's interaction with its PersistenceDelegate is
+  // assumed to work (it's tested in net/dns/host_cache_unittest.cc).
+  void WriteToCache(const std::string& host) {
+    net::HostCache::Key key(host, net::ADDRESS_FAMILY_UNSPECIFIED, 0);
+    net::HostCache::Entry entry(net::OK, net::AddressList());
+    cache_->Set(key, entry, base::TimeTicks::Now(),
+                base::TimeDelta::FromSeconds(1));
+  }
+
+  // Reads the current value of the pref from the TestingPrefServiceSimple
+  // and deserializes it into a temporary new HostCache. Only checks the size,
+  // not the full contents, since the tests in this file are only intended
+  // to test that writes happen when they're supposed to, not serialization
+  // correctness.
+  void CheckPref(uint size) {
+    const base::Value* value = pref_service_->GetUserPref(kPrefName);
+    base::ListValue list;
+    if (value)
+      list = base::ListValue(value->GetList());
+    net::HostCache temp_cache(10);
+    temp_cache.RestoreFromListValue(list);
+    ASSERT_EQ(size, temp_cache.size());
+  }
+
+  // Generates a temporary HostCache with a few entries and uses it to
+  // initialize the value in prefs.
+  void InitializePref() {
+    net::HostCache temp_cache(10);
+
+    net::HostCache::Key key1("1", net::ADDRESS_FAMILY_UNSPECIFIED, 0);
+    net::HostCache::Key key2("2", net::ADDRESS_FAMILY_UNSPECIFIED, 0);
+    net::HostCache::Key key3("3", net::ADDRESS_FAMILY_UNSPECIFIED, 0);
+    net::HostCache::Entry entry(net::OK, net::AddressList());
+
+    temp_cache.Set(key1, entry, base::TimeTicks::Now(),
+                   base::TimeDelta::FromSeconds(1));
+    temp_cache.Set(key2, entry, base::TimeTicks::Now(),
+                   base::TimeDelta::FromSeconds(1));
+    temp_cache.Set(key3, entry, base::TimeTicks::Now(),
+                   base::TimeDelta::FromSeconds(1));
+
+    base::ListValue value;
+    temp_cache.GetAsListValue(&value, false);
+    pref_service_->Set(kPrefName, value);
+  }
+
+  static const char kPrefName[];
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  base::ScopedMockTimeMessageLoopTaskRunner task_runner_;
+
+  // The HostCache and PrefService have to outlive the
+  // HostCachePersistenceManager.
+  std::unique_ptr<net::HostCache> cache_;
+  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+  std::unique_ptr<HostCachePersistenceManager> persistence_manager_;
+};
+
+const char HostCachePersistenceManagerTest::kPrefName[] = "net.test";
+
+// Make a single change to the HostCache and make sure that it's written
+// when the timer expires. Then repeat.
+TEST_F(HostCachePersistenceManagerTest, SeparateWrites) {
+  MakePersistenceManager(base::TimeDelta::FromSeconds(60));
+
+  WriteToCache("1");
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(59));
+  CheckPref(0);
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  CheckPref(1);
+
+  WriteToCache("2");
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(59));
+  CheckPref(1);
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  CheckPref(2);
+}
+
+// Write to the HostCache multiple times and make sure that all changes
+// are written to prefs at the appropriate times.
+TEST_F(HostCachePersistenceManagerTest, MultipleWrites) {
+  MakePersistenceManager(base::TimeDelta::FromSeconds(300));
+
+  WriteToCache("1");
+  WriteToCache("2");
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(299));
+  CheckPref(0);
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  CheckPref(2);
+
+  WriteToCache("3");
+  WriteToCache("4");
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(299));
+  CheckPref(2);
+  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  CheckPref(4);
+}
+
+// Make changes to the HostCache at different times and ensure that the writes
+// to prefs are batched as expected.
+TEST_F(HostCachePersistenceManagerTest, BatchedWrites) {
+  MakePersistenceManager(base::TimeDelta::FromMilliseconds(100));
+
+  WriteToCache("1");
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(30));
+  WriteToCache("2");
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(30));
+  WriteToCache("3");
+  CheckPref(0);
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(40));
+  CheckPref(3);
+
+  // Add a delay in between batches.
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
+
+  WriteToCache("4");
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(30));
+  WriteToCache("5");
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(30));
+  WriteToCache("6");
+  CheckPref(3);
+  task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(40));
+  CheckPref(6);
+}
+
+// Set the pref before the HostCachePersistenceManager is created, and make
+// sure it gets picked up by the HostCache.
+TEST_F(HostCachePersistenceManagerTest, InitAfterPrefs) {
+  CheckPref(0);
+  InitializePref();
+  CheckPref(3);
+
+  MakePersistenceManager(base::TimeDelta::FromSeconds(1));
+  task_runner_->RunUntilIdle();
+  ASSERT_EQ(3u, cache_->size());
+}
+
+// Set the pref after the HostCachePersistenceManager is created, and make
+// sure it gets picked up by the HostCache.
+TEST_F(HostCachePersistenceManagerTest, InitBeforePrefs) {
+  MakePersistenceManager(base::TimeDelta::FromSeconds(1));
+  ASSERT_EQ(0u, cache_->size());
+
+  CheckPref(0);
+  InitializePref();
+  CheckPref(3);
+  ASSERT_EQ(3u, cache_->size());
+}
+
+}  // namespace cronet
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 78f15c4..ea1e1e2 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -262,7 +262,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WMHelper::CursorObserver overrides:
 
-void Pointer::OnCursorSetChanged(ui::CursorSetType cursor_set) {
+void Pointer::OnCursorSizeChanged(ui::CursorSize cursor_size) {
   if (focus_)
     UpdateCursor();
 }
@@ -394,7 +394,7 @@
     float scale = helper->GetDisplayInfo(display.id()).device_scale_factor() /
                   capture_scale_;
 
-    if (helper->GetCursorSet() == ui::CURSOR_SET_LARGE)
+    if (helper->GetCursorSize() == ui::CursorSize::kLarge)
       scale *= kLargeCursorScale;
 
     ui::ScaleAndRotateCursorBitmapAndHotpoint(scale, display.rotation(),
diff --git a/components/exo/pointer.h b/components/exo/pointer.h
index 74c5b97..6dc1a0b 100644
--- a/components/exo/pointer.h
+++ b/components/exo/pointer.h
@@ -60,7 +60,7 @@
   void OnScrollEvent(ui::ScrollEvent* event) override;
 
   // Overridden from WMHelper::CursorObserver:
-  void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
+  void OnCursorSizeChanged(ui::CursorSize cursor_size) override;
   void OnCursorDisplayChanged(const display::Display& display) override;
 
   // Overridden from WMHelper::DisplayConfigurationObserver:
diff --git a/components/exo/wm_helper.cc b/components/exo/wm_helper.cc
index a24aa2f..a1103174 100644
--- a/components/exo/wm_helper.cc
+++ b/components/exo/wm_helper.cc
@@ -98,9 +98,9 @@
     observer.OnCursorVisibilityChanged(is_visible);
 }
 
-void WMHelper::NotifyCursorSetChanged(ui::CursorSetType cursor_set) {
+void WMHelper::NotifyCursorSizeChanged(ui::CursorSize cursor_size) {
   for (CursorObserver& observer : cursor_observers_)
-    observer.OnCursorSetChanged(cursor_set);
+    observer.OnCursorSizeChanged(cursor_size);
 }
 
 void WMHelper::NotifyCursorDisplayChanged(const display::Display& display) {
diff --git a/components/exo/wm_helper.h b/components/exo/wm_helper.h
index d68237c..8ed149e 100644
--- a/components/exo/wm_helper.h
+++ b/components/exo/wm_helper.h
@@ -48,7 +48,7 @@
   class CursorObserver {
    public:
     virtual void OnCursorVisibilityChanged(bool is_visible) {}
-    virtual void OnCursorSetChanged(ui::CursorSetType cursor_set) {}
+    virtual void OnCursorSizeChanged(ui::CursorSize cursor_size) {}
     virtual void OnCursorDisplayChanged(const display::Display& display) {}
 
    protected:
@@ -105,7 +105,7 @@
   virtual aura::Window* GetPrimaryDisplayContainer(int container_id) = 0;
   virtual aura::Window* GetActiveWindow() const = 0;
   virtual aura::Window* GetFocusedWindow() const = 0;
-  virtual ui::CursorSetType GetCursorSet() const = 0;
+  virtual ui::CursorSize GetCursorSize() const = 0;
   virtual const display::Display& GetCursorDisplay() const = 0;
   virtual void AddPreTargetHandler(ui::EventHandler* handler) = 0;
   virtual void PrependPreTargetHandler(ui::EventHandler* handler) = 0;
@@ -122,7 +122,7 @@
   void NotifyWindowFocused(aura::Window* gained_focus,
                            aura::Window* lost_focus);
   void NotifyCursorVisibilityChanged(bool is_visible);
-  void NotifyCursorSetChanged(ui::CursorSetType cursor_set);
+  void NotifyCursorSizeChanged(ui::CursorSize cursor_size);
   void NotifyCursorDisplayChanged(const display::Display& display);
   void NotifyMaximizeModeStarted();
   void NotifyMaximizeModeEnding();
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc
index 70764d0..daef7ad 100644
--- a/components/exo/wm_helper_ash.cc
+++ b/components/exo/wm_helper_ash.cc
@@ -70,11 +70,11 @@
   return focus_client->GetFocusedWindow();
 }
 
-ui::CursorSetType WMHelperAsh::GetCursorSet() const {
+ui::CursorSize WMHelperAsh::GetCursorSize() const {
   // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
   if (ash::Shell::GetAshConfig() == ash::Config::MUS)
-    return ui::CURSOR_SET_NORMAL;
-  return ash::Shell::Get()->cursor_manager()->GetCursorSet();
+    return ui::CursorSize::kNormal;
+  return ash::Shell::Get()->cursor_manager()->GetCursorSize();
 }
 
 const display::Display& WMHelperAsh::GetCursorDisplay() const {
@@ -128,8 +128,8 @@
   NotifyCursorVisibilityChanged(is_visible);
 }
 
-void WMHelperAsh::OnCursorSetChanged(ui::CursorSetType cursor_set) {
-  NotifyCursorSetChanged(cursor_set);
+void WMHelperAsh::OnCursorSizeChanged(ui::CursorSize cursor_size) {
+  NotifyCursorSizeChanged(cursor_size);
 }
 
 void WMHelperAsh::OnCursorDisplayChanged(const display::Display& display) {
diff --git a/components/exo/wm_helper_ash.h b/components/exo/wm_helper_ash.h
index 52986246..3e1fa32 100644
--- a/components/exo/wm_helper_ash.h
+++ b/components/exo/wm_helper_ash.h
@@ -34,7 +34,7 @@
   aura::Window* GetPrimaryDisplayContainer(int container_id) override;
   aura::Window* GetActiveWindow() const override;
   aura::Window* GetFocusedWindow() const override;
-  ui::CursorSetType GetCursorSet() const override;
+  ui::CursorSize GetCursorSize() const override;
   const display::Display& GetCursorDisplay() const override;
   void AddPreTargetHandler(ui::EventHandler* handler) override;
   void PrependPreTargetHandler(ui::EventHandler* handler) override;
@@ -54,7 +54,7 @@
 
   // Overridden from aura::client::CursorClientObserver:
   void OnCursorVisibilityChanged(bool is_visible) override;
-  void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
+  void OnCursorSizeChanged(ui::CursorSize cursor_size) override;
   void OnCursorDisplayChanged(const display::Display& display) override;
 
   // Overridden from ash::ShellObserver:
diff --git a/components/exo/wm_helper_mus.cc b/components/exo/wm_helper_mus.cc
index 99028b75..2bf0338 100644
--- a/components/exo/wm_helper_mus.cc
+++ b/components/exo/wm_helper_mus.cc
@@ -58,9 +58,9 @@
   return focused_window_;
 }
 
-ui::CursorSetType WMHelperMus::GetCursorSet() const {
+ui::CursorSize WMHelperMus::GetCursorSize() const {
   NOTIMPLEMENTED();
-  return ui::CursorSetType::CURSOR_SET_NORMAL;
+  return ui::CursorSize::kNormal;
 }
 
 const display::Display& WMHelperMus::GetCursorDisplay() const {
diff --git a/components/exo/wm_helper_mus.h b/components/exo/wm_helper_mus.h
index 017d33f..205442a7 100644
--- a/components/exo/wm_helper_mus.h
+++ b/components/exo/wm_helper_mus.h
@@ -33,7 +33,7 @@
   aura::Window* GetPrimaryDisplayContainer(int container_id) override;
   aura::Window* GetActiveWindow() const override;
   aura::Window* GetFocusedWindow() const override;
-  ui::CursorSetType GetCursorSet() const override;
+  ui::CursorSize GetCursorSize() const override;
   const display::Display& GetCursorDisplay() const override;
   void AddPreTargetHandler(ui::EventHandler* handler) override;
   void PrependPreTargetHandler(ui::EventHandler* handler) override;
diff --git a/components/metrics/net/network_metrics_provider.cc b/components/metrics/net/network_metrics_provider.cc
index c28b989..df7a8752 100644
--- a/components/metrics/net/network_metrics_provider.cc
+++ b/components/metrics/net/network_metrics_provider.cc
@@ -42,6 +42,29 @@
       network_quality_estimator_provider->GetNetworkQualityEstimator());
 }
 
+SystemProfileProto::Network::EffectiveConnectionType
+ConvertEffectiveConnectionType(
+    net::EffectiveConnectionType effective_connection_type) {
+  switch (effective_connection_type) {
+    case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
+      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+    case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
+      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
+    case net::EFFECTIVE_CONNECTION_TYPE_2G:
+      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G;
+    case net::EFFECTIVE_CONNECTION_TYPE_3G:
+      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_3G;
+    case net::EFFECTIVE_CONNECTION_TYPE_4G:
+      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G;
+    case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
+    case net::EFFECTIVE_CONNECTION_TYPE_LAST:
+      NOTREACHED();
+      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+  }
+  NOTREACHED();
+  return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+}
+
 }  // namespace
 
 // Listens to the changes in the effective conection type.
@@ -112,7 +135,8 @@
       network_quality_estimator_provider_(
           std::move(network_quality_estimator_provider)),
       effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
-      effective_connection_type_is_ambiguous_(false),
+      min_effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+      max_effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
       weak_ptr_factory_(this) {
   net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
   connection_type_ = net::NetworkChangeNotifier::GetConnectionType();
@@ -179,7 +203,11 @@
   network->set_wifi_phy_layer_protocol_is_ambiguous(
       wifi_phy_layer_protocol_is_ambiguous_);
   network->set_wifi_phy_layer_protocol(GetWifiPHYLayerProtocol());
-  network->set_effective_connection_type(GetEffectiveConnectionType());
+
+  network->set_min_effective_connection_type(
+      ConvertEffectiveConnectionType(min_effective_connection_type_));
+  network->set_max_effective_connection_type(
+      ConvertEffectiveConnectionType(max_effective_connection_type_));
 
   // Update the connection type. Note that this is necessary to set the network
   // type to "none" if there is no network connection for an entire UMA logging
@@ -189,7 +217,8 @@
   // Reset the "ambiguous" flags, since a new metrics log session has started.
   connection_type_is_ambiguous_ = false;
   wifi_phy_layer_protocol_is_ambiguous_ = false;
-  effective_connection_type_is_ambiguous_ = false;
+  min_effective_connection_type_ = effective_connection_type_;
+  max_effective_connection_type_ = effective_connection_type_;
 
   if (!wifi_access_point_info_provider_.get()) {
 #if defined(OS_CHROMEOS)
@@ -222,7 +251,6 @@
   if (type != connection_type_ &&
       connection_type_ != net::NetworkChangeNotifier::CONNECTION_NONE) {
     connection_type_is_ambiguous_ = true;
-    effective_connection_type_is_ambiguous_ = true;
   }
   connection_type_ = type;
 
@@ -277,34 +305,6 @@
   return SystemProfileProto::Network::WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
 }
 
-SystemProfileProto::Network::EffectiveConnectionType
-NetworkMetricsProvider::GetEffectiveConnectionType() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (effective_connection_type_is_ambiguous_)
-    return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS;
-
-  switch (effective_connection_type_) {
-    case net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-    case net::EFFECTIVE_CONNECTION_TYPE_OFFLINE:
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_OFFLINE;
-    case net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
-    case net::EFFECTIVE_CONNECTION_TYPE_2G:
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G;
-    case net::EFFECTIVE_CONNECTION_TYPE_3G:
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_3G;
-    case net::EFFECTIVE_CONNECTION_TYPE_4G:
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_4G;
-    case net::EFFECTIVE_CONNECTION_TYPE_LAST:
-      NOTREACHED();
-      return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-  }
-  NOTREACHED();
-  return SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-}
-
 void NetworkMetricsProvider::ProbeWifiPHYLayerProtocol() {
   DCHECK(thread_checker_.CalledOnValidThread());
   base::PostTaskWithTraitsAndReplyWithResult(
@@ -427,12 +427,35 @@
 void NetworkMetricsProvider::OnEffectiveConnectionTypeChanged(
     net::EffectiveConnectionType type) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (effective_connection_type_ != type &&
-      type != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN &&
-      effective_connection_type_ != net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
-    effective_connection_type_is_ambiguous_ = true;
-  }
   effective_connection_type_ = type;
+
+  if (effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
+      effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
+    // The effective connection type may be reported as Unknown if there is a
+    // change in the connection type. Disregard it since network requests can't
+    // be send during the changes in connection type. Similarly, disregard
+    // offline as the type since it may be reported as the effective connection
+    // type for a short period when there is a change in the connection type.
+    return;
+  }
+
+  if (min_effective_connection_type_ ==
+          net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN &&
+      max_effective_connection_type_ ==
+          net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+    min_effective_connection_type_ = type;
+    max_effective_connection_type_ = type;
+    return;
+  }
+
+  min_effective_connection_type_ =
+      std::min(min_effective_connection_type_, effective_connection_type_);
+  max_effective_connection_type_ =
+      std::max(max_effective_connection_type_, effective_connection_type_);
+
+  DCHECK_EQ(
+      min_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+      max_effective_connection_type_ == net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
 }
 
 }  // namespace metrics
diff --git a/components/metrics/net/network_metrics_provider.h b/components/metrics/net/network_metrics_provider.h
index 6d13ac3..69d514a 100644
--- a/components/metrics/net/network_metrics_provider.h
+++ b/components/metrics/net/network_metrics_provider.h
@@ -76,8 +76,6 @@
   SystemProfileProto::Network::ConnectionType GetConnectionType() const;
   SystemProfileProto::Network::WifiPHYLayerProtocol GetWifiPHYLayerProtocol()
       const;
-  SystemProfileProto::Network::EffectiveConnectionType
-  GetEffectiveConnectionType() const;
 
   // Posts a call to net::GetWifiPHYLayerProtocol on the blocking pool.
   void ProbeWifiPHYLayerProtocol();
@@ -133,9 +131,10 @@
   // Last known effective connection type.
   net::EffectiveConnectionType effective_connection_type_;
 
-  // True if |effective_connection_type_| changed during the lifetime of the
-  // log.
-  bool effective_connection_type_is_ambiguous_;
+  // Minimum and maximum effective connection type since the metrics were last
+  // provided.
+  net::EffectiveConnectionType min_effective_connection_type_;
+  net::EffectiveConnectionType max_effective_connection_type_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/components/metrics/net/network_metrics_provider_unittest.cc b/components/metrics/net/network_metrics_provider_unittest.cc
index 5701538..469a409 100644
--- a/components/metrics/net/network_metrics_provider_unittest.cc
+++ b/components/metrics/net/network_metrics_provider_unittest.cc
@@ -74,26 +74,41 @@
 
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
             network_metrics_provider.effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            network_metrics_provider.min_effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            network_metrics_provider.max_effective_connection_type_);
   network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
   EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
-            system_profile.network().effective_connection_type());
+            system_profile.network().min_effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            system_profile.network().max_effective_connection_type());
 
   // Set RTT so that the effective connection type is computed as 2G.
   estimator.set_recent_http_rtt(base::TimeDelta::FromMilliseconds(1500));
   estimator.set_start_time_null_http_rtt(
       base::TimeDelta::FromMilliseconds(1500));
-
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
             network_metrics_provider.effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            network_metrics_provider.min_effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            network_metrics_provider.max_effective_connection_type_);
   // Running a request would cause the effective connection type to be computed
   // as 2G, and observers to be notified.
   estimator.RunOneRequest();
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
             network_metrics_provider.effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+            network_metrics_provider.min_effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+            network_metrics_provider.max_effective_connection_type_);
   network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
   EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
-            system_profile.network().effective_connection_type());
+            system_profile.network().min_effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+            system_profile.network().max_effective_connection_type());
 
   // Set RTT so that the effective connection type is computed as SLOW_2G.
   estimator.set_recent_http_rtt(base::TimeDelta::FromMilliseconds(3000));
@@ -105,22 +120,29 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
             network_metrics_provider.effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+            network_metrics_provider.min_effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+            network_metrics_provider.max_effective_connection_type_);
   network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
-  // Effective connection type is set to ambiguous since the effective
-  // connection type changed from 2G to SLOW_2G during the lifetime of the log.
-  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS,
-            system_profile.network().effective_connection_type());
+  // Effective connection type changed from 2G to SLOW_2G during the lifetime of
+  // the log. Minimum value of ECT must be different from the maximum value.
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+            system_profile.network().min_effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+            system_profile.network().max_effective_connection_type());
 
-  // Getting the system profile again should return the actual effective
-  // connection type since the effective connection type did not change during
-  // the lifetime of the log.
+  // Getting the system profile again should return the current effective
+  // connection type.
   network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
   EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
-            system_profile.network().effective_connection_type());
+            system_profile.network().min_effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+            system_profile.network().max_effective_connection_type());
 }
 
-// Verifies that the effective connection type is set to AMBIGUOUS when there is
-// a change in the connection type.
+// Verifies that the effective connection type is not set to UNKNOWN when there
+// is a change in the connection type.
 TEST_F(NetworkMetricsProviderTest, ECTAmbiguousOnConnectionTypeChange) {
   net::TestNetworkQualityEstimator estimator;
   std::unique_ptr<NetworkMetricsProvider::NetworkQualityEstimatorProvider>
@@ -132,15 +154,43 @@
 
   EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
             network_metrics_provider.effective_connection_type_);
-  EXPECT_FALSE(
-      network_metrics_provider.effective_connection_type_is_ambiguous_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            network_metrics_provider.min_effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+            network_metrics_provider.max_effective_connection_type_);
 
+  // Set RTT so that the effective connection type is computed as 2G.
+  estimator.set_recent_http_rtt(base::TimeDelta::FromMilliseconds(1500));
+  estimator.set_start_time_null_http_rtt(
+      base::TimeDelta::FromMilliseconds(1500));
+  // Running a request would cause the effective connection type to be computed
+  // as 2G, and observers to be notified.
+  estimator.RunOneRequest();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+            network_metrics_provider.effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+            network_metrics_provider.min_effective_connection_type_);
+  EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_2G,
+            network_metrics_provider.max_effective_connection_type_);
+
+  // There is no change in the connection type. Effective connection types
+  // should be reported as 2G.
+  network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+            system_profile.network().min_effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+            system_profile.network().max_effective_connection_type());
+
+  // Even with change in the connection type, effective connection types
+  // should be reported as 2G.
   network_metrics_provider.OnConnectionTypeChanged(
       net::NetworkChangeNotifier::CONNECTION_2G);
-  EXPECT_TRUE(network_metrics_provider.effective_connection_type_is_ambiguous_);
   network_metrics_provider.ProvideSystemProfileMetrics(&system_profile);
-  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS,
-            system_profile.network().effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+            system_profile.network().min_effective_connection_type());
+  EXPECT_EQ(SystemProfileProto::Network::EFFECTIVE_CONNECTION_TYPE_2G,
+            system_profile.network().max_effective_connection_type());
 }
 
-}  // namespace metrics
+}  // namespace metrics
\ No newline at end of file
diff --git a/components/metrics/proto/system_profile.proto b/components/metrics/proto/system_profile.proto
index dccd80d..6b4dc6f4 100644
--- a/components/metrics/proto/system_profile.proto
+++ b/components/metrics/proto/system_profile.proto
@@ -281,7 +281,7 @@
   optional Hardware hardware = 6;
 
   // Information about the network connection.
-  // Next tag: 7
+  // Next tag: 9
   message Network {
     // Set to true if connection_type changed during the lifetime of the log.
     optional bool connection_type_is_ambiguous = 1;
@@ -372,22 +372,34 @@
     // translated through NetworkMetricsProvider::GetConnectionType.
     enum EffectiveConnectionType {
       EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0;
-      // Specifies that the connection_type changed during the lifetime of the
-      // log.
-      EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS = 1;
-      EFFECTIVE_CONNECTION_TYPE_OFFLINE = 2;
+      // Deprecated: Specifies that the connection_type changed during the
+      // lifetime of the log.
+      DEPRECATED_EFFECTIVE_CONNECTION_TYPE_AMBIGUOUS = 1 [deprecated = true];
+      DEPRECATED_EFFECTIVE_CONNECTION_TYPE_OFFLINE = 2 [deprecated = true];
       EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 3;
       EFFECTIVE_CONNECTION_TYPE_2G = 4;
       EFFECTIVE_CONNECTION_TYPE_3G = 5;
       EFFECTIVE_CONNECTION_TYPE_4G = 6;
     }
-    // The connection type according to net::NetworkQualityEstimator.
+    // Deprecated: The connection type according to
+    // net::NetworkQualityEstimator. EffectiveConnectionType is the connection
+    // type whose typical performance is most similar to the measured
+    // performance of the network in use. In many cases, the "effective"
+    // connection type and the actual type of connection in use are the same,
+    // but often a network connection performs significantly differently,
+    // usually worse, from its expected capabilities.
+    optional EffectiveConnectionType deprecated_effective_connection_type = 6
+        [deprecated = true];
+
+    // The minimum and maximum values of the effective connection type enum
+    // during the lifetime of the log according to net::NetworkQualityEstimator.
     // EffectiveConnectionType is the connection type whose typical performance
     // is most similar to the measured performance of the network in use. In
     // many cases, the "effective" connection type and the actual type of
     // connection in use are the same, but often a network connection performs
     // significantly differently, usually worse, from its expected capabilities.
-    optional EffectiveConnectionType effective_connection_type = 6;
+    optional EffectiveConnectionType min_effective_connection_type = 7;
+    optional EffectiveConnectionType max_effective_connection_type = 8;
   }
   optional Network network = 13;
 
diff --git a/components/new_or_sad_tab_strings.grdp b/components/new_or_sad_tab_strings.grdp
index 9cb2bfd..46e48aa 100644
--- a/components/new_or_sad_tab_strings.grdp
+++ b/components/new_or_sad_tab_strings.grdp
@@ -45,17 +45,17 @@
       </message>
       <if expr="is_macosx">
         <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode." formatter_data="android_java">
-          Open page in Incognito mode (⇧⌘N)
+          Open page in a new Incognito window (⇧⌘N)
         </message>
       </if>
       <if expr="is_win or is_linux or chromeos">
         <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode." formatter_data="android_java">
-          Open page in Incognito mode (Ctrl-Shift-N)
+          Open page in a new Incognito window (Ctrl-Shift-N)
         </message>
       </if>
       <if expr="is_android or is_ios">
         <message name="IDS_SAD_TAB_RELOAD_INCOGNITO" desc="One of the bullet points displayed on the web page if a reload failed to fix the issue, advising the user to open the web page in Chrome's Incognito mode." formatter_data="android_java">
-          Open page in Incognito mode
+          Open page in a new Incognito tab
         </message>
       </if>
       <if expr="is_macosx or chromeos">
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc
index 09c16d9..6f2f895 100644
--- a/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -21,7 +21,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/test/sequenced_worker_pool_owner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/history/core/browser/top_sites.h"
 #include "components/history/core/browser/top_sites_observer.h"
@@ -259,8 +258,7 @@
       : prefs_(pref_service),
         url_fetcher_factory_(/*default_factory=*/nullptr),
         url_request_context_(new net::TestURLRequestContextGetter(
-            base::ThreadTaskRunnerHandle::Get())),
-        worker_pool_owner_(/*max_threads=*/2, "PopularSitesFactoryForTest.") {
+            base::ThreadTaskRunnerHandle::Get())) {
     PopularSitesImpl::RegisterProfilePrefs(pref_service->registry());
     if (enabled) {
       prefs_->SetString(prefs::kPopularSitesOverrideCountry, "IN");
@@ -285,17 +283,16 @@
 
   std::unique_ptr<PopularSites> New() {
     return base::MakeUnique<PopularSitesImpl>(
-        worker_pool_owner_.pool().get(), prefs_,
+        prefs_,
         /*template_url_service=*/nullptr,
         /*variations_service=*/nullptr, url_request_context_.get(),
-        /*directory=*/base::FilePath(), base::Bind(JsonUnsafeParser::Parse));
+        base::Bind(JsonUnsafeParser::Parse));
   }
 
  private:
   PrefService* prefs_;
   net::FakeURLFetcherFactory url_fetcher_factory_;
   scoped_refptr<net::TestURLRequestContextGetter> url_request_context_;
-  base::SequencedWorkerPoolOwner worker_pool_owner_;
 };
 
 // CallbackList-like container without Subscription, mimicking the
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index eb52b39..ed4e99b 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -10,12 +10,8 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
@@ -62,10 +58,6 @@
 const char kPopularSitesURLPref[] = "popular_sites_url";
 const char kPopularSitesJsonPref[] = "suggested_sites_json";
 
-// TODO(crbug.com/683890): This refers to a local cache stored by older
-// versions of Chrome, no longer used. Remove after M61.
-const char kPopularSitesLocalFilenameToCleanup[] = "suggested_sites.json";
-
 GURL GetPopularSitesURL(const std::string& directory,
                         const std::string& country,
                         const std::string& version) {
@@ -197,32 +189,19 @@
 PopularSites::Site::~Site() {}
 
 PopularSitesImpl::PopularSitesImpl(
-    const scoped_refptr<base::SequencedWorkerPool>& blocking_pool,
     PrefService* prefs,
     const TemplateURLService* template_url_service,
     VariationsService* variations_service,
     net::URLRequestContextGetter* download_context,
-    const base::FilePath& directory,
     ParseJSONCallback parse_json)
-    : blocking_runner_(blocking_pool->GetTaskRunnerWithShutdownBehavior(
-          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)),
-      prefs_(prefs),
+    : prefs_(prefs),
       template_url_service_(template_url_service),
       variations_(variations_service),
       download_context_(download_context),
       parse_json_(std::move(parse_json)),
       is_fallback_(false),
       sites_(ParseSiteList(*prefs->GetList(kPopularSitesJsonPref))),
-      weak_ptr_factory_(this) {
-  // If valid path provided, remove local files created by older versions.
-  if (!directory.empty() && blocking_runner_) {
-    blocking_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(base::IgnoreResult(&base::DeleteFile),
-                   directory.AppendASCII(kPopularSitesLocalFilenameToCleanup),
-                   /*recursive=*/false));
-  }
-}
+      weak_ptr_factory_(this) {}
 
 PopularSitesImpl::~PopularSitesImpl() {}
 
diff --git a/components/ntp_tiles/popular_sites_impl.h b/components/ntp_tiles/popular_sites_impl.h
index b045dea6a..1162973 100644
--- a/components/ntp_tiles/popular_sites_impl.h
+++ b/components/ntp_tiles/popular_sites_impl.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
@@ -19,8 +18,6 @@
 #include "url/gurl.h"
 
 namespace base {
-class TaskRunner;
-class SequencedWorkerPool;
 class Value;
 }
 
@@ -51,12 +48,10 @@
 class PopularSitesImpl : public PopularSites, public net::URLFetcherDelegate {
  public:
   PopularSitesImpl(
-      const scoped_refptr<base::SequencedWorkerPool>& blocking_pool,
       PrefService* prefs,
       const TemplateURLService* template_url_service,
       variations::VariationsService* variations_service,
       net::URLRequestContextGetter* download_context,
-      const base::FilePath& directory,
       ParseJSONCallback parse_json);
 
   ~PopularSitesImpl() override;
@@ -89,7 +84,6 @@
   void OnDownloadFailed();
 
   // Parameters set from constructor.
-  scoped_refptr<base::TaskRunner> const blocking_runner_;
   PrefService* const prefs_;
   const TemplateURLService* const template_url_service_;
   variations::VariationsService* const variations_;
diff --git a/components/ntp_tiles/popular_sites_impl_unittest.cc b/components/ntp_tiles/popular_sites_impl_unittest.cc
index 661cc244..419483e 100644
--- a/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -11,16 +11,12 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/files/important_file_writer.h"
-#include "base/files/scoped_temp_dir.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
-#include "base/test/sequenced_worker_pool_owner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/ntp_tiles/constants.h"
@@ -85,14 +81,11 @@
             {kUrl, "https://www.chromium.org/"},
             {kFaviconUrl, "https://www.chromium.org/favicon.ico"},
         },
-        worker_pool_owner_(2, "PopularSitesTest."),
         prefs_(new sync_preferences::TestingPrefServiceSyncable()),
         url_fetcher_factory_(nullptr) {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableNTPPopularSites);
     PopularSitesImpl::RegisterProfilePrefs(prefs_->registry());
-    CHECK(scoped_cache_dir_.CreateUniqueTempDir());
-    cache_dir_ = scoped_cache_dir_.GetPath();
   }
 
   void SetCountryAndVersion(const std::string& country,
@@ -161,9 +154,9 @@
   std::unique_ptr<PopularSites> CreatePopularSites(
       net::URLRequestContextGetter* context) {
     return base::MakeUnique<PopularSitesImpl>(
-        worker_pool_owner_.pool().get(), prefs_.get(),
+        prefs_.get(),
         /*template_url_service=*/nullptr,
-        /*variations_service=*/nullptr, context, cache_dir_,
+        /*variations_service=*/nullptr, context,
         base::Bind(JsonUnsafeParser::Parse));
   }
 
@@ -172,9 +165,6 @@
   const TestPopularSite kChromium;
 
   base::MessageLoopForUI ui_loop_;
-  base::SequencedWorkerPoolOwner worker_pool_owner_;
-  base::ScopedTempDir scoped_cache_dir_;
-  base::FilePath cache_dir_;
   std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs_;
   net::FakeURLFetcherFactory url_fetcher_factory_;
 };
@@ -309,22 +299,6 @@
   EXPECT_THAT(popular_sites->sites().size(), Eq(1ul));
 }
 
-TEST_F(PopularSitesTest, ClearsCacheFileFromOldVersions) {
-  SetCountryAndVersion("ZZ", "9");
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
-      {kWikipedia});
-
-  PopularSites::SitesVector sites;
-  const base::FilePath old_cache_path =
-      cache_dir_.AppendASCII("suggested_sites.json");
-  CHECK(base::ImportantFileWriter::WriteFileAtomically(old_cache_path,
-                                                       "Old cache"));
-  FetchPopularSites(/*force_download=*/false, &sites);
-  worker_pool_owner_.pool()->FlushForTesting();
-  EXPECT_FALSE(base::PathExists(old_cache_path));
-}
-
 TEST_F(PopularSitesTest, UsesCachedJson) {
   SetCountryAndVersion("ZZ", "9");
   RespondWithJSON(
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc
index 252fe150..fc3f5ca5 100644
--- a/components/payments/content/payment_request_spec.cc
+++ b/components/payments/content/payment_request_spec.cc
@@ -42,6 +42,21 @@
   return std::string();
 }
 
+// Returns the card type associated with the given BasicCardType.
+autofill::CreditCard::CardType GetBasicCardType(
+    const mojom::BasicCardType& type) {
+  switch (type) {
+    case mojom::BasicCardType::CREDIT:
+      return autofill::CreditCard::CARD_TYPE_CREDIT;
+    case mojom::BasicCardType::DEBIT:
+      return autofill::CreditCard::CARD_TYPE_DEBIT;
+    case mojom::BasicCardType::PREPAID:
+      return autofill::CreditCard::CARD_TYPE_PREPAID;
+  }
+  NOTREACHED();
+  return autofill::CreditCard::CARD_TYPE_UNKNOWN;
+}
+
 }  // namespace
 
 const char kBasicCardMethodName[] = "basic-card";
@@ -159,24 +174,41 @@
 
     PaymentMethodData method_data;
     method_data.supported_methods = method_data_entry->supported_methods;
-    // Transfer the supported basic card networks.
-    std::vector<std::string> supported_networks;
+
+    // Transfer the supported basic card networks (visa, amex) and types
+    // (credit, debit).
     for (const mojom::BasicCardNetwork& network :
          method_data_entry->supported_networks) {
-      supported_networks.push_back(GetBasicCardNetworkName(network));
+      method_data.supported_networks.push_back(
+          GetBasicCardNetworkName(network));
     }
-    method_data.supported_networks = std::move(supported_networks);
+    for (const mojom::BasicCardType& type :
+         method_data_entry->supported_types) {
+      autofill::CreditCard::CardType card_type = GetBasicCardType(type);
+      method_data.supported_types.insert(card_type);
+      supported_card_types_set_.insert(card_type);
+    }
 
-    // TODO(crbug.com/708603): Add browser-side support for
-    // |method_data.supported_types|.
     method_data_vector.push_back(std::move(method_data));
   }
 
+  // TODO(rouslan): Parse card types (credit, debit, prepaid) in data_util, so
+  // iOS can use it as well. http://crbug.com/602665
   data_util::ParseBasicCardSupportedNetworks(method_data_vector,
                                              &supported_card_networks_,
                                              &basic_card_specified_networks_);
   supported_card_networks_set_.insert(supported_card_networks_.begin(),
                                       supported_card_networks_.end());
+
+  // Omitting the card types means all 3 card types are supported.
+  if (supported_card_types_set_.empty()) {
+    supported_card_types_set_.insert(autofill::CreditCard::CARD_TYPE_CREDIT);
+    supported_card_types_set_.insert(autofill::CreditCard::CARD_TYPE_DEBIT);
+    supported_card_types_set_.insert(autofill::CreditCard::CARD_TYPE_PREPAID);
+  }
+
+  // Let the user decide whether an unknown card type should be used.
+  supported_card_types_set_.insert(autofill::CreditCard::CARD_TYPE_UNKNOWN);
 }
 
 void PaymentRequestSpec::UpdateSelectedShippingOption(bool after_update) {
diff --git a/components/payments/content/payment_request_spec.h b/components/payments/content/payment_request_spec.h
index c8fd2a6..9170efaf 100644
--- a/components/payments/content/payment_request_spec.h
+++ b/components/payments/content/payment_request_spec.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "components/payments/core/currency_formatter.h"
 #include "components/payments/core/payment_options_provider.h"
 #include "third_party/WebKit/public/platform/modules/payments/payment_request.mojom.h"
@@ -82,6 +83,10 @@
       const {
     return stringified_method_data_;
   }
+  const std::set<autofill::CreditCard::CardType>& supported_card_types_set()
+      const {
+    return supported_card_types_set_;
+  }
   // Returns whether the |method_name| was specified as supported through the
   // "basic-card" payment method. If false, it means either the |method_name| is
   // not supported at all, or specified directly in supportedMethods.
@@ -157,6 +162,8 @@
   std::vector<std::string> supported_card_networks_;
   std::set<std::string> supported_card_networks_set_;
 
+  std::set<autofill::CreditCard::CardType> supported_card_types_set_;
+
   // Only the set of basic-card specified networks. NOTE: callers should use
   // |supported_card_networks_set_| to check merchant support.
   std::set<std::string> basic_card_specified_networks_;
diff --git a/components/payments/content/payment_request_state.cc b/components/payments/content/payment_request_state.cc
index 47a068ec..740a4d6 100644
--- a/components/payments/content/payment_request_state.cc
+++ b/components/payments/content/payment_request_state.cc
@@ -77,11 +77,10 @@
 }
 
 bool PaymentRequestState::CanMakePayment() const {
-  for (const std::unique_ptr<PaymentInstrument>& instrument :
-       available_instruments_) {
+  for (const auto& instrument : available_instruments_) {
     if (instrument->IsValidForCanMakePayment()) {
       // AddAutofillPaymentInstrument() filters out available instruments based
-      // on supported card networks.
+      // on supported card networks (visa, amex) and types (credit, debit).
       DCHECK(spec_->supported_card_networks_set().find(
                  instrument->method_name()) !=
              spec_->supported_card_networks_set().end());
@@ -144,15 +143,26 @@
   std::string basic_card_network =
       autofill::data_util::GetPaymentRequestData(card.network())
           .basic_card_issuer_network;
-  if (!spec_->supported_card_networks_set().count(basic_card_network))
+  if (!spec_->supported_card_networks_set().count(basic_card_network) ||
+      !spec_->supported_card_types_set().count(card.card_type())) {
     return;
+  }
+
+  // The total number of card types: credit, debit, prepaid, unknown.
+  constexpr size_t kTotalNumberOfCardTypes = 4U;
+
+  // Whether the card type (credit, debit, prepaid) matches thetype that the
+  // merchant has requested exactly. This should be false for unknown card
+  // types, if the merchant cannot accept some card types.
+  bool matches_merchant_card_type_exactly =
+      card.card_type() != autofill::CreditCard::CARD_TYPE_UNKNOWN ||
+      spec_->supported_card_types_set().size() == kTotalNumberOfCardTypes;
 
   // AutofillPaymentInstrument makes a copy of |card| so it is effectively
   // owned by this object.
-  std::unique_ptr<PaymentInstrument> instrument =
-      base::MakeUnique<AutofillPaymentInstrument>(
-          basic_card_network, card, shipping_profiles_, app_locale_,
-          payment_request_delegate_);
+  auto instrument = base::MakeUnique<AutofillPaymentInstrument>(
+      basic_card_network, card, matches_merchant_card_type_exactly,
+      shipping_profiles_, app_locale_, payment_request_delegate_);
   available_instruments_.push_back(std::move(instrument));
 
   if (selected)
@@ -293,7 +303,8 @@
   auto first_complete_instrument =
       std::find_if(instruments.begin(), instruments.end(),
                    [](const std::unique_ptr<PaymentInstrument>& instrument) {
-                     return instrument->IsCompleteForPayment();
+                     return instrument->IsCompleteForPayment() &&
+                            instrument->IsExactlyMatchingMerchantRequest();
                    });
   selected_instrument_ = first_complete_instrument == instruments.end()
                              ? nullptr
diff --git a/components/payments/content/payment_response_helper_unittest.cc b/components/payments/content/payment_response_helper_unittest.cc
index d21dac6..4d5d122 100644
--- a/components/payments/content/payment_response_helper_unittest.cc
+++ b/components/payments/content/payment_response_helper_unittest.cc
@@ -37,8 +37,8 @@
     visa_card.set_billing_address_id(address_.guid());
     visa_card.set_use_count(5u);
     autofill_instrument_ = base::MakeUnique<AutofillPaymentInstrument>(
-        "visa", visa_card, billing_addresses_, "en-US",
-        &test_payment_request_delegate_);
+        "visa", visa_card, /*matches_merchant_card_type_exactly=*/true,
+        billing_addresses_, "en-US", &test_payment_request_delegate_);
   }
   ~PaymentResponseHelperTest() override {}
 
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn
index eaa3d41..5ceb667 100644
--- a/components/payments/core/BUILD.gn
+++ b/components/payments/core/BUILD.gn
@@ -86,6 +86,7 @@
     "payment_method_data_unittest.cc",
     "payment_request_data_util_unittest.cc",
     "payments_profile_comparator_unittest.cc",
+    "strings_util_unittest.cc",
     "subkey_requester_unittest.cc",
   ]
 
diff --git a/components/payments/core/autofill_payment_instrument.cc b/components/payments/core/autofill_payment_instrument.cc
index 82ff24d..2d935ea 100644
--- a/components/payments/core/autofill_payment_instrument.cc
+++ b/components/payments/core/autofill_payment_instrument.cc
@@ -25,6 +25,7 @@
 AutofillPaymentInstrument::AutofillPaymentInstrument(
     const std::string& method_name,
     const autofill::CreditCard& card,
+    bool matches_merchant_card_type_exactly,
     const std::vector<autofill::AutofillProfile*>& billing_profiles,
     const std::string& app_locale,
     PaymentRequestDelegate* payment_request_delegate)
@@ -34,6 +35,7 @@
               .icon_resource_id,
           PaymentInstrument::Type::AUTOFILL),
       credit_card_(card),
+      matches_merchant_card_type_exactly_(matches_merchant_card_type_exactly),
       billing_profiles_(billing_profiles),
       app_locale_(app_locale),
       delegate_(nullptr),
@@ -85,6 +87,10 @@
          autofill::CREDIT_CARD_EXPIRED;
 }
 
+bool AutofillPaymentInstrument::IsExactlyMatchingMerchantRequest() {
+  return matches_merchant_card_type_exactly_;
+}
+
 base::string16 AutofillPaymentInstrument::GetMissingInfoLabel() {
   return autofill::GetCompletionMessageForCard(
       autofill::GetCompletionStatusForCard(credit_card_, app_locale_,
diff --git a/components/payments/core/autofill_payment_instrument.h b/components/payments/core/autofill_payment_instrument.h
index 6df075f..fc4243e 100644
--- a/components/payments/core/autofill_payment_instrument.h
+++ b/components/payments/core/autofill_payment_instrument.h
@@ -33,6 +33,7 @@
   AutofillPaymentInstrument(
       const std::string& method_name,
       const autofill::CreditCard& card,
+      bool matches_merchant_card_type_exactly,
       const std::vector<autofill::AutofillProfile*>& billing_profiles,
       const std::string& app_locale,
       PaymentRequestDelegate* payment_request_delegate);
@@ -41,6 +42,7 @@
   // PaymentInstrument:
   void InvokePaymentApp(PaymentInstrument::Delegate* delegate) override;
   bool IsCompleteForPayment() override;
+  bool IsExactlyMatchingMerchantRequest() override;
   base::string16 GetMissingInfoLabel() override;
   bool IsValidForCanMakePayment() override;
   void RecordUse() override;
@@ -65,6 +67,13 @@
 
   // A copy of the card is owned by this object.
   autofill::CreditCard credit_card_;
+
+  // Whether the card type (credit, debit, prepaid) matches the merchant's
+  // requested card type exactly. If the merchant accepts all card types, then
+  // this variable is always "true". If the merchant accepts only a subset of
+  // the card types, then this variable is "false" for unknown card types.
+  const bool matches_merchant_card_type_exactly_;
+
   // Not owned by this object, should outlive this.
   const std::vector<autofill::AutofillProfile*>& billing_profiles_;
 
diff --git a/components/payments/core/autofill_payment_instrument_unittest.cc b/components/payments/core/autofill_payment_instrument_unittest.cc
index 7f84726..117d587 100644
--- a/components/payments/core/autofill_payment_instrument_unittest.cc
+++ b/components/payments/core/autofill_payment_instrument_unittest.cc
@@ -164,8 +164,10 @@
 
 // A valid local credit card is a valid instrument for payment.
 TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment) {
-  AutofillPaymentInstrument instrument("visa", local_credit_card(),
-                                       billing_profiles(), "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", local_credit_card(),
+      /*matches_merchant_card_type_exactly=*/true, billing_profiles(), "en-US",
+      nullptr);
   EXPECT_TRUE(instrument.IsCompleteForPayment());
   EXPECT_TRUE(instrument.GetMissingInfoLabel().empty());
 }
@@ -174,8 +176,9 @@
 TEST_F(AutofillPaymentInstrumentTest, IsCompleteForPayment_Expired) {
   autofill::CreditCard& card = local_credit_card();
   card.SetExpirationYear(2016);  // Expired.
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_TRUE(instrument.IsCompleteForPayment());
   EXPECT_EQ(base::string16(), instrument.GetMissingInfoLabel());
 }
@@ -186,8 +189,9 @@
   card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
                base::ASCIIToUTF16(""), "en-US");
   base::string16 missing_info;
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsCompleteForPayment());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_ON_CARD_REQUIRED),
             instrument.GetMissingInfoLabel());
@@ -198,8 +202,9 @@
   autofill::CreditCard& card = local_credit_card();
   card.SetNumber(base::ASCIIToUTF16(""));
   base::string16 missing_info;
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsCompleteForPayment());
   EXPECT_EQ(l10n_util::GetStringUTF16(
                 IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
@@ -212,8 +217,9 @@
   autofill::CreditCard& card = local_credit_card();
   card.set_billing_address_id("");
   base::string16 missing_info;
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsCompleteForPayment());
   EXPECT_EQ(
       l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED),
@@ -227,8 +233,9 @@
   autofill::CreditCard& card = local_credit_card();
   card.set_billing_address_id("InvalidBillingAddressId");
   base::string16 missing_info;
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsCompleteForPayment());
   EXPECT_EQ(
       l10n_util::GetStringUTF16(IDS_PAYMENTS_CARD_BILLING_ADDRESS_REQUIRED),
@@ -243,8 +250,9 @@
   card.SetNumber(base::ASCIIToUTF16(""));
   card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
                base::ASCIIToUTF16(""), "en-US");
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsCompleteForPayment());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED),
             instrument.GetMissingInfoLabel());
@@ -255,8 +263,9 @@
   autofill::CreditCard card = autofill::test::GetMaskedServerCard();
   ASSERT_GT(billing_profiles().size(), 0UL);
   card.set_billing_address_id(billing_profiles()[0]->guid());
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_TRUE(instrument.IsCompleteForPayment());
   EXPECT_TRUE(instrument.GetMissingInfoLabel().empty());
 }
@@ -267,8 +276,9 @@
   ASSERT_GT(billing_profiles().size(), 0UL);
   card.set_billing_address_id(billing_profiles()[0]->guid());
   card.SetExpirationYear(2016);  // Expired.
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_TRUE(instrument.IsCompleteForPayment());
   EXPECT_EQ(base::string16(), instrument.GetMissingInfoLabel());
 }
@@ -277,8 +287,9 @@
 TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_Minimal) {
   autofill::CreditCard& card = local_credit_card();
   card.SetExpirationYear(2016);  // Expired.
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_TRUE(instrument.IsValidForCanMakePayment());
 }
 
@@ -286,8 +297,9 @@
 TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_MaskedCard) {
   autofill::CreditCard card = autofill::test::GetMaskedServerCard();
   card.SetExpirationYear(2016);  // Expired.
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_TRUE(instrument.IsValidForCanMakePayment());
 }
 
@@ -296,8 +308,9 @@
   autofill::CreditCard& card = local_credit_card();
   card.SetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
                base::ASCIIToUTF16(""), "en-US");
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsValidForCanMakePayment());
 }
 
@@ -305,8 +318,9 @@
 TEST_F(AutofillPaymentInstrumentTest, IsValidForCanMakePayment_NoNumber) {
   autofill::CreditCard& card = local_credit_card();
   card.SetNumber(base::ASCIIToUTF16(""));
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", nullptr);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", nullptr);
   EXPECT_FALSE(instrument.IsValidForCanMakePayment());
 }
 
@@ -320,8 +334,9 @@
 
   autofill::CreditCard& card = local_credit_card();
   card.SetNumber(base::ASCIIToUTF16(""));
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", &delegate);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", &delegate);
 
   FakePaymentInstrumentDelegate instrument_delegate;
 
@@ -348,8 +363,9 @@
 
   autofill::CreditCard& card = local_credit_card();
   card.SetNumber(base::ASCIIToUTF16(""));
-  AutofillPaymentInstrument instrument("visa", card, billing_profiles(),
-                                       "en-US", &delegate);
+  AutofillPaymentInstrument instrument(
+      "visa", card, /*matches_merchant_card_type_exactly=*/true,
+      billing_profiles(), "en-US", &delegate);
 
   FakePaymentInstrumentDelegate instrument_delegate;
 
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h
index 6da0769..f189c02 100644
--- a/components/payments/core/payment_instrument.h
+++ b/components/payments/core/payment_instrument.h
@@ -39,6 +39,10 @@
   // Returns whether the instrument is complete to be used as a payment method
   // without further editing.
   virtual bool IsCompleteForPayment() = 0;
+  // Returns whether the instrument is exactly matching all filters provided by
+  // the merchant. For example, this can return "false" for unknown card types,
+  // if the merchant requested only debit cards.
+  virtual bool IsExactlyMatchingMerchantRequest() = 0;
   // Returns a message to indicate to the user what's missing for the instrument
   // to be complete for payment.
   virtual base::string16 GetMissingInfoLabel() = 0;
diff --git a/components/payments/core/payment_method_data.cc b/components/payments/core/payment_method_data.cc
index 2ea818e..b0bb839 100644
--- a/components/payments/core/payment_method_data.cc
+++ b/components/payments/core/payment_method_data.cc
@@ -20,6 +20,27 @@
 static const char kSupportedNetworks[] = "supportedNetworks";
 static const char kSupportedTypes[] = "supportedTypes";
 
+// Converts |supported_type| to |card_type| and returns true on success.
+bool ConvertCardTypeStringToEnum(const std::string& supported_type,
+                                 autofill::CreditCard::CardType* card_type) {
+  if (supported_type == "credit") {
+    *card_type = autofill::CreditCard::CARD_TYPE_CREDIT;
+    return true;
+  }
+
+  if (supported_type == "debit") {
+    *card_type = autofill::CreditCard::CARD_TYPE_DEBIT;
+    return true;
+  }
+
+  if (supported_type == "prepaid") {
+    *card_type = autofill::CreditCard::CARD_TYPE_PREPAID;
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace
 
 PaymentMethodData::PaymentMethodData() {}
@@ -84,7 +105,10 @@
             !base::IsStringASCII(supported_type)) {
           return false;
         }
-        this->supported_types.push_back(supported_type);
+        autofill::CreditCard::CardType card_type =
+            autofill::CreditCard::CARD_TYPE_UNKNOWN;
+        if (ConvertCardTypeStringToEnum(supported_type, &card_type))
+          this->supported_types.insert(card_type);
       }
     }
   }
diff --git a/components/payments/core/payment_method_data.h b/components/payments/core/payment_method_data.h
index 5bc7241..f0ce9237 100644
--- a/components/payments/core/payment_method_data.h
+++ b/components/payments/core/payment_method_data.h
@@ -6,9 +6,12 @@
 #define COMPONENTS_PAYMENTS_CORE_PAYMENT_METHOD_DATA_H_
 
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
+#include "components/autofill/core/browser/credit_card.h"
+
 namespace base {
 class DictionaryValue;
 }
@@ -41,7 +44,7 @@
   // When the methods include "basic-card", a list of networks and types that
   // are supported.
   std::vector<std::string> supported_networks;
-  std::vector<std::string> supported_types;
+  std::set<autofill::CreditCard::CardType> supported_types;
 };
 
 }  // namespace payments
diff --git a/components/payments/core/payment_method_data_unittest.cc b/components/payments/core/payment_method_data_unittest.cc
index a20e283..b44a2316 100644
--- a/components/payments/core/payment_method_data_unittest.cc
+++ b/components/payments/core/payment_method_data_unittest.cc
@@ -12,20 +12,14 @@
 // Tests the success case when populating a PaymentMethodData from a dictionary.
 TEST(PaymentMethodData, FromDictionaryValueSuccess) {
   PaymentMethodData expected;
-  std::vector<std::string> supported_methods;
-  supported_methods.push_back("visa");
-  supported_methods.push_back("basic-card");
-  expected.supported_methods = supported_methods;
+  expected.supported_methods.push_back("visa");
+  expected.supported_methods.push_back("basic-card");
   expected.data =
       "{\"supportedNetworks\":[\"mastercard\"],"
       "\"supportedTypes\":[\"debit\",\"credit\"]}";
-  std::vector<std::string> supported_networks;
-  supported_networks.push_back("mastercard");
-  expected.supported_networks = supported_networks;
-  std::vector<std::string> supported_types;
-  supported_types.push_back("debit");
-  supported_types.push_back("credit");
-  expected.supported_types = supported_types;
+  expected.supported_networks.push_back("mastercard");
+  expected.supported_types.insert(autofill::CreditCard::CARD_TYPE_DEBIT);
+  expected.supported_types.insert(autofill::CreditCard::CARD_TYPE_CREDIT);
 
   base::DictionaryValue method_data_dict;
   std::unique_ptr<base::ListValue> supported_methods_list(new base::ListValue);
@@ -97,13 +91,11 @@
   method_data2.supported_networks = supported_networks1;
   EXPECT_EQ(method_data1, method_data2);
 
-  std::vector<std::string> supported_types1{"credit"};
-  method_data1.supported_types = supported_types1;
+  method_data1.supported_types = {autofill::CreditCard::CARD_TYPE_UNKNOWN};
   EXPECT_NE(method_data1, method_data2);
-  std::vector<std::string> supported_types2{"debit"};
-  method_data2.supported_types = supported_types2;
+  method_data2.supported_types = {autofill::CreditCard::CARD_TYPE_DEBIT};
   EXPECT_NE(method_data1, method_data2);
-  method_data2.supported_types = supported_types1;
+  method_data2.supported_types = method_data1.supported_types;
   EXPECT_EQ(method_data1, method_data2);
 }
 
diff --git a/components/payments/core/strings_util.cc b/components/payments/core/strings_util.cc
index 165d2b22..bc5fad06 100644
--- a/components/payments/core/strings_util.cc
+++ b/components/payments/core/strings_util.cc
@@ -13,6 +13,27 @@
 #include "ui/base/l10n/l10n_util.h"
 
 namespace payments {
+namespace {
+
+constexpr size_t kNone = 0;
+constexpr size_t kCredit = 1;
+constexpr size_t kDebit = 2;
+constexpr size_t kPrepaid = 4;
+
+size_t getCardTypeBitmask(
+    const std::set<autofill::CreditCard::CardType>& types) {
+  return (types.find(autofill::CreditCard::CARD_TYPE_CREDIT) != types.end()
+              ? kCredit
+              : kNone) |
+         (types.find(autofill::CreditCard::CARD_TYPE_DEBIT) != types.end()
+              ? kDebit
+              : kNone) |
+         (types.find(autofill::CreditCard::CARD_TYPE_PREPAID) != types.end()
+              ? kPrepaid
+              : kNone);
+}
+
+}  // namespace
 
 base::string16 GetShippingAddressLabelFormAutofillProfile(
     const autofill::AutofillProfile& profile,
@@ -99,4 +120,47 @@
   }
 }
 
+base::string16 GetAcceptedCardTypesText(
+    const std::set<autofill::CreditCard::CardType>& types) {
+  int string_ids[8];
+
+  string_ids[kNone] = IDS_PAYMENTS_ACCEPTED_CARDS_LABEL;
+  string_ids[kCredit | kDebit | kPrepaid] = IDS_PAYMENTS_ACCEPTED_CARDS_LABEL;
+
+  string_ids[kCredit] = IDS_PAYMENTS_ACCEPTED_CREDIT_CARDS_LABEL;
+  string_ids[kDebit] = IDS_PAYMENTS_ACCEPTED_DEBIT_CARDS_LABEL;
+  string_ids[kPrepaid] = IDS_PAYMENTS_ACCEPTED_PREPAID_CARDS_LABEL;
+
+  string_ids[kCredit | kDebit] = IDS_PAYMENTS_ACCEPTED_CREDIT_DEBIT_CARDS_LABEL;
+  string_ids[kCredit | kPrepaid] =
+      IDS_PAYMENTS_ACCEPTED_CREDIT_PREPAID_CARDS_LABEL;
+  string_ids[kDebit | kPrepaid] =
+      IDS_PAYMENTS_ACCEPTED_DEBIT_PREPAID_CARDS_LABEL;
+
+  return l10n_util::GetStringUTF16(string_ids[getCardTypeBitmask(types)]);
+}
+
+base::string16 GetCardTypesAreAcceptedText(
+    const std::set<autofill::CreditCard::CardType>& types) {
+  int string_ids[8];
+
+  string_ids[kNone] = 0;
+  string_ids[kCredit | kDebit | kPrepaid] = 0;
+
+  string_ids[kCredit] = IDS_PAYMENTS_CREDIT_CARDS_ARE_ACCEPTED_LABEL;
+  string_ids[kDebit] = IDS_PAYMENTS_DEBIT_CARDS_ARE_ACCEPTED_LABEL;
+  string_ids[kPrepaid] = IDS_PAYMENTS_PREPAID_CARDS_ARE_ACCEPTED_LABEL;
+
+  string_ids[kCredit | kDebit] =
+      IDS_PAYMENTS_CREDIT_DEBIT_CARDS_ARE_ACCEPTED_LABEL;
+  string_ids[kCredit | kPrepaid] =
+      IDS_PAYMENTS_CREDIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL;
+  string_ids[kDebit | kPrepaid] =
+      IDS_PAYMENTS_DEBIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL;
+
+  int string_id = string_ids[getCardTypeBitmask(types)];
+  return string_id == 0 ? base::string16()
+                        : l10n_util::GetStringUTF16(string_id);
+}
+
 }  // namespace payments
diff --git a/components/payments/core/strings_util.h b/components/payments/core/strings_util.h
index c693d29..db084f40 100644
--- a/components/payments/core/strings_util.h
+++ b/components/payments/core/strings_util.h
@@ -5,9 +5,11 @@
 #ifndef COMPONENTS_PAYMENTS_CORE_STRINGS_UTIL_H_
 #define COMPONENTS_PAYMENTS_CORE_STRINGS_UTIL_H_
 
+#include <set>
 #include <string>
 
 #include "base/strings/string16.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "components/payments/core/payment_options_provider.h"
 
 namespace autofill {
@@ -41,6 +43,19 @@
 base::string16 GetShippingOptionSectionString(
     PaymentShippingType shipping_type);
 
+// Returns the label "Accepted cards" that is customized based on the
+// accepted card |types|. For example, "Accepted debit cards". If |types| is
+// empty or contains all possible values, then returns the generic "Accepted
+// cards" string.
+base::string16 GetAcceptedCardTypesText(
+    const std::set<autofill::CreditCard::CardType>& types);
+
+// Returns the label "Cards are accepted" that is customized based on the
+// accepted card |types|. For example, "Debit cards are accepted". If |types| is
+// empty or contains all possible values, then returns an empty string.
+base::string16 GetCardTypesAreAcceptedText(
+    const std::set<autofill::CreditCard::CardType>& types);
+
 }  // namespace payments
 
 #endif  // COMPONENTS_PAYMENTS_CORE_STRINGS_UTIL_H_
diff --git a/components/payments/core/strings_util_unittest.cc b/components/payments/core/strings_util_unittest.cc
new file mode 100644
index 0000000..7aebf44
--- /dev/null
+++ b/components/payments/core/strings_util_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/payments/core/strings_util.h"
+
+#include <string>
+#include <vector>
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+namespace {
+
+using CardType = ::autofill::CreditCard::CardType;
+
+constexpr CardType CREDIT = ::autofill::CreditCard::CARD_TYPE_CREDIT;
+constexpr CardType DEBIT = ::autofill::CreditCard::CARD_TYPE_DEBIT;
+constexpr CardType PREPAID = ::autofill::CreditCard::CARD_TYPE_PREPAID;
+constexpr CardType UNKNOWN = ::autofill::CreditCard::CARD_TYPE_UNKNOWN;
+
+}  // namespace
+
+TEST(StringsUtilTest, GetAcceptedCardTypesText) {
+  static const struct {
+    std::vector<CardType> card_types;
+    const char* const expected_text;
+  } kTestCases[] = {
+      {std::vector<CardType>(), "Accepted cards"},
+      {{UNKNOWN}, "Accepted cards"},
+      {{CREDIT}, "Accepted credit cards"},
+      {{DEBIT}, "Accepted debit cards"},
+      {{PREPAID}, "Accepted prepaid cards"},
+      {{CREDIT, DEBIT}, "Accepted credit and debit cards"},
+      {{CREDIT, PREPAID}, "Accepted credit and prepaid cards"},
+      {{DEBIT, PREPAID}, "Accepted debit and prepaid cards"},
+      {{CREDIT, DEBIT, PREPAID}, "Accepted cards"},
+  };
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    EXPECT_EQ(
+        base::UTF8ToUTF16(kTestCases[i].expected_text),
+        GetAcceptedCardTypesText(std::set<CardType>(
+            kTestCases[i].card_types.begin(), kTestCases[i].card_types.end())));
+  }
+}
+
+TEST(StringsUtilTest, GetCardTypesAreAcceptedText) {
+  static const struct {
+    std::vector<CardType> card_types;
+    const char* const expected_text;
+  } kTestCases[] = {
+      {std::vector<CardType>(), ""},
+      {{UNKNOWN}, ""},
+      {{CREDIT}, "Credit cards are accepted."},
+      {{DEBIT}, "Debit cards are accepted."},
+      {{PREPAID}, "Prepaid cards are accepted."},
+      {{CREDIT, DEBIT}, "Credit and debit cards are accepted."},
+      {{CREDIT, PREPAID}, "Credit and prepaid cards are accepted."},
+      {{DEBIT, PREPAID}, "Debit and prepaid cards are accepted."},
+      {{CREDIT, DEBIT, PREPAID}, ""},
+  };
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    EXPECT_EQ(
+        base::UTF8ToUTF16(kTestCases[i].expected_text),
+        GetCardTypesAreAcceptedText(std::set<CardType>(
+            kTestCases[i].card_types.begin(), kTestCases[i].card_types.end())));
+  }
+}
+
+}  // namespace payments
diff --git a/components/payments_strings.grdp b/components/payments_strings.grdp
index 8ad9e0c..e5c7902 100644
--- a/components/payments_strings.grdp
+++ b/components/payments_strings.grdp
@@ -16,9 +16,45 @@
   <message name="IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX" desc="The label for the checkbox that enables the user to save a credit card to their device, for example, on their phone." formatter_data="android_java">
     Save this card to this device
   </message>
-  <message name="IDS_PAYMENTS_ACCEPTED_CARDS_LABEL" desc="The title for the section that displays the credit card types that the merchant accepts. Below the title, we show a row of icons indicating the accepted cards (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+  <message name="IDS_PAYMENTS_ACCEPTED_CARDS_LABEL" desc="The title for the section that displays the card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
     Accepted cards
   </message>
+  <message name="IDS_PAYMENTS_ACCEPTED_CREDIT_CARDS_LABEL" desc="The title for the section that displays the credit card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted credit card networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+    Accepted credit cards
+  </message>
+  <message name="IDS_PAYMENTS_ACCEPTED_DEBIT_CARDS_LABEL" desc="The title for the section that displays the debit card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted debit card networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+    Accepted debit cards
+  </message>
+  <message name="IDS_PAYMENTS_ACCEPTED_PREPAID_CARDS_LABEL" desc="The title for the section that displays the prepaid card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted prepaid card networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+    Accepted prepaid cards
+  </message>
+  <message name="IDS_PAYMENTS_ACCEPTED_CREDIT_DEBIT_CARDS_LABEL" desc="The title for the section that displays the credit and debit card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+    Accepted credit and debit cards
+  </message>
+  <message name="IDS_PAYMENTS_ACCEPTED_CREDIT_PREPAID_CARDS_LABEL" desc="The title for the section that displays the credit and prepaid card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+    Accepted credit and prepaid cards
+  </message>
+  <message name="IDS_PAYMENTS_ACCEPTED_DEBIT_PREPAID_CARDS_LABEL" desc="The title for the section that displays the debit and prepaid card networks that the merchant accepts. Below the title, we show a row of icons indicating the accepted networks (Visa icon, Mastercard icon, etc.)." formatter_data="android_java">
+    Accepted debit and prepaid cards
+  </message>
+  <message name="IDS_PAYMENTS_CREDIT_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's credit cards that the merchant accepts." formatter_data="android_java">
+    Credit cards are accepted.
+  </message>
+  <message name="IDS_PAYMENTS_DEBIT_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's debit cards that the merchant accepts." formatter_data="android_java">
+    Debit cards are accepted.
+  </message>
+  <message name="IDS_PAYMENTS_PREPAID_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's prepaid cards that the merchant accepts." formatter_data="android_java">
+    Prepaid cards are accepted.
+  </message>
+  <message name="IDS_PAYMENTS_CREDIT_DEBIT_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's credit and debit cards that the merchant accepts." formatter_data="android_java">
+    Credit and debit cards are accepted.
+  </message>
+  <message name="IDS_PAYMENTS_CREDIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's credit and prepaid cards that the merchant accepts." formatter_data="android_java">
+    Credit and prepaid cards are accepted.
+  </message>
+  <message name="IDS_PAYMENTS_DEBIT_PREPAID_CARDS_ARE_ACCEPTED_LABEL" desc="A message for the section that displays user's debit and prepaid cards that the merchant accepts." formatter_data="android_java">
+    Debit and prepaid cards are accepted.
+  </message>
   <message name="IDS_PAYMENTS_METHOD_OF_PAYMENT_LABEL" desc="The title for the section that lets the user select the method of payment." formatter_data="android_java">
     Payment method
   </message>
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index 13d75998..89d5849 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -45,6 +45,41 @@
          type == dm_protocol::kChromeUserPolicyType;
 }
 
+LicenseType TranslateLicenseType(em::LicenseType type) {
+  switch (type) {
+    case em::CDM_PERPETUAL:
+      return LicenseType::PERPETUAL;
+    case em::CDM_ANNUAL:
+      return LicenseType::ANNUAL;
+    case em::KIOSK:
+      return LicenseType::KIOSK;
+    default:
+      LOG(ERROR) << "Unknown License type: " << type;
+      return LicenseType::UNKNOWN;
+  }
+}
+
+void ExtractLicenseMap(const em::CheckDeviceLicenseResponse& license_response,
+                       CloudPolicyClient::LicenseMap& licenses) {
+  for (int i = 0; i < license_response.license_availability_size(); i++) {
+    const em::LicenseAvailability& license =
+        license_response.license_availability(i);
+    if (!license.has_license_type() || !license.has_available_licenses())
+      continue;
+    auto license_type = TranslateLicenseType(license.license_type());
+    if (license_type == LicenseType::UNKNOWN)
+      continue;
+    bool duplicate =
+        licenses
+            .insert(std::make_pair(license_type, license.available_licenses()))
+            .second;
+    if (duplicate) {
+      LOG(WARNING) << "Duplicate license type in response :"
+                   << static_cast<int>(license_type);
+    }
+  }
+}
+
 }  // namespace
 
 CloudPolicyClient::Observer::~Observer() {}
@@ -432,6 +467,27 @@
   request_jobs_.back()->Start(job_callback);
 }
 
+void CloudPolicyClient::RequestAvailableLicenses(
+    const std::string& auth_token,
+    const LicenseRequestCallback& callback) {
+  DCHECK(!auth_token.empty());
+
+  std::unique_ptr<DeviceManagementRequestJob> request_job(service_->CreateJob(
+      DeviceManagementRequestJob::TYPE_REQUEST_LICENSE_TYPES,
+      GetRequestContext()));
+
+  request_job->SetOAuthToken(auth_token);
+
+  request_job->GetRequest()->mutable_check_device_license_request();
+
+  const DeviceManagementRequestJob::Callback job_callback =
+      base::Bind(&CloudPolicyClient::OnAvailableLicensesRequested,
+                 weak_ptr_factory_.GetWeakPtr(), request_job.get(), callback);
+
+  request_jobs_.push_back(std::move(request_job));
+  request_jobs_.back()->Start(job_callback);
+}
+
 void CloudPolicyClient::UpdateGcmId(
     const std::string& gcm_id,
     const CloudPolicyClient::StatusCallback& callback) {
@@ -701,6 +757,44 @@
   RemoveJob(job);
 }
 
+void CloudPolicyClient::OnAvailableLicensesRequested(
+    const DeviceManagementRequestJob* job,
+    const CloudPolicyClient::LicenseRequestCallback& callback,
+    DeviceManagementStatus status,
+    int net_error,
+    const em::DeviceManagementResponse& response) {
+  CloudPolicyClient::LicenseMap licenses;
+
+  if (status != DM_STATUS_SUCCESS) {
+    LOG(WARNING) << "Could not get available license types";
+    status_ = status;
+    callback.Run(false /* success */, licenses);
+    RemoveJob(job);
+    return;
+  }
+
+  if (!response.has_check_device_license_response()) {
+    LOG(WARNING) << "Invalid license request response.";
+    status_ = DM_STATUS_RESPONSE_DECODING_ERROR;
+    callback.Run(false /* success */, licenses);
+    RemoveJob(job);
+    return;
+  }
+
+  status_ = status;
+  const em::CheckDeviceLicenseResponse& license_response =
+      response.check_device_license_response();
+
+  if (license_response.has_license_selection_mode() &&
+      (license_response.license_selection_mode() ==
+       em::CheckDeviceLicenseResponse::USER_SELECTION)) {
+    ExtractLicenseMap(license_response, licenses);
+  }
+
+  callback.Run(true /* success */, licenses);
+  RemoveJob(job);
+}
+
 void CloudPolicyClient::RemoveJob(const DeviceManagementRequestJob* job) {
   for (auto it = request_jobs_.begin(); it != request_jobs_.end(); ++it) {
     if (it->get() == job) {
diff --git a/components/policy/core/common/cloud/cloud_policy_client.h b/components/policy/core/common/cloud/cloud_policy_client.h
index d5cf0a11..1f4f6ef 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.h
+++ b/components/policy/core/common/cloud/cloud_policy_client.h
@@ -49,10 +49,18 @@
       std::map<std::pair<std::string, std::string>,
                std::unique_ptr<enterprise_management::PolicyFetchResponse>>;
 
+  // Maps a license type to number of available licenses.
+  using LicenseMap = std::map<LicenseType, int>;
+
   // A callback which receives boolean status of an operation.  If the operation
   // succeeded, |status| is true.
   using StatusCallback = base::Callback<void(bool status)>;
 
+  // A callback for available licenses request. If the operation succeeded,
+  // |success| is true, and |map| contains available licenses.
+  using LicenseRequestCallback =
+      base::Callback<void(bool success, const LicenseMap& map)>;
+
   // A callback which receives fetched remote commands.
   using RemoteCommandCallback = base::Callback<void(
       DeviceManagementStatus,
@@ -188,6 +196,12 @@
                               const std::string& location,
                               const StatusCallback& callback);
 
+  // Requests a list of licenses available for enrollment. Uses OAuth2 token
+  // |auth_token| to identify user who issues the request, the |callback| will
+  // be called when the operation completes.
+  void RequestAvailableLicenses(const std::string& auth_token,
+                                const LicenseRequestCallback& callback);
+
   // Sends a GCM id update request to the DM server. The server will
   // associate the DM token in authorization header with |gcm_id|, and
   // |callback| will be called when the operation completes.
@@ -350,6 +364,14 @@
       int net_error,
       const enterprise_management::DeviceManagementResponse& response);
 
+  // Callback for available license types request.
+  void OnAvailableLicensesRequested(
+      const DeviceManagementRequestJob* job,
+      const LicenseRequestCallback& callback,
+      DeviceManagementStatus status,
+      int net_error,
+      const enterprise_management::DeviceManagementResponse& response);
+
   // Callback for gcm id update requests.
   void OnGcmIdUpdated(
       const DeviceManagementRequestJob* job,
diff --git a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
index d4f30fb..eb08c617 100644
--- a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
@@ -82,6 +82,16 @@
                     const std::vector<em::RemoteCommand>&));
 };
 
+// A mock class to allow us to set expectations on available licenses fetch
+// callback
+class MockAvailableLicensesObserver {
+ public:
+  MockAvailableLicensesObserver() {}
+
+  MOCK_METHOD2(OnAvailableLicensesFetched,
+               void(bool, const CloudPolicyClient::LicenseMap&));
+};
+
 }  // namespace
 
 class CloudPolicyClientTest : public testing::Test {
@@ -170,6 +180,21 @@
             em::DeviceAttributeUpdateResponse_ResultType_ATTRIBUTE_UPDATE_SUCCESS);
 
     gcm_id_update_request_.mutable_gcm_id_update_request()->set_gcm_id(kGcmID);
+
+    check_device_license_request_.mutable_check_device_license_request();
+
+    em::CheckDeviceLicenseResponse* device_license_response =
+        check_device_license_response_.mutable_check_device_license_response();
+    device_license_response->set_license_selection_mode(
+        em::CheckDeviceLicenseResponse_LicenseSelectionMode_USER_SELECTION);
+    em::LicenseAvailability* license_one =
+        device_license_response->add_license_availability();
+    license_one->set_license_type(em::CDM_PERPETUAL);
+    license_one->set_available_licenses(10);
+    em::LicenseAvailability* license_two =
+        device_license_response->add_license_availability();
+    license_two->set_license_type(em::KIOSK);
+    license_two->set_available_licenses(0);
   }
 
   void SetUp() override {
@@ -313,6 +338,19 @@
                          MatchProto(gcm_id_update_request_)));
   }
 
+  void ExpectCheckDeviceLicense(const std::string& oauth_token,
+                                const em::DeviceManagementResponse& response) {
+    EXPECT_CALL(
+        service_,
+        CreateJob(DeviceManagementRequestJob::TYPE_REQUEST_LICENSE_TYPES,
+                  request_context_))
+        .WillOnce(service_.SucceedJob(response));
+    EXPECT_CALL(service_, StartJob(dm_protocol::kValueRequestCheckDeviceLicense,
+                                   std::string(), oauth_token, std::string(),
+                                   std::string(),
+                                   MatchProto(check_device_license_request_)));
+  }
+
   void CheckPolicyResponse() {
     ASSERT_TRUE(client_->GetPolicyFor(policy_type_, std::string()));
     EXPECT_THAT(*client_->GetPolicyFor(policy_type_, std::string()),
@@ -337,6 +375,7 @@
   em::DeviceManagementRequest attribute_update_permission_request_;
   em::DeviceManagementRequest attribute_update_request_;
   em::DeviceManagementRequest gcm_id_update_request_;
+  em::DeviceManagementRequest check_device_license_request_;
 
   // Protobufs used in successful responses.
   em::DeviceManagementResponse registration_response_;
@@ -348,6 +387,8 @@
   em::DeviceManagementResponse attribute_update_permission_response_;
   em::DeviceManagementResponse attribute_update_response_;
   em::DeviceManagementResponse gcm_id_update_response_;
+  em::DeviceManagementResponse check_device_license_response_;
+  em::DeviceManagementResponse check_device_license_broken_response_;
 
   base::MessageLoop loop_;
   std::string client_id_;
@@ -355,6 +396,7 @@
   MockDeviceManagementService service_;
   StrictMock<MockCloudPolicyClientObserver> observer_;
   StrictMock<MockStatusCallbackObserver> callback_observer_;
+  StrictMock<MockAvailableLicensesObserver> license_callback_observer_;
   FakeSigningService fake_signing_service_;
   std::unique_ptr<CloudPolicyClient> client_;
   // Pointer to the client's request context.
@@ -952,4 +994,32 @@
   EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
 }
 
+TEST_F(CloudPolicyClientTest, RequestAvailableLicenses) {
+  ExpectCheckDeviceLicense(kOAuthToken, check_device_license_response_);
+
+  EXPECT_CALL(license_callback_observer_, OnAvailableLicensesFetched(true, _))
+      .Times(1);
+
+  CloudPolicyClient::LicenseRequestCallback callback =
+      base::Bind(&MockAvailableLicensesObserver::OnAvailableLicensesFetched,
+                 base::Unretained(&license_callback_observer_));
+
+  client_->RequestAvailableLicenses(kOAuthToken, callback);
+  EXPECT_EQ(DM_STATUS_SUCCESS, client_->status());
+}
+
+TEST_F(CloudPolicyClientTest, RequestAvailableLicensesBrokenResponse) {
+  ExpectCheckDeviceLicense(kOAuthToken, check_device_license_broken_response_);
+
+  EXPECT_CALL(license_callback_observer_, OnAvailableLicensesFetched(false, _))
+      .Times(1);
+
+  CloudPolicyClient::LicenseRequestCallback callback =
+      base::Bind(&MockAvailableLicensesObserver::OnAvailableLicensesFetched,
+                 base::Unretained(&license_callback_observer_));
+
+  client_->RequestAvailableLicenses(kOAuthToken, callback);
+  EXPECT_EQ(DM_STATUS_RESPONSE_DECODING_ERROR, client_->status());
+}
+
 }  // namespace policy
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc
index d37a2e3..b90ae7a6 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.cc
+++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -53,6 +53,7 @@
     "active_directory_enroll_play_user";
 const char kValueRequestActiveDirectoryPlayActivity[] =
     "active_directory_play_activity";
+const char kValueRequestCheckDeviceLicense[] = "check_device_license";
 
 const char kChromeDevicePolicyType[] = "google/chromeos/device";
 #if defined(OS_CHROMEOS)
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.h b/components/policy/core/common/cloud/cloud_policy_constants.h
index 25a41103..e8891d37 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.h
+++ b/components/policy/core/common/cloud/cloud_policy_constants.h
@@ -45,6 +45,7 @@
 POLICY_EXPORT extern const char kValueRequestCertBasedRegister[];
 POLICY_EXPORT extern const char kValueRequestActiveDirectoryEnrollPlayUser[];
 POLICY_EXPORT extern const char kValueRequestActiveDirectoryPlayActivity[];
+POLICY_EXPORT extern const char kValueRequestCheckDeviceLicense[];
 
 // Policy type strings for the policy_type field in PolicyFetchRequest.
 POLICY_EXPORT extern const char kChromeDevicePolicyType[];
@@ -136,6 +137,14 @@
                                           // launch a kiosk webapp.
 };
 
+// License types available for enrollment.
+enum class LicenseType {
+  UNKNOWN,    // Included for compatibility.
+  PERPETUAL,  // Perpetual license
+  ANNUAL,     // Annual license
+  KIOSK       // Single App Kiosk license
+};
+
 }  // namespace policy
 
 #endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_CONSTANTS_H_
diff --git a/components/policy/core/common/cloud/device_management_service.cc b/components/policy/core/common/cloud/device_management_service.cc
index a86cd35..1ed83ab1 100644
--- a/components/policy/core/common/cloud/device_management_service.cc
+++ b/components/policy/core/common/cloud/device_management_service.cc
@@ -156,6 +156,8 @@
       return dm_protocol::kValueRequestActiveDirectoryEnrollPlayUser;
     case DeviceManagementRequestJob::TYPE_ACTIVE_DIRECTORY_PLAY_ACTIVITY:
       return dm_protocol::kValueRequestActiveDirectoryPlayActivity;
+    case DeviceManagementRequestJob::TYPE_REQUEST_LICENSE_TYPES:
+      return dm_protocol::kValueRequestCheckDeviceLicense;
   }
   NOTREACHED() << "Invalid job type " << type;
   return "";
diff --git a/components/policy/core/common/cloud/device_management_service.h b/components/policy/core/common/cloud/device_management_service.h
index bd257a9..8314438 100644
--- a/components/policy/core/common/cloud/device_management_service.h
+++ b/components/policy/core/common/cloud/device_management_service.h
@@ -62,6 +62,7 @@
     TYPE_CERT_BASED_REGISTRATION = 13,
     TYPE_ACTIVE_DIRECTORY_ENROLL_PLAY_USER = 14,
     TYPE_ACTIVE_DIRECTORY_PLAY_ACTIVITY = 15,
+    TYPE_REQUEST_LICENSE_TYPES = 16,
   };
 
   typedef base::Callback<
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.cc b/components/subresource_filter/content/browser/async_document_subresource_filter.cc
index 8d1887f..c91f0b9 100644
--- a/components/subresource_filter/content/browser/async_document_subresource_filter.cc
+++ b/components/subresource_filter/content/browser/async_document_subresource_filter.cc
@@ -151,6 +151,12 @@
     std::move(first_disallowed_load_callback_).Run();
 }
 
+const ActivationState& AsyncDocumentSubresourceFilter::activation_state()
+    const {
+  CHECK(activation_state_);
+  return activation_state_.value();
+}
+
 // AsyncDocumentSubresourceFilter::Core ----------------------------------------
 
 AsyncDocumentSubresourceFilter::Core::Core() {
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.h b/components/subresource_filter/content/browser/async_document_subresource_filter.h
index ead8c1c..fa607e8 100644
--- a/components/subresource_filter/content/browser/async_document_subresource_filter.h
+++ b/components/subresource_filter/content/browser/async_document_subresource_filter.h
@@ -114,9 +114,7 @@
   void ReportDisallowedLoad();
 
   // Must be called after activation state computation is finished.
-  const ActivationState& activation_state() const {
-    return activation_state_.value();
-  }
+  const ActivationState& activation_state() const;
 
   // The |first_disallowed_load_callback|, if it is non-null, is invoked on the
   // first ReportDisallowedLoad() call.
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 6517e58..11e5fdf 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
@@ -72,13 +73,18 @@
   if (navigation_handle->GetNetErrorCode() != net::OK)
     return;
 
-  auto throttle = ongoing_activation_throttles_.find(navigation_handle);
-  if (throttle == ongoing_activation_throttles_.end())
+  auto it = ongoing_activation_throttles_.find(navigation_handle);
+  if (it == ongoing_activation_throttles_.end())
     return;
 
+  // TODO(crbug.com/736249): Remove CHECKs in this file when the root cause of
+  // the crash is found.
+  ActivationStateComputingNavigationThrottle* throttle = it->second;
+  CHECK_EQ(navigation_handle, throttle->navigation_handle());
+
   // Main frame throttles with disabled page-level activation will not have
   // associated filters.
-  AsyncDocumentSubresourceFilter* filter = throttle->second->filter();
+  AsyncDocumentSubresourceFilter* filter = throttle->filter();
   if (!filter)
     return;
 
@@ -92,7 +98,7 @@
       "ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation",
       "activation_state", filter->activation_state().ToTracedValue());
 
-  throttle->second->WillSendActivationToRenderer();
+  throttle->WillSendActivationToRenderer();
 
   content::RenderFrameHost* frame_host =
       navigation_handle->GetRenderFrameHost();
@@ -113,6 +119,7 @@
   auto throttle = ongoing_activation_throttles_.find(navigation_handle);
   std::unique_ptr<AsyncDocumentSubresourceFilter> filter;
   if (throttle != ongoing_activation_throttles_.end()) {
+    CHECK_EQ(navigation_handle, throttle->second->navigation_handle());
     filter = throttle->second->ReleaseFilter();
     ongoing_activation_throttles_.erase(throttle);
   }
@@ -206,6 +213,7 @@
   }
   if (auto activation_throttle =
           MaybeCreateActivationStateComputingThrottle(navigation_handle)) {
+    CHECK(!base::ContainsKey(ongoing_activation_throttles_, navigation_handle));
     ongoing_activation_throttles_[navigation_handle] =
         activation_throttle.get();
     throttles->push_back(std::move(activation_throttle));
diff --git a/components/suggestions/proto/suggestions.proto b/components/suggestions/proto/suggestions.proto
index 27f5d14..5fcf03ae 100644
--- a/components/suggestions/proto/suggestions.proto
+++ b/components/suggestions/proto/suggestions.proto
@@ -23,15 +23,19 @@
 //
 // Notice that the tags on this proto must match the ones on the server side.
 //
-// Next tag: 2
+// Next tag: 17
 message SuggestionsProfile {
   repeated ChromeSuggestion suggestions = 1;
 
+  reserved 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
+
   // Timestamp when the profile was generated (usec).
   optional int64 timestamp = 16;
 }
 
-// The suggestions for this user, ordered from best to worst.
+// An individual suggestion.
+//
+// Notice that the tags on this proto must match the ones on the server side.
 //
 // Next tag: 15
 message ChromeSuggestion {
@@ -50,8 +54,12 @@
   // The provider(s) responsible for this suggestion.
   repeated ProviderId providers = 5;
 
+  reserved 6;
+
   // The timestamp (usec) at which this suggestion ceases to be valid.
   optional int64 expiry_ts = 7;
+
+  reserved 8, 9, 10, 11, 12, 13, 14;
 }
 
 // A list of URLs that should be filtered from the SuggestionsProfile.
diff --git a/components/test/data/web_database/version_73.sql b/components/test/data/web_database/version_73.sql
new file mode 100644
index 0000000..2eb7697e
--- /dev/null
+++ b/components/test/data/web_database/version_73.sql
@@ -0,0 +1,25 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('mmap_status','-1');
+INSERT INTO "meta" VALUES('version','73');
+INSERT INTO "meta" VALUES('last_compatible_version','72');
+CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
+CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR, last_visited INTEGER DEFAULT 0);
+CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value));
+CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
+CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0);
+CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR);
+CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
+CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR);
+CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
+CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR);
+CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, unmask_date INTEGER NOT NULL DEFAULT 0);
+CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
+CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
+CREATE TABLE server_address_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, has_converted BOOL NOT NULL DEFAULT FALSE);
+CREATE TABLE autofill_sync_metadata (storage_key VARCHAR PRIMARY KEY NOT NULL,value BLOB);
+CREATE TABLE autofill_model_type_state (id INTEGER PRIMARY KEY, value BLOB);
+CREATE INDEX autofill_name ON autofill (name);
+CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
+COMMIT;
diff --git a/components/webdata/common/BUILD.gn b/components/webdata/common/BUILD.gn
index c107b5a..7a11220 100644
--- a/components/webdata/common/BUILD.gn
+++ b/components/webdata/common/BUILD.gn
@@ -59,6 +59,7 @@
     "//components/test/data/web_database/version_70.sql",
     "//components/test/data/web_database/version_71.sql",
     "//components/test/data/web_database/version_72.sql",
+    "//components/test/data/web_database/version_73.sql",
   ]
   outputs = [
     "{{bundle_resources_dir}}/" +
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index a58004c..9e64be9 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -13,7 +13,7 @@
 // corresponding changes must happen in the unit tests, and new migration test
 // added.  See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
 // static
-const int WebDatabase::kCurrentVersionNumber = 73;
+const int WebDatabase::kCurrentVersionNumber = 74;
 
 const int WebDatabase::kDeprecatedVersionNumber = 51;
 
@@ -29,15 +29,15 @@
   meta_table->SetVersionNumber(version_num);
   if (update_compatible_version_num) {
     meta_table->SetCompatibleVersionNumber(
-          std::min(version_num, kCompatibleVersionNumber));
+        std::min(version_num, kCompatibleVersionNumber));
   }
 }
 
 // Outputs the failed version number as a warning and always returns
 // |sql::INIT_FAILURE|.
 sql::InitStatus FailedMigrationTo(int version_num) {
-  LOG(WARNING) << "Unable to update web database to version "
-               << version_num << ".";
+  LOG(WARNING) << "Unable to update web database to version " << version_num
+               << ".";
   NOTREACHED();
   return sql::INIT_FAILURE;
 }
@@ -46,8 +46,7 @@
 
 WebDatabase::WebDatabase() {}
 
-WebDatabase::~WebDatabase() {
-}
+WebDatabase::~WebDatabase() {}
 
 void WebDatabase::AddTable(WebDatabaseTable* table) {
   tables_[table->GetTypeKey()] = table;
@@ -150,8 +149,7 @@
   DCHECK_GT(current_version, kDeprecatedVersionNumber);
 
   for (int next_version = current_version + 1;
-       next_version <= kCurrentVersionNumber;
-       ++next_version) {
+       next_version <= kCurrentVersionNumber; ++next_version) {
     // Do any database-wide migrations.
     bool update_compatible_version = false;
     if (!MigrateToVersion(next_version, &update_compatible_version))
@@ -175,7 +173,7 @@
 }
 
 bool WebDatabase::MigrateToVersion(int version,
-                      bool* update_compatible_version) {
+                                   bool* update_compatible_version) {
   // Migrate if necessary.
   switch (version) {
     case 58:
@@ -188,10 +186,9 @@
 
 bool WebDatabase::MigrateToVersion58DropWebAppsAndIntents() {
   sql::Transaction transaction(&db_);
-  return transaction.Begin() &&
-      db_.Execute("DROP TABLE IF EXISTS web_apps") &&
-      db_.Execute("DROP TABLE IF EXISTS web_app_icons") &&
-      db_.Execute("DROP TABLE IF EXISTS web_intents") &&
-      db_.Execute("DROP TABLE IF EXISTS web_intents_defaults") &&
-      transaction.Commit();
+  return transaction.Begin() && db_.Execute("DROP TABLE IF EXISTS web_apps") &&
+         db_.Execute("DROP TABLE IF EXISTS web_app_icons") &&
+         db_.Execute("DROP TABLE IF EXISTS web_intents") &&
+         db_.Execute("DROP TABLE IF EXISTS web_intents_defaults") &&
+         transaction.Commit();
 }
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc
index ac54bd8..8c6a30f5 100644
--- a/components/webdata/common/web_database_migration_unittest.cc
+++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -103,7 +103,7 @@
     source_path = source_path.AppendASCII("web_database");
     source_path = source_path.Append(file);
     return base::PathExists(source_path) &&
-        base::ReadFileToString(source_path, contents);
+           base::ReadFileToString(source_path, contents);
   }
 
   static int VersionFromConnection(sql::Connection* connection) {
@@ -130,7 +130,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
 };
 
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 73;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 74;
 
 void WebDatabaseMigrationTest::LoadDatabase(
     const base::FilePath::StringType& file) {
@@ -207,8 +207,7 @@
 
 // Versions below 52 are deprecated. This verifies that old databases are razed.
 TEST_F(WebDatabaseMigrationTest, RazeDeprecatedVersionAndReinit) {
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_50.sql")));
+  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_50.sql")));
 
   // Verify pre-conditions.  These are expectations for version 50 of the
   // database.
@@ -221,14 +220,14 @@
     ASSERT_TRUE(meta_table.Init(&connection, 50, 50));
 
     ASSERT_FALSE(connection.DoesColumnExist("keywords", "image_url"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords",
-                                            "search_url_post_params"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords",
-                                            "suggest_url_post_params"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords",
-                                            "instant_url_post_params"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords",
-                                            "image_url_post_params"));
+    ASSERT_FALSE(
+        connection.DoesColumnExist("keywords", "search_url_post_params"));
+    ASSERT_FALSE(
+        connection.DoesColumnExist("keywords", "suggest_url_post_params"));
+    ASSERT_FALSE(
+        connection.DoesColumnExist("keywords", "instant_url_post_params"));
+    ASSERT_FALSE(
+        connection.DoesColumnExist("keywords", "image_url_post_params"));
   }
 
   DoMigration();
@@ -245,22 +244,21 @@
 
     // New columns should have been created.
     EXPECT_TRUE(connection.DoesColumnExist("keywords", "image_url"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords",
-                                           "search_url_post_params"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords",
-                                           "suggest_url_post_params"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords",
-                                           "instant_url_post_params"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords",
-                                           "image_url_post_params"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("keywords", "search_url_post_params"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("keywords", "suggest_url_post_params"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("keywords", "instant_url_post_params"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("keywords", "image_url_post_params"));
   }
 }
 
 // Tests that the column |new_tab_url| is added to the keyword table schema for
 // a version 52 database.
 TEST_F(WebDatabaseMigrationTest, MigrateVersion52ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_52.sql")));
+  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_52.sql")));
 
   // Verify pre-conditions.  These are expectations for version 52 of the
   // database.
@@ -348,12 +346,11 @@
     EXPECT_FALSE(connection.DoesColumnExist("autofill_profile_phones", "type"));
 
     // Data should have been preserved.
-    sql::Statement s_profiles(
-        connection.GetUniqueStatement(
-            "SELECT guid, company_name, street_address, dependent_locality,"
-            " city, state, zipcode, sorting_code, country_code, date_modified,"
-            " origin "
-            "FROM autofill_profiles"));
+    sql::Statement s_profiles(connection.GetUniqueStatement(
+        "SELECT guid, company_name, street_address, dependent_locality,"
+        " city, state, zipcode, sorting_code, country_code, date_modified,"
+        " origin "
+        "FROM autofill_profiles"));
 
     // Address lines 1 and 2.
     ASSERT_TRUE(s_profiles.Step());
@@ -426,9 +423,8 @@
     EXPECT_FALSE(s_profiles.Step());
 
     // Verify the phone number data as well.
-    sql::Statement s_phones(
-        connection.GetUniqueStatement(
-            "SELECT guid, number FROM autofill_profile_phones"));
+    sql::Statement s_phones(connection.GetUniqueStatement(
+        "SELECT guid, number FROM autofill_profile_phones"));
 
     ASSERT_TRUE(s_phones.Step());
     EXPECT_EQ("00000000-0000-0000-0000-000000000001", s_phones.ColumnString(0));
@@ -559,12 +555,11 @@
 
     // Data should have been preserved.  Note that it appears out of order
     // relative to the previous table, as it's been alphabetized.  That's ok.
-    sql::Statement s(
-        connection.GetUniqueStatement(
-            "SELECT name, value, value_lower, date_created, date_last_used,"
-            " count "
-            "FROM autofill "
-            "ORDER BY name, value ASC"));
+    sql::Statement s(connection.GetUniqueStatement(
+        "SELECT name, value, value_lower, date_created, date_last_used,"
+        " count "
+        "FROM autofill "
+        "ORDER BY name, value ASC"));
 
     // "jane.doe@example.org": Timestamps should be parsed correctly, and only
     // the first and last should be kept.
@@ -644,19 +639,17 @@
 
     // Data should have been preserved. Language code should have been set to
     // empty string.
-    sql::Statement s_profiles(
-        connection.GetUniqueStatement(
-            "SELECT guid, company_name, street_address, dependent_locality,"
-            " city, state, zipcode, sorting_code, country_code, date_modified,"
-            " origin, language_code "
-            "FROM autofill_profiles"));
+    sql::Statement s_profiles(connection.GetUniqueStatement(
+        "SELECT guid, company_name, street_address, dependent_locality,"
+        " city, state, zipcode, sorting_code, country_code, date_modified,"
+        " origin, language_code "
+        "FROM autofill_profiles"));
 
     ASSERT_TRUE(s_profiles.Step());
     EXPECT_EQ("00000000-0000-0000-0000-000000000001",
               s_profiles.ColumnString(0));
     EXPECT_EQ(ASCIIToUTF16("Google Inc"), s_profiles.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("340 Main St"),
-              s_profiles.ColumnString16(2));
+    EXPECT_EQ(ASCIIToUTF16("340 Main St"), s_profiles.ColumnString16(2));
     EXPECT_EQ(base::string16(), s_profiles.ColumnString16(3));
     EXPECT_EQ(ASCIIToUTF16("Los Angeles"), s_profiles.ColumnString16(4));
     EXPECT_EQ(ASCIIToUTF16("CA"), s_profiles.ColumnString16(5));
@@ -689,10 +682,9 @@
         connection.DoesColumnExist("autofill_profile_names", "full_name"));
 
     // Verify the starting data.
-    sql::Statement s_names(
-        connection.GetUniqueStatement(
-            "SELECT guid, first_name, middle_name, last_name "
-            "FROM autofill_profile_names"));
+    sql::Statement s_names(connection.GetUniqueStatement(
+        "SELECT guid, first_name, middle_name, last_name "
+        "FROM autofill_profile_names"));
     ASSERT_TRUE(s_names.Step());
     EXPECT_EQ("B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD", s_names.ColumnString(0));
     EXPECT_EQ(ASCIIToUTF16("Jon"), s_names.ColumnString16(1));
@@ -719,10 +711,9 @@
 
     // Data should have been preserved. Full name should have been set to the
     // empty string.
-    sql::Statement s_names(
-        connection.GetUniqueStatement(
-            "SELECT guid, first_name, middle_name, last_name, full_name "
-            "FROM autofill_profile_names"));
+    sql::Statement s_names(connection.GetUniqueStatement(
+        "SELECT guid, first_name, middle_name, last_name, full_name "
+        "FROM autofill_profile_names"));
 
     ASSERT_TRUE(s_names.Step());
     EXPECT_EQ("B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD", s_names.ColumnString(0));
@@ -778,7 +769,8 @@
 TEST_F(WebDatabaseMigrationTest, MigrateVersion58ToCurrent) {
   ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_58.sql")));
 
-  const char query_extensions[] = "SELECT * FROM keywords "
+  const char query_extensions[] =
+      "SELECT * FROM keywords "
       "WHERE url='chrome-extension://iphchnegaodmijmkdlbhbanjhfphhikp/"
       "?q={searchTerms}'";
   // Verify pre-conditions.
@@ -818,8 +810,9 @@
     }
     EXPECT_EQ(0, count);
 
-    s.Assign(connection.GetUniqueStatement("SELECT * FROM keywords "
-        "WHERE short_name='Google'"));
+    s.Assign(
+        connection.GetUniqueStatement("SELECT * FROM keywords "
+                                      "WHERE short_name='Google'"));
     ASSERT_TRUE(s.is_valid());
     count = 0;
     while (s.Step()) {
@@ -915,10 +908,10 @@
     sql::MetaTable meta_table;
     ASSERT_TRUE(meta_table.Init(&connection, 61, 61));
 
-    EXPECT_FALSE(connection.DoesColumnExist("unmasked_credit_cards",
-                                            "use_count"));
-    EXPECT_FALSE(connection.DoesColumnExist("unmasked_credit_cards",
-                                            "use_date"));
+    EXPECT_FALSE(
+        connection.DoesColumnExist("unmasked_credit_cards", "use_count"));
+    EXPECT_FALSE(
+        connection.DoesColumnExist("unmasked_credit_cards", "use_date"));
   }
 
   DoMigration();
@@ -932,10 +925,10 @@
     // Check version.
     EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
 
-    EXPECT_TRUE(connection.DoesColumnExist("unmasked_credit_cards",
-                                           "use_count"));
-    EXPECT_TRUE(connection.DoesColumnExist("unmasked_credit_cards",
-                                           "use_date"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("unmasked_credit_cards", "use_count"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("unmasked_credit_cards", "use_date"));
   }
 }
 
@@ -956,10 +949,9 @@
     EXPECT_FALSE(connection.DoesTableExist("server_address_metadata"));
 
     // Add a server address --- make sure it gets an ID.
-    sql::Statement insert_profiles(
-        connection.GetUniqueStatement(
-            "INSERT INTO server_addresses(id, postal_code) "
-            "VALUES ('', 90210)"));
+    sql::Statement insert_profiles(connection.GetUniqueStatement(
+        "INSERT INTO server_addresses(id, postal_code) "
+        "VALUES ('', 90210)"));
     insert_profiles.Run();
   }
 
@@ -977,9 +969,8 @@
     EXPECT_TRUE(connection.DoesTableExist("server_card_metadata"));
     EXPECT_TRUE(connection.DoesTableExist("server_address_metadata"));
 
-    sql::Statement read_profiles(
-        connection.GetUniqueStatement(
-            "SELECT id, postal_code FROM server_addresses"));
+    sql::Statement read_profiles(connection.GetUniqueStatement(
+        "SELECT id, postal_code FROM server_addresses"));
     ASSERT_TRUE(read_profiles.Step());
     EXPECT_FALSE(read_profiles.ColumnString(0).empty());
     EXPECT_EQ("90210", read_profiles.ColumnString(1));
@@ -999,8 +990,8 @@
     sql::MetaTable meta_table;
     ASSERT_TRUE(meta_table.Init(&connection, 65, 65));
 
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
-                                            "billing_address_id"));
+    EXPECT_FALSE(
+        connection.DoesColumnExist("credit_cards", "billing_address_id"));
 
     EXPECT_TRUE(connection.Execute(
         "INSERT INTO credit_cards(guid, name_on_card) VALUES ('', 'Alice')"));
@@ -1017,8 +1008,8 @@
     // Check version.
     EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
 
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
-                                           "billing_address_id"));
+    EXPECT_TRUE(
+        connection.DoesColumnExist("credit_cards", "billing_address_id"));
 
     sql::Statement read_credit_cards(connection.GetUniqueStatement(
         "SELECT name_on_card, billing_address_id FROM credit_cards"));
@@ -1045,9 +1036,9 @@
     EXPECT_FALSE(connection.DoesColumnExist("masked_credit_cards",
                                             "billing_address_id"));
 
-    EXPECT_TRUE(connection.Execute(
-        "INSERT INTO masked_credit_cards(id, name_on_card) "
-        "VALUES ('id', 'Alice')"));
+    EXPECT_TRUE(
+        connection.Execute("INSERT INTO masked_credit_cards(id, name_on_card) "
+                           "VALUES ('id', 'Alice')"));
   }
 
   DoMigration();
@@ -1128,8 +1119,7 @@
     // Check version.
     EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
 
-    EXPECT_TRUE(
-        connection.DoesColumnExist("keywords", "last_visited"));
+    EXPECT_TRUE(connection.DoesColumnExist("keywords", "last_visited"));
   }
 }
 
@@ -1277,7 +1267,8 @@
     // Check version.
     EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
 
-    EXPECT_FALSE(connection.DoesColumnExist("masked_credit_cards", "type"));
+    // Don't check for absence of "type", because that's added in version 73
+    // with a different meaning.
     EXPECT_TRUE(connection.DoesColumnExist("masked_credit_cards", "network"));
 
     sql::Statement s_cards_metadata(connection.GetUniqueStatement(
@@ -1326,3 +1317,45 @@
     EXPECT_EQ("", s_masked_cards.ColumnString(0));
   }
 }
+
+// Tests adding "type" column for the "masked_credit_cards" table.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion73ToCurrent) {
+  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_73.sql")));
+
+  // Verify pre-conditions.
+  {
+    sql::Connection connection;
+    ASSERT_TRUE(connection.Open(GetDatabasePath()));
+    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+    sql::MetaTable meta_table;
+    ASSERT_TRUE(meta_table.Init(&connection, 73, 73));
+
+    EXPECT_FALSE(connection.DoesColumnExist("masked_credit_cards", "type"));
+
+    EXPECT_TRUE(
+        connection.Execute("INSERT INTO masked_credit_cards(id, network) "
+                           "VALUES ('id', 'VISA')"));
+  }
+
+  DoMigration();
+
+  // Verify post-conditions.
+  {
+    sql::Connection connection;
+    ASSERT_TRUE(connection.Open(GetDatabasePath()));
+    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+    // Check version.
+    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+    EXPECT_TRUE(connection.DoesColumnExist("masked_credit_cards", "type"));
+
+    sql::Statement cards(connection.GetUniqueStatement(
+        "SELECT id, network, type FROM masked_credit_cards"));
+    ASSERT_TRUE(cards.Step());
+    EXPECT_EQ("id", cards.ColumnString(0));
+    EXPECT_EQ("VISA", cards.ColumnString(1));
+    EXPECT_EQ(CreditCard::CARD_TYPE_UNKNOWN, cards.ColumnInt(2));
+  }
+}
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 5591ad8..003339c 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -402,7 +402,8 @@
   if (obj.is_null() || !GetWindowAndroid())
     return;
 
-  GetViewAndroid()->set_content_offset(gfx::Vector2dF(0.0f, content_offset));
+  GetViewAndroid()->set_content_offset(content_offset);
+  GetViewAndroid()->set_viewport_size(viewport_size);
 
   page_scale_ = page_scale_factor;
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index b7518d4..156f863 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2440,7 +2440,7 @@
     // On Android, call sites should pass in the bounds with correct offset
     // to capture the intended content area.
     gfx::Rect snapshot_bounds(GetView()->GetViewBounds());
-    snapshot_bounds.Offset(0, GetView()->GetNativeView()->content_offset().y());
+    snapshot_bounds.Offset(0, GetView()->GetNativeView()->content_offset());
 #else
     gfx::Rect snapshot_bounds(GetView()->GetViewBounds().size());
 #endif
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 975f18cf..19a9a84 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1431,8 +1431,9 @@
 
   float dip_scale = view_.GetDipScale();
   float top_controls_pix = frame_metadata.top_controls_height * dip_scale;
-  float top_shown_pix =
-      top_controls_pix * frame_metadata.top_controls_shown_ratio;
+  float top_content_offset = frame_metadata.top_controls_height *
+                             frame_metadata.top_controls_shown_ratio;
+  float top_shown_pix = top_content_offset * dip_scale;
 
   if (ime_adapter_android_)
     ime_adapter_android_->UpdateFrameInfo(frame_metadata.selection.start,
@@ -1464,9 +1465,8 @@
   UpdateBackgroundColor(is_transparent ? SK_ColorTRANSPARENT
                                        : frame_metadata.root_background_color);
 
-  view_.set_content_offset(gfx::Vector2dF(0.0f,
-      frame_metadata.top_controls_height *
-          frame_metadata.top_controls_shown_ratio));
+  view_.set_content_offset(top_content_offset);
+  view_.set_viewport_size(frame_metadata.scrollable_viewport_size);
 
   bool top_changed = !FloatEquals(top_shown_pix, prev_top_shown_pix_);
   if (top_changed) {
@@ -1491,9 +1491,7 @@
       gfx::Vector2dF(frame_metadata.min_page_scale_factor,
                      frame_metadata.max_page_scale_factor),
       frame_metadata.root_layer_size, frame_metadata.scrollable_viewport_size,
-      frame_metadata.top_controls_height *
-          frame_metadata.top_controls_shown_ratio,
-      top_shown_pix, top_changed, is_mobile_optimized);
+      top_content_offset, top_shown_pix, top_changed, is_mobile_optimized);
 }
 
 void RenderWidgetHostViewAndroid::ShowInternal() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java b/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
index 472fe05..1c52ac282 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java
@@ -53,6 +53,9 @@
         }
     }
 
+    // Delay between the call to freeConnection and the connection actually beeing   freed.
+    private static final long FREE_CONNECTION_DELAY_MILLIS = 1;
+
     // Connections to services. Indices of the array correspond to the service numbers.
     private final ChildProcessConnection[] mChildProcessConnections;
 
@@ -155,7 +158,7 @@
 
     /** @return a connection ready to be bound, or null if there are no free slots. */
     public ChildProcessConnection allocate(Context context, Bundle serviceBundle,
-            ChildProcessConnection.DeathCallback deathCallback) {
+            final ChildProcessConnection.DeathCallback deathCallback) {
         assert LauncherThread.runningOnLauncherThread();
         if (mFreeConnectionIndices.isEmpty()) {
             Log.d(TAG, "Ran out of services to allocate.");
@@ -165,14 +168,40 @@
         assert mChildProcessConnections[slot] == null;
         ComponentName serviceName = new ComponentName(mPackageName, mServiceClassName + slot);
 
+        ChildProcessConnection.DeathCallback deathCallbackWrapper =
+                new ChildProcessConnection.DeathCallback() {
+                    @Override
+                    public void onChildProcessDied(final ChildProcessConnection connection) {
+                        assert LauncherThread.runningOnLauncherThread();
+
+                        // Forward the call to the provided callback if any.
+                        if (deathCallback != null) {
+                            deathCallback.onChildProcessDied(connection);
+                        }
+
+                        // Freeing a service should be delayed. This is so that we avoid immediately
+                        // reusing the freed service (see http://crbug.com/164069): the framework
+                        // might keep a service process alive when it's been unbound for a short
+                        // time. If a new connection to the same service is bound at that point, the
+                        // process is reused and bad things happen (mostly static variables are set
+                        // when we don't expect them to).
+                        LauncherThread.postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                free(connection);
+                            }
+                        }, FREE_CONNECTION_DELAY_MILLIS);
+                    }
+                };
+
         mChildProcessConnections[slot] = mConnectionFactory.createConnection(context, serviceName,
-                mBindAsExternalService, serviceBundle, mCreationParams, deathCallback);
+                mBindAsExternalService, serviceBundle, mCreationParams, deathCallbackWrapper);
         Log.d(TAG, "Allocator allocated a connection, name: %s, slot: %d", mServiceClassName, slot);
         return mChildProcessConnections[slot];
     }
 
     /** Frees a connection and notifies listeners. */
-    public void free(ChildProcessConnection connection) {
+    private void free(ChildProcessConnection connection) {
         assert LauncherThread.runningOnLauncherThread();
 
         // mChildProcessConnections is relatively short (20 items at max at this point).
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
index be68eec..37b3663 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
@@ -30,7 +30,8 @@
     /**
      * Used to notify the consumer about disconnection of the service. This callback is provided
      * earlier than ConnectionCallbacks below, as a child process might die before the connection is
-     * fully set up.
+     * fully set up. This callback is invoked if the connection is stopped by the client or if it
+     * happens unexpectedly (process crashes).
      */
     interface DeathCallback {
         // Called on Launcher thread.
@@ -61,7 +62,7 @@
     interface ConnectionCallback {
         /**
          * Called when the connection to the service is established.
-         * @param connecion the connection object to the child process
+         * @param connection the connection object to the child process
          */
         void onConnected(ChildProcessConnection connection);
     }
@@ -145,7 +146,6 @@
     }
 
     private final Context mContext;
-    private final ChildProcessConnection.DeathCallback mDeathCallback;
     private final ComponentName mServiceName;
 
     // Parameters passed to the child process through the service binding intent.
@@ -165,6 +165,9 @@
         }
     }
 
+    // Callback invoked when the service is stopped.
+    private DeathCallback mDeathCallback;
+
     // This is set in start() and is used in onServiceConnected().
     private StartCallback mStartCallback;
 
@@ -306,7 +309,7 @@
                 Log.e(TAG, "Failed to establish the service connection.");
                 // We have to notify the caller so that they can free-up associated resources.
                 // TODO(ppi): Can we hard-fail here?
-                mDeathCallback.onChildProcessDied(ChildProcessConnection.this);
+                notifyDeathCallback();
             }
         } finally {
             TraceEvent.end("ChildProcessConnection.start");
@@ -354,6 +357,7 @@
         unbind();
         mService = null;
         mConnectionParams = null;
+        notifyDeathCallback();
     }
 
     private void onServiceConnectedOnLauncherThread(IBinder service) {
@@ -417,13 +421,13 @@
         mServiceDisconnected = true;
         Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPid);
         stop(); // We don't want to auto-restart on crash. Let the browser do that.
-        mDeathCallback.onChildProcessDied(ChildProcessConnection.this);
+
         // If we have a pending connection callback, we need to communicate the failure to
         // the caller.
         if (mConnectionCallback != null) {
             mConnectionCallback.onConnected(null);
+            mConnectionCallback = null;
         }
-        mConnectionCallback = null;
     }
 
     private void onSetupConnectionResult(int pid) {
@@ -598,6 +602,15 @@
         }
     }
 
+    private void notifyDeathCallback() {
+        if (mDeathCallback != null) {
+            // Prevent nested calls to this method.
+            DeathCallback deathCallback = mDeathCallback;
+            mDeathCallback = null;
+            deathCallback.onChildProcessDied(this);
+        }
+    }
+
     @VisibleForTesting
     protected ChildServiceConnection createServiceConnection(int bindFlags) {
         assert LauncherThread.runningOnLauncherThread();
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
index 1c45daf8..aab86ba 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
@@ -54,7 +54,7 @@
     // Represents an invalid process handle; same as base/process/process.h kNullProcessHandle.
     private static final int NULL_PROCESS_HANDLE = 0;
 
-    // Delay between the call to freeConnection and the connection actually beeing   freed.
+    // Delay between the call to freeConnection and the connection actually beeing freed.
     private static final long FREE_CONNECTION_DELAY_MILLIS = 1;
 
     // Factory used by the SpareConnection to create the actual ChildProcessConnection.
@@ -367,8 +367,6 @@
                         assert LauncherThread.runningOnLauncherThread();
                         if (connection.getPid() != 0) {
                             stop(connection.getPid());
-                        } else {
-                            freeConnection(connectionAllocator, connection);
                         }
                         // Forward the call to the provided callback if any. The spare connection
                         // uses that for clean-up.
@@ -515,24 +513,6 @@
         mConnection.setupConnection(connectionBundle, getIBinderCallback(), connectionCallback);
     }
 
-    private static void freeConnection(final ChildConnectionAllocator connectionAllocator,
-            final ChildProcessConnection connection) {
-        assert LauncherThread.runningOnLauncherThread();
-
-        // Freeing a service should be delayed. This is so that we avoid immediately reusing the
-        // freed service (see http://crbug.com/164069): the framework might keep a service process
-        // alive when it's been unbound for a short time. If a new connection to the same service
-        // is bound at that point, the process is reused and bad things happen (mostly static
-        // variables are set when we don't expect them to).
-        LauncherThread.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                assert connectionAllocator != null;
-                connectionAllocator.free(connection);
-            }
-        }, FREE_CONNECTION_DELAY_MILLIS);
-    }
-
     public void onChildProcessStarted() {
         assert LauncherThread.runningOnLauncherThread();
 
@@ -598,7 +578,6 @@
         }
         launcher.onConnectionLost(launcher.mConnection, pid);
         launcher.mConnection.stop();
-        freeConnection(launcher.mConnectionAllocator, launcher.mConnection);
     }
 
     @CalledByNative
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
index 3ff0365..ed2c651b 100644
--- a/device/bluetooth/bluetooth_task_manager_win.cc
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -864,8 +864,9 @@
     std::vector<uint8_t> new_value,
     const HResultCallback& callback) {
   ULONG length = (ULONG)(sizeof(ULONG) + new_value.size());
-  std::unique_ptr<BTH_LE_GATT_CHARACTERISTIC_VALUE> win_new_value(
-      (PBTH_LE_GATT_CHARACTERISTIC_VALUE)(new UCHAR[length]));
+  std::vector<UCHAR> data(length);
+  auto* win_new_value =
+      reinterpret_cast<PBTH_LE_GATT_CHARACTERISTIC_VALUE>(&data[0]);
   win_new_value->DataSize = (ULONG)new_value.size();
   for (ULONG i = 0; i < new_value.size(); i++)
     win_new_value->Data[i] = new_value[i];
@@ -873,7 +874,7 @@
   HRESULT hr =
       win::BluetoothLowEnergyWrapper::GetInstance()->WriteCharacteristicValue(
           service_path, (PBTH_LE_GATT_CHARACTERISTIC)(&characteristic),
-          win_new_value.get());
+          win_new_value);
 
   ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, hr));
 }
diff --git a/extensions/browser/api/webcam_private/v4l2_webcam.cc b/extensions/browser/api/webcam_private/v4l2_webcam.cc
index 0bcbe64..277493b 100644
--- a/extensions/browser/api/webcam_private/v4l2_webcam.cc
+++ b/extensions/browser/api/webcam_private/v4l2_webcam.cc
@@ -77,32 +77,58 @@
   return res >= 0;
 }
 
-bool V4L2Webcam::GetWebcamParameter(int fd, uint32_t control_id, int* value) {
+bool V4L2Webcam::GetWebcamParameter(int fd,
+                                    uint32_t control_id,
+                                    int* value,
+                                    int* min_value,
+                                    int* max_value) {
+  // Try to query current value for |control_id|. The getter fails if not
+  // supported.
   struct v4l2_control v4l2_ctrl = {control_id};
-
   if (HANDLE_EINTR(ioctl(fd, VIDIOC_G_CTRL, &v4l2_ctrl)))
     return false;
-
   *value = v4l2_ctrl.value;
+
+  // Try to query the valid range for |control_id|. Not supporting a range query
+  // is not a failure.
+  struct v4l2_queryctrl v4l2_range_query = {control_id};
+  if (HANDLE_EINTR(ioctl(fd, VIDIOC_QUERYCTRL, &v4l2_range_query))) {
+    *min_value = 0;
+    *max_value = 0;
+  } else {
+    *min_value = v4l2_range_query.minimum;
+    *max_value = v4l2_range_query.maximum;
+  }
+
   return true;
 }
 
 void V4L2Webcam::GetPan(const GetPTZCompleteCallback& callback) {
   int value = 0;
-  bool success = GetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, &value);
-  callback.Run(success, value);
+  int min_value = 0;
+  int max_value = 0;
+  bool success = GetWebcamParameter(fd_.get(), V4L2_CID_PAN_ABSOLUTE, &value,
+                                    &min_value, &max_value);
+
+  callback.Run(success, value, min_value, max_value);
 }
 
 void V4L2Webcam::GetTilt(const GetPTZCompleteCallback& callback) {
   int value = 0;
-  bool success = GetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, &value);
-  callback.Run(success, value);
+  int min_value = 0;
+  int max_value = 0;
+  bool success = GetWebcamParameter(fd_.get(), V4L2_CID_TILT_ABSOLUTE, &value,
+                                    &min_value, &max_value);
+  callback.Run(success, value, min_value, max_value);
 }
 
 void V4L2Webcam::GetZoom(const GetPTZCompleteCallback& callback) {
   int value = 0;
-  bool success = GetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, &value);
-  callback.Run(success, value);
+  int min_value = 0;
+  int max_value = 0;
+  bool success = GetWebcamParameter(fd_.get(), V4L2_CID_ZOOM_ABSOLUTE, &value,
+                                    &min_value, &max_value);
+  callback.Run(success, value, min_value, max_value);
 }
 
 void V4L2Webcam::SetPan(int value,
diff --git a/extensions/browser/api/webcam_private/v4l2_webcam.h b/extensions/browser/api/webcam_private/v4l2_webcam.h
index 5c2ac79..a09af69 100644
--- a/extensions/browser/api/webcam_private/v4l2_webcam.h
+++ b/extensions/browser/api/webcam_private/v4l2_webcam.h
@@ -22,8 +22,12 @@
  private:
   ~V4L2Webcam() override;
   bool EnsureLogitechCommandsMapped();
-  bool SetWebcamParameter(int fd, uint32_t control_id, int value);
-  bool GetWebcamParameter(int fd, uint32_t control_id, int* value);
+  static bool SetWebcamParameter(int fd, uint32_t control_id, int value);
+  static bool GetWebcamParameter(int fd,
+                                 uint32_t control_id,
+                                 int* value,
+                                 int* min_value,
+                                 int* max_value);
 
   // Webcam:
   void GetPan(const GetPTZCompleteCallback& callback) override;
diff --git a/extensions/browser/api/webcam_private/visca_webcam.cc b/extensions/browser/api/webcam_private/visca_webcam.cc
index 9ef6654..52477e0 100644
--- a/extensions/browser/api/webcam_private/visca_webcam.cc
+++ b/extensions/browser/api/webcam_private/visca_webcam.cc
@@ -316,7 +316,7 @@
                                      const std::vector<char>& response) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (!success) {
-    callback.Run(false, 0);
+    callback.Run(false, 0 /* value */, 0 /* min_value */, 0 /* max_value */);
     ProcessNextCommand();
     return;
   }
@@ -334,7 +334,7 @@
       break;
   }
   if (!is_valid_response) {
-    callback.Run(false, 0);
+    callback.Run(false, 0 /* value */, 0 /* min_value */, 0 /* max_value */);
     ProcessNextCommand();
     return;
   }
@@ -356,7 +356,8 @@
       value = BuildResponseInt(response, 2);
       break;
   }
-  callback.Run(true, value);
+  // TODO(pbos): Add support for valid ranges.
+  callback.Run(true, value, 0, 0);
   ProcessNextCommand();
 }
 
diff --git a/extensions/browser/api/webcam_private/visca_webcam_unittest.cc b/extensions/browser/api/webcam_private/visca_webcam_unittest.cc
index a2ecc8a..5109650 100644
--- a/extensions/browser/api/webcam_private/visca_webcam_unittest.cc
+++ b/extensions/browser/api/webcam_private/visca_webcam_unittest.cc
@@ -61,9 +61,14 @@
   GetPTZExpectations(bool expected_success, int expected_value)
       : expected_success_(expected_success), expected_value_(expected_value) {}
 
-  void OnCallback(bool success, int value) {
+  void OnCallback(bool success, int value, int min_value, int max_value) {
     EXPECT_EQ(expected_success_, success);
     EXPECT_EQ(expected_value_, value);
+
+    // TODO(pbos): min/max values aren't currently supported. These expectations
+    // should be updated when we do.
+    EXPECT_EQ(0, min_value);
+    EXPECT_EQ(0, max_value);
   }
 
  private:
diff --git a/extensions/browser/api/webcam_private/webcam.h b/extensions/browser/api/webcam_private/webcam.h
index 6aba62d..d008a93 100644
--- a/extensions/browser/api/webcam_private/webcam.h
+++ b/extensions/browser/api/webcam_private/webcam.h
@@ -31,8 +31,9 @@
 
   Webcam();
 
-  using GetPTZCompleteCallback = base::Callback<void(bool, int)>;
-  using SetPTZCompleteCallback = base::Callback<void(bool)>;
+  using GetPTZCompleteCallback = base::Callback<
+      void(bool success, int value, int min_value, int max_value)>;
+  using SetPTZCompleteCallback = base::Callback<void(bool success)>;
 
   virtual void GetPan(const GetPTZCompleteCallback& callback) = 0;
   virtual void GetTilt(const GetPTZCompleteCallback& callback) = 0;
diff --git a/extensions/browser/api/webcam_private/webcam_private_api.h b/extensions/browser/api/webcam_private/webcam_private_api.h
index 4da8d4f..069dda5 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api.h
+++ b/extensions/browser/api/webcam_private/webcam_private_api.h
@@ -140,10 +140,21 @@
     INQUIRY_TILT,
     INQUIRY_ZOOM,
   };
-  void OnGetWebcamParameters(InquiryType type, bool success, int value);
 
+  void OnGetWebcamParameters(InquiryType type,
+                             bool success,
+                             int value,
+                             int min_value,
+                             int max_value);
+
+  int min_pan_;
+  int max_pan_;
   int pan_;
+  int min_tilt_;
+  int max_tilt_;
   int tilt_;
+  int min_zoom_;
+  int max_zoom_;
   int zoom_;
   bool get_pan_;
   bool get_tilt_;
diff --git a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
index 05457ce..6981124 100644
--- a/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
+++ b/extensions/browser/api/webcam_private/webcam_private_api_chromeos.cc
@@ -320,8 +320,14 @@
 }
 
 WebcamPrivateGetFunction::WebcamPrivateGetFunction()
-    : pan_(0),
+    : min_pan_(0),
+      max_pan_(0),
+      pan_(0),
+      min_tilt_(0),
+      max_tilt_(0),
       tilt_(0),
+      min_zoom_(0),
+      max_zoom_(0),
       zoom_(0),
       get_pan_(false),
       get_tilt_(false),
@@ -355,7 +361,9 @@
 
 void WebcamPrivateGetFunction::OnGetWebcamParameters(InquiryType type,
                                                      bool success,
-                                                     int value) {
+                                                     int value,
+                                                     int min_value,
+                                                     int max_value) {
   if (!success_)
     return;
   success_ = success_ && success;
@@ -366,23 +374,45 @@
   } else {
     switch (type) {
       case INQUIRY_PAN:
+        min_pan_ = min_value;
+        max_pan_ = max_value;
         pan_ = value;
         get_pan_ = true;
         break;
       case INQUIRY_TILT:
+        min_tilt_ = min_value;
+        max_tilt_ = max_value;
         tilt_ = value;
         get_tilt_ = true;
         break;
       case INQUIRY_ZOOM:
+        min_zoom_ = min_value;
+        max_zoom_ = max_value;
         zoom_ = value;
         get_zoom_ = true;
         break;
     }
     if (get_pan_ && get_tilt_ && get_zoom_) {
-      webcam_private::WebcamConfiguration result;
-      result.pan.reset(new double(pan_));
-      result.tilt.reset(new double(tilt_));
-      result.zoom.reset(new double(zoom_));
+      webcam_private::WebcamCurrentConfiguration result;
+      if (min_pan_ != max_pan_) {
+        result.pan_range = base::MakeUnique<webcam_private::Range>();
+        result.pan_range->min = min_pan_;
+        result.pan_range->max = max_pan_;
+      }
+      if (min_tilt_ != max_tilt_) {
+        result.tilt_range = base::MakeUnique<webcam_private::Range>();
+        result.tilt_range->min = min_tilt_;
+        result.tilt_range->max = max_tilt_;
+      }
+      if (min_zoom_ != max_zoom_) {
+        result.zoom_range = base::MakeUnique<webcam_private::Range>();
+        result.zoom_range->min = min_zoom_;
+        result.zoom_range->max = max_zoom_;
+      }
+
+      result.pan = pan_;
+      result.tilt = tilt_;
+      result.zoom = zoom_;
       SetResult(result.ToValue());
       SendResponse(true);
     }
diff --git a/extensions/common/api/webcam_private.idl b/extensions/common/api/webcam_private.idl
index 8095699..3f5e11c 100644
--- a/extensions/common/api/webcam_private.idl
+++ b/extensions/common/api/webcam_private.idl
@@ -22,9 +22,22 @@
     double? zoom;
   };
 
+  dictionary Range { double min; double max; };
+
+  dictionary WebcamCurrentConfiguration {
+    double pan;
+    double tilt;
+    double zoom;
+
+    // Supported range of pan, tilt and zoom values.
+    Range? panRange;
+    Range? tiltRange;
+    Range? zoomRange;
+  };
+
   callback WebcamIdCallback = void(DOMString webcamId);
   callback WebcamConfigurationCallback =
-      void(WebcamConfiguration configuration);
+      void(WebcamCurrentConfiguration configuration);
 
   interface Functions {
     // Open a serial port that controls a webcam.
@@ -36,9 +49,9 @@
 
     static void get(DOMString webcamId, WebcamConfigurationCallback callback);
     static void set(DOMString webcamId, WebcamConfiguration config);
-    
+
     // Reset a webcam. Note: the value of the parameter have no effect, it's the
-    // presence of the parameter that matters. E.g.: reset(webcamId, {pan: 0, 
+    // presence of the parameter that matters. E.g.: reset(webcamId, {pan: 0,
     // tilt: 1}); will reset pan & tilt, but not zoom.
     static void reset(DOMString webcamId, WebcamConfiguration config);
   };
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index 73f7770..c7722c0 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -17,44 +17,48 @@
     "api/display_source/display_source_session.h",
     "api_activity_logger.cc",
     "api_activity_logger.h",
-    "api_binding.cc",
-    "api_binding.h",
-    "api_binding_bridge.cc",
-    "api_binding_bridge.h",
-    "api_binding_hooks.cc",
-    "api_binding_hooks.h",
-    "api_binding_hooks_delegate.cc",
-    "api_binding_hooks_delegate.h",
-    "api_binding_js_util.cc",
-    "api_binding_js_util.h",
-    "api_binding_types.cc",
-    "api_binding_types.h",
-    "api_bindings_system.cc",
-    "api_bindings_system.h",
     "api_definitions_natives.cc",
     "api_definitions_natives.h",
-    "api_event_handler.cc",
-    "api_event_handler.h",
-    "api_event_listeners.cc",
-    "api_event_listeners.h",
-    "api_invocation_errors.cc",
-    "api_invocation_errors.h",
-    "api_last_error.cc",
-    "api_last_error.h",
-    "api_request_handler.cc",
-    "api_request_handler.h",
-    "api_signature.cc",
-    "api_signature.h",
-    "api_type_reference_map.cc",
-    "api_type_reference_map.h",
     "app_window_custom_bindings.cc",
     "app_window_custom_bindings.h",
-    "argument_spec.cc",
-    "argument_spec.h",
-    "binding_access_checker.cc",
-    "binding_access_checker.h",
     "binding_generating_native_handler.cc",
     "binding_generating_native_handler.h",
+    "bindings/api_binding.cc",
+    "bindings/api_binding.h",
+    "bindings/api_binding_bridge.cc",
+    "bindings/api_binding_bridge.h",
+    "bindings/api_binding_hooks.cc",
+    "bindings/api_binding_hooks.h",
+    "bindings/api_binding_hooks_delegate.cc",
+    "bindings/api_binding_hooks_delegate.h",
+    "bindings/api_binding_js_util.cc",
+    "bindings/api_binding_js_util.h",
+    "bindings/api_binding_types.cc",
+    "bindings/api_binding_types.h",
+    "bindings/api_bindings_system.cc",
+    "bindings/api_bindings_system.h",
+    "bindings/api_event_handler.cc",
+    "bindings/api_event_handler.h",
+    "bindings/api_event_listeners.cc",
+    "bindings/api_event_listeners.h",
+    "bindings/api_invocation_errors.cc",
+    "bindings/api_invocation_errors.h",
+    "bindings/api_last_error.cc",
+    "bindings/api_last_error.h",
+    "bindings/api_request_handler.cc",
+    "bindings/api_request_handler.h",
+    "bindings/api_signature.cc",
+    "bindings/api_signature.h",
+    "bindings/api_type_reference_map.cc",
+    "bindings/api_type_reference_map.h",
+    "bindings/argument_spec.cc",
+    "bindings/argument_spec.h",
+    "bindings/binding_access_checker.cc",
+    "bindings/binding_access_checker.h",
+    "bindings/declarative_event.cc",
+    "bindings/declarative_event.h",
+    "bindings/event_emitter.cc",
+    "bindings/event_emitter.h",
     "blob_native_handler.cc",
     "blob_native_handler.h",
     "chrome_setting.cc",
@@ -71,8 +75,6 @@
     "css_native_handler.h",
     "declarative_content_hooks_delegate.cc",
     "declarative_content_hooks_delegate.h",
-    "declarative_event.cc",
-    "declarative_event.h",
     "dispatcher.cc",
     "dispatcher.h",
     "dispatcher_delegate.h",
@@ -84,8 +86,6 @@
     "dom_activity_logger.h",
     "event_bindings.cc",
     "event_bindings.h",
-    "event_emitter.cc",
-    "event_emitter.h",
     "extension_bindings_system.h",
     "extension_frame_helper.cc",
     "extension_frame_helper.h",
@@ -305,31 +305,31 @@
   sources = [
     "activity_log_converter_strategy_unittest.cc",
     "api/mojo_private/mojo_private_unittest.cc",
-    "api_binding_hooks_test_delegate.cc",
-    "api_binding_hooks_test_delegate.h",
-    "api_binding_js_util_unittest.cc",
-    "api_binding_test.cc",
-    "api_binding_test.h",
-    "api_binding_test_util.cc",
-    "api_binding_test_util.h",
-    "api_binding_unittest.cc",
-    "api_bindings_system_unittest.cc",
-    "api_bindings_system_unittest.h",
-    "api_event_handler_unittest.cc",
-    "api_event_listeners_unittest.cc",
-    "api_invocation_errors_unittest.cc",
-    "api_last_error_unittest.cc",
-    "api_request_handler_unittest.cc",
-    "api_signature_unittest.cc",
     "api_test_base.cc",
     "api_test_base.h",
     "api_test_base_unittest.cc",
-    "argument_spec_builder.cc",
-    "argument_spec_builder.h",
-    "argument_spec_unittest.cc",
-    "binding_access_checker_unittest.cc",
-    "declarative_event_unittest.cc",
-    "event_emitter_unittest.cc",
+    "bindings/api_binding_hooks_test_delegate.cc",
+    "bindings/api_binding_hooks_test_delegate.h",
+    "bindings/api_binding_js_util_unittest.cc",
+    "bindings/api_binding_test.cc",
+    "bindings/api_binding_test.h",
+    "bindings/api_binding_test_util.cc",
+    "bindings/api_binding_test_util.h",
+    "bindings/api_binding_unittest.cc",
+    "bindings/api_bindings_system_unittest.cc",
+    "bindings/api_bindings_system_unittest.h",
+    "bindings/api_event_handler_unittest.cc",
+    "bindings/api_event_listeners_unittest.cc",
+    "bindings/api_invocation_errors_unittest.cc",
+    "bindings/api_last_error_unittest.cc",
+    "bindings/api_request_handler_unittest.cc",
+    "bindings/api_signature_unittest.cc",
+    "bindings/argument_spec_builder.cc",
+    "bindings/argument_spec_builder.h",
+    "bindings/argument_spec_unittest.cc",
+    "bindings/binding_access_checker_unittest.cc",
+    "bindings/declarative_event_unittest.cc",
+    "bindings/event_emitter_unittest.cc",
     "event_unittest.cc",
     "gc_callback_unittest.cc",
     "json_schema_unittest.cc",
diff --git a/extensions/renderer/bindings/DEPS b/extensions/renderer/bindings/DEPS
new file mode 100644
index 0000000..cec3540
--- /dev/null
+++ b/extensions/renderer/bindings/DEPS
@@ -0,0 +1,25 @@
+include_rules = [
+  # The core bindings module is designed to be independent of the extensions
+  # system.
+  # TODO(devlin): We could move bindings to be a //component, if we wanted.
+  "-extensions/renderer",
+  "+extensions/renderer/bindings",
+
+  "-extensions/common",
+  # We allow a few specific includes around event filtering, since these are
+  # necessary for filtered listeners and do not themselves include any
+  # extensions system knowledge.
+  "+extensions/common/event_filter.h",
+  "+extensions/common/event_filtering_info.h",
+  "+extensions/common/event_matcher.h",
+  "+extensions/common/value_counter.h",
+]
+
+specific_include_rules = {
+  # Allow tests to include extensions system files. Typically, this shouldn't
+  # be necessary, but it can be useful.
+  ".*test\.(cc|h)$": [
+    "+extensions/renderer",
+    "+extensions/common",
+  ]
+}
diff --git a/extensions/renderer/bindings/OWNERS b/extensions/renderer/bindings/OWNERS
new file mode 100644
index 0000000..9d2a3d1a
--- /dev/null
+++ b/extensions/renderer/bindings/OWNERS
@@ -0,0 +1,2 @@
+rdevlin.cronin@chromium.org
+lazyboy@chromium.org
diff --git a/extensions/renderer/api_binding.cc b/extensions/renderer/bindings/api_binding.cc
similarity index 97%
rename from extensions/renderer/api_binding.cc
rename to extensions/renderer/bindings/api_binding.cc
index 32580304..e69ecca 100644
--- a/extensions/renderer/api_binding.cc
+++ b/extensions/renderer/bindings/api_binding.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding.h"
+#include "extensions/renderer/bindings/api_binding.h"
 
 #include <algorithm>
 
@@ -12,17 +12,15 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "extensions/common/extension_api.h"
-#include "extensions/renderer/api_binding_hooks.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/api_event_handler.h"
-#include "extensions/renderer/api_invocation_errors.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/binding_access_checker.h"
-#include "extensions/renderer/declarative_event.h"
-#include "extensions/renderer/v8_helpers.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
+#include "extensions/renderer/bindings/declarative_event.h"
 #include "gin/arguments.h"
 #include "gin/handle.h"
 #include "gin/per_context_data.h"
diff --git a/extensions/renderer/api_binding.h b/extensions/renderer/bindings/api_binding.h
similarity index 96%
rename from extensions/renderer/api_binding.h
rename to extensions/renderer/bindings/api_binding.h
index 8cd3e819..3412e6e2 100644
--- a/extensions/renderer/api_binding.h
+++ b/extensions/renderer/bindings/api_binding.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_H_
-#define EXTENSIONS_RENDERER_API_BINDING_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_H_
 
 #include <map>
 #include <memory>
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/supports_user_data.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "v8/include/v8.h"
 
 namespace base {
@@ -160,4 +160,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_H_
diff --git a/extensions/renderer/api_binding_bridge.cc b/extensions/renderer/bindings/api_binding_bridge.cc
similarity index 96%
rename from extensions/renderer/api_binding_bridge.cc
rename to extensions/renderer/bindings/api_binding_bridge.cc
index 38073499..9f4bc91 100644
--- a/extensions/renderer/api_binding_bridge.cc
+++ b/extensions/renderer/bindings/api_binding_bridge.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_bridge.h"
+#include "extensions/renderer/bindings/api_binding_bridge.h"
 
 #include "base/values.h"
-#include "extensions/renderer/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
 #include "gin/converter.h"
 #include "gin/object_template_builder.h"
 
diff --git a/extensions/renderer/api_binding_bridge.h b/extensions/renderer/bindings/api_binding_bridge.h
similarity index 88%
rename from extensions/renderer/api_binding_bridge.h
rename to extensions/renderer/bindings/api_binding_bridge.h
index 32f1238..298e15e 100644
--- a/extensions/renderer/api_binding_bridge.h
+++ b/extensions/renderer/bindings/api_binding_bridge.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_BRIDGE_H_
-#define EXTENSIONS_RENDERER_API_BINDING_BRIDGE_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_BRIDGE_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_BRIDGE_H_
 
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "gin/wrappable.h"
 #include "v8/include/v8.h"
 
@@ -60,4 +60,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_BRIDGE_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_BRIDGE_H_
diff --git a/extensions/renderer/api_binding_hooks.cc b/extensions/renderer/bindings/api_binding_hooks.cc
similarity index 98%
rename from extensions/renderer/api_binding_hooks.cc
rename to extensions/renderer/bindings/api_binding_hooks.cc
index 03d1419..cd61147d 100644
--- a/extensions/renderer/api_binding_hooks.cc
+++ b/extensions/renderer/bindings/api_binding_hooks.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/supports_user_data.h"
-#include "extensions/renderer/api_binding_hooks_delegate.h"
-#include "extensions/renderer/api_signature.h"
+#include "extensions/renderer/bindings/api_binding_hooks_delegate.h"
+#include "extensions/renderer/bindings/api_signature.h"
 #include "gin/arguments.h"
 #include "gin/handle.h"
 #include "gin/object_template_builder.h"
diff --git a/extensions/renderer/api_binding_hooks.h b/extensions/renderer/bindings/api_binding_hooks.h
similarity index 94%
rename from extensions/renderer/api_binding_hooks.h
rename to extensions/renderer/bindings/api_binding_hooks.h
index 82f8510..f29ccb5 100644
--- a/extensions/renderer/api_binding_hooks.h
+++ b/extensions/renderer/bindings/api_binding_hooks.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_HOOKS_H_
-#define EXTENSIONS_RENDERER_API_BINDING_HOOKS_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_H_
 
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
@@ -102,4 +102,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_HOOKS_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_H_
diff --git a/extensions/renderer/api_binding_hooks_delegate.cc b/extensions/renderer/bindings/api_binding_hooks_delegate.cc
similarity index 92%
rename from extensions/renderer/api_binding_hooks_delegate.cc
rename to extensions/renderer/bindings/api_binding_hooks_delegate.cc
index 03b1413..8b954c8 100644
--- a/extensions/renderer/api_binding_hooks_delegate.cc
+++ b/extensions/renderer/bindings/api_binding_hooks_delegate.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_hooks_delegate.h"
+#include "extensions/renderer/bindings/api_binding_hooks_delegate.h"
 
 namespace extensions {
 
diff --git a/extensions/renderer/api_binding_hooks_delegate.h b/extensions/renderer/bindings/api_binding_hooks_delegate.h
similarity index 82%
rename from extensions/renderer/api_binding_hooks_delegate.h
rename to extensions/renderer/bindings/api_binding_hooks_delegate.h
index 13d60b2..9ab14f9 100644
--- a/extensions/renderer/api_binding_hooks_delegate.h
+++ b/extensions/renderer/bindings/api_binding_hooks_delegate.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_HOOKS_DELEGATE_H_
-#define EXTENSIONS_RENDERER_API_BINDING_HOOKS_DELEGATE_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_DELEGATE_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_DELEGATE_H_
 
-#include "extensions/renderer/api_binding_hooks.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
@@ -42,4 +42,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_HOOKS_DELEGATE_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_DELEGATE_H_
diff --git a/extensions/renderer/api_binding_hooks_test_delegate.cc b/extensions/renderer/bindings/api_binding_hooks_test_delegate.cc
similarity index 96%
rename from extensions/renderer/api_binding_hooks_test_delegate.cc
rename to extensions/renderer/bindings/api_binding_hooks_test_delegate.cc
index 85d3cca..fe0ea19 100644
--- a/extensions/renderer/api_binding_hooks_test_delegate.cc
+++ b/extensions/renderer/bindings/api_binding_hooks_test_delegate.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_hooks_test_delegate.h"
+#include "extensions/renderer/bindings/api_binding_hooks_test_delegate.h"
 
 namespace extensions {
 
diff --git a/extensions/renderer/api_binding_hooks_test_delegate.h b/extensions/renderer/bindings/api_binding_hooks_test_delegate.h
similarity index 87%
rename from extensions/renderer/api_binding_hooks_test_delegate.h
rename to extensions/renderer/bindings/api_binding_hooks_test_delegate.h
index 94233cb..2ea563bf 100644
--- a/extensions/renderer/api_binding_hooks_test_delegate.h
+++ b/extensions/renderer/bindings/api_binding_hooks_test_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_HOOKS_TEST_DELEGATE_H_
-#define EXTENSIONS_RENDERER_API_BINDING_HOOKS_TEST_DELEGATE_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_TEST_DELEGATE_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_TEST_DELEGATE_H_
 
 #include <map>
 #include <string>
@@ -11,8 +11,8 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
-#include "extensions/renderer/api_binding_hooks_delegate.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_hooks_delegate.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
@@ -71,4 +71,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_HOOKS_TEST_DELEGATE_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_HOOKS_TEST_DELEGATE_H_
diff --git a/extensions/renderer/api_binding_js_util.cc b/extensions/renderer/bindings/api_binding_js_util.cc
similarity index 95%
rename from extensions/renderer/api_binding_js_util.cc
rename to extensions/renderer/bindings/api_binding_js_util.cc
index 29c39be..8f1fb4367 100644
--- a/extensions/renderer/api_binding_js_util.cc
+++ b/extensions/renderer/bindings/api_binding_js_util.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_js_util.h"
+#include "extensions/renderer/bindings/api_binding_js_util.h"
 
 #include "base/values.h"
-#include "extensions/renderer/api_event_handler.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/declarative_event.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/declarative_event.h"
 #include "gin/converter.h"
 #include "gin/dictionary.h"
 #include "gin/handle.h"
diff --git a/extensions/renderer/api_binding_js_util.h b/extensions/renderer/bindings/api_binding_js_util.h
similarity index 93%
rename from extensions/renderer/api_binding_js_util.h
rename to extensions/renderer/bindings/api_binding_js_util.h
index 9963c82..78675d30 100644
--- a/extensions/renderer/api_binding_js_util.h
+++ b/extensions/renderer/bindings/api_binding_js_util.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_JS_UTIL_H_
-#define EXTENSIONS_RENDERER_API_BINDING_JS_UTIL_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_JS_UTIL_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_JS_UTIL_H_
 
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "gin/wrappable.h"
 #include "v8/include/v8.h"
 
@@ -105,4 +105,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_JS_UTIL_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_JS_UTIL_H_
diff --git a/extensions/renderer/api_binding_js_util_unittest.cc b/extensions/renderer/bindings/api_binding_js_util_unittest.cc
similarity index 96%
rename from extensions/renderer/api_binding_js_util_unittest.cc
rename to extensions/renderer/bindings/api_binding_js_util_unittest.cc
index 3c0fdec..f6e8375 100644
--- a/extensions/renderer/api_binding_js_util_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_js_util_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_js_util.h"
+#include "extensions/renderer/bindings/api_binding_js_util.h"
 
 #include "base/bind.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_bindings_system.h"
-#include "extensions/renderer/api_bindings_system_unittest.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_bindings_system.h"
+#include "extensions/renderer/bindings/api_bindings_system_unittest.h"
 #include "gin/handle.h"
 
 namespace extensions {
diff --git a/extensions/renderer/api_binding_test.cc b/extensions/renderer/bindings/api_binding_test.cc
similarity index 98%
rename from extensions/renderer/api_binding_test.cc
rename to extensions/renderer/bindings/api_binding_test.cc
index 05ad0d8..c07825b 100644
--- a/extensions/renderer/api_binding_test.cc
+++ b/extensions/renderer/bindings/api_binding_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
diff --git a/extensions/renderer/api_binding_test.h b/extensions/renderer/bindings/api_binding_test.h
similarity index 91%
rename from extensions/renderer/api_binding_test.h
rename to extensions/renderer/bindings/api_binding_test.h
index 76e0f716..fe2f193 100644
--- a/extensions/renderer/api_binding_test.h
+++ b/extensions/renderer/bindings/api_binding_test.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_TEST_H_
-#define EXTENSIONS_RENDERER_API_BINDING_TEST_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TEST_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TEST_H_
 
 #include <memory>
 #include <vector>
@@ -69,4 +69,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_TEST_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TEST_H_
diff --git a/extensions/renderer/api_binding_test_util.cc b/extensions/renderer/bindings/api_binding_test_util.cc
similarity index 98%
rename from extensions/renderer/api_binding_test_util.cc
rename to extensions/renderer/bindings/api_binding_test_util.cc
index 9977556..79091dfa 100644
--- a/extensions/renderer/api_binding_test_util.cc
+++ b/extensions/renderer/bindings/api_binding_test_util.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
 
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
diff --git a/extensions/renderer/api_binding_test_util.h b/extensions/renderer/bindings/api_binding_test_util.h
similarity index 96%
rename from extensions/renderer/api_binding_test_util.h
rename to extensions/renderer/bindings/api_binding_test_util.h
index 949049d..e0a7ada 100644
--- a/extensions/renderer/api_binding_test_util.h
+++ b/extensions/renderer/bindings/api_binding_test_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_TEST_UTIL_H_
-#define EXTENSIONS_RENDERER_API_BINDING_TEST_UTIL_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TEST_UTIL_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TEST_UTIL_H_
 
 #include <memory>
 #include <string>
@@ -127,4 +127,4 @@
 
 }  // extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_TEST_UTIL_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TEST_UTIL_H_
diff --git a/extensions/renderer/api_binding_types.cc b/extensions/renderer/bindings/api_binding_types.cc
similarity index 82%
rename from extensions/renderer/api_binding_types.cc
rename to extensions/renderer/bindings/api_binding_types.cc
index e354d8b..4f2be0ec 100644
--- a/extensions/renderer/api_binding_types.cc
+++ b/extensions/renderer/bindings/api_binding_types.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 
 namespace extensions {
 namespace binding {
diff --git a/extensions/renderer/api_binding_types.h b/extensions/renderer/bindings/api_binding_types.h
similarity index 91%
rename from extensions/renderer/api_binding_types.h
rename to extensions/renderer/bindings/api_binding_types.h
index 07aecf8..3f2ee5306 100644
--- a/extensions/renderer/api_binding_types.h
+++ b/extensions/renderer/bindings/api_binding_types.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDING_TYPES_H_
-#define EXTENSIONS_RENDERER_API_BINDING_TYPES_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TYPES_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TYPES_H_
 
 #include <memory>
 #include <vector>
@@ -52,4 +52,4 @@
 }  // namespace binding
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDING_TYPES_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDING_TYPES_H_
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/bindings/api_binding_unittest.cc
similarity index 98%
rename from extensions/renderer/api_binding_unittest.cc
rename to extensions/renderer/bindings/api_binding_unittest.cc
index 20114a8..9f43d1a 100644
--- a/extensions/renderer/api_binding_unittest.cc
+++ b/extensions/renderer/bindings/api_binding_unittest.cc
@@ -2,21 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_binding.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "extensions/renderer/api_binding_hooks.h"
-#include "extensions/renderer/api_binding_hooks_test_delegate.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_event_handler.h"
-#include "extensions/renderer/api_invocation_errors.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/api_binding.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_hooks_test_delegate.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 #include "gin/arguments.h"
 #include "gin/converter.h"
 #include "gin/public/context_holder.h"
diff --git a/extensions/renderer/api_bindings_system.cc b/extensions/renderer/bindings/api_bindings_system.cc
similarity index 97%
rename from extensions/renderer/api_bindings_system.cc
rename to extensions/renderer/bindings/api_bindings_system.cc
index c39be87b..f3b0790 100644
--- a/extensions/renderer/api_bindings_system.cc
+++ b/extensions/renderer/bindings/api_bindings_system.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_bindings_system.h"
+#include "extensions/renderer/bindings/api_bindings_system.h"
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
-#include "extensions/renderer/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
 
 namespace extensions {
 
diff --git a/extensions/renderer/api_bindings_system.h b/extensions/renderer/bindings/api_bindings_system.h
similarity index 89%
rename from extensions/renderer/api_bindings_system.h
rename to extensions/renderer/bindings/api_bindings_system.h
index a030371d..dd6d48e 100644
--- a/extensions/renderer/api_bindings_system.h
+++ b/extensions/renderer/bindings/api_bindings_system.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDINGS_SYSTEM_H_
-#define EXTENSIONS_RENDERER_API_BINDINGS_SYSTEM_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDINGS_SYSTEM_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDINGS_SYSTEM_H_
 
 #include <map>
 #include <memory>
@@ -11,13 +11,13 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "extensions/renderer/api_binding.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/api_event_handler.h"
-#include "extensions/renderer/api_last_error.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/api_binding.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
+#include "extensions/renderer/bindings/api_last_error.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 
 namespace base {
 class DictionaryValue;
@@ -146,4 +146,4 @@
 
 }  // namespace
 
-#endif  // EXTENSIONS_RENDERER_API_BINDINGS_SYSTEM_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDINGS_SYSTEM_H_
diff --git a/extensions/renderer/api_bindings_system_unittest.cc b/extensions/renderer/bindings/api_bindings_system_unittest.cc
similarity index 96%
rename from extensions/renderer/api_bindings_system_unittest.cc
rename to extensions/renderer/bindings/api_bindings_system_unittest.cc
index 30c5d1c..1a63eca 100644
--- a/extensions/renderer/api_bindings_system_unittest.cc
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_bindings_system.h"
+#include "extensions/renderer/bindings/api_bindings_system.h"
 
 #include "base/bind.h"
 #include "base/macros.h"
@@ -11,14 +11,13 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "extensions/common/event_filtering_info.h"
-#include "extensions/common/extension_api.h"
-#include "extensions/renderer/api_binding.h"
-#include "extensions/renderer/api_binding_hooks.h"
-#include "extensions/renderer/api_binding_hooks_test_delegate.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/api_bindings_system_unittest.h"
-#include "extensions/renderer/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_binding.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_hooks_test_delegate.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_bindings_system_unittest.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
 #include "gin/arguments.h"
 #include "gin/converter.h"
 #include "gin/try_catch.h"
diff --git a/extensions/renderer/api_bindings_system_unittest.h b/extensions/renderer/bindings/api_bindings_system_unittest.h
similarity index 90%
rename from extensions/renderer/api_bindings_system_unittest.h
rename to extensions/renderer/bindings/api_bindings_system_unittest.h
index 4f5deb8..d4510fc 100644
--- a/extensions/renderer/api_bindings_system_unittest.h
+++ b/extensions/renderer/bindings/api_bindings_system_unittest.h
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_BINDINGS_SYSTEM_UNITTEST_H_
-#define EXTENSIONS_RENDERER_API_BINDINGS_SYSTEM_UNITTEST_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_BINDINGS_SYSTEM_UNITTEST_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_BINDINGS_SYSTEM_UNITTEST_H_
 
 #include <map>
 #include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/api_request_handler.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
 #include "v8/include/v8.h"
 
 namespace base {
@@ -101,4 +101,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_BINDINGS_SYSTEM_UNITTEST_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_BINDINGS_SYSTEM_UNITTEST_H_
diff --git a/extensions/renderer/api_event_handler.cc b/extensions/renderer/bindings/api_event_handler.cc
similarity index 98%
rename from extensions/renderer/api_event_handler.cc
rename to extensions/renderer/bindings/api_event_handler.cc
index 1057a17b..2b7a754 100644
--- a/extensions/renderer/api_event_handler.cc
+++ b/extensions/renderer/bindings/api_event_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_event_handler.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
 
 #include <algorithm>
 #include <map>
@@ -15,8 +15,8 @@
 #include "base/supports_user_data.h"
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
-#include "extensions/renderer/api_event_listeners.h"
-#include "extensions/renderer/event_emitter.h"
+#include "extensions/renderer/bindings/api_event_listeners.h"
+#include "extensions/renderer/bindings/event_emitter.h"
 #include "gin/handle.h"
 #include "gin/per_context_data.h"
 
diff --git a/extensions/renderer/api_event_handler.h b/extensions/renderer/bindings/api_event_handler.h
similarity index 93%
rename from extensions/renderer/api_event_handler.h
rename to extensions/renderer/bindings/api_event_handler.h
index 60a6be5..4dbd77c 100644
--- a/extensions/renderer/api_event_handler.h
+++ b/extensions/renderer/bindings/api_event_handler.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_EVENT_HANDLER_H_
-#define EXTENSIONS_RENDERER_API_EVENT_HANDLER_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_EVENT_HANDLER_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_EVENT_HANDLER_H_
 
 #include <string>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "extensions/common/event_filter.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/event_emitter.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/event_emitter.h"
 #include "v8/include/v8.h"
 
 namespace base {
@@ -109,4 +109,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_EVENT_HANDLER_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_EVENT_HANDLER_H_
diff --git a/extensions/renderer/api_event_handler_unittest.cc b/extensions/renderer/bindings/api_event_handler_unittest.cc
similarity index 99%
rename from extensions/renderer/api_event_handler_unittest.cc
rename to extensions/renderer/bindings/api_event_handler_unittest.cc
index b2ccef0..af76d703 100644
--- a/extensions/renderer/api_event_handler_unittest.cc
+++ b/extensions/renderer/bindings/api_event_handler_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_event_handler.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -11,8 +11,8 @@
 #include "base/test/mock_callback.h"
 #include "base/values.h"
 #include "extensions/common/event_filtering_info.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
 #include "gin/arguments.h"
 #include "gin/converter.h"
 #include "gin/public/context_holder.h"
diff --git a/extensions/renderer/api_event_listeners.cc b/extensions/renderer/bindings/api_event_listeners.cc
similarity index 98%
rename from extensions/renderer/api_event_listeners.cc
rename to extensions/renderer/bindings/api_event_listeners.cc
index 27f2ab39..140d8dd 100644
--- a/extensions/renderer/api_event_listeners.cc
+++ b/extensions/renderer/bindings/api_event_listeners.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_event_listeners.h"
+#include "extensions/renderer/bindings/api_event_listeners.h"
 
 #include <algorithm>
 #include <memory>
diff --git a/extensions/renderer/api_event_listeners.h b/extensions/renderer/bindings/api_event_listeners.h
similarity index 96%
rename from extensions/renderer/api_event_listeners.h
rename to extensions/renderer/bindings/api_event_listeners.h
index 564bcebf..7b4b9a52 100644
--- a/extensions/renderer/api_event_listeners.h
+++ b/extensions/renderer/bindings/api_event_listeners.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_EVENT_LISTENERS_H_
-#define EXTENSIONS_RENDERER_API_EVENT_LISTENERS_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_EVENT_LISTENERS_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_EVENT_LISTENERS_H_
 
 #include <string>
 #include <vector>
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "extensions/common/value_counter.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "v8/include/v8.h"
 
 namespace base {
@@ -166,4 +166,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_EVENT_LISTENERS_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_EVENT_LISTENERS_H_
diff --git a/extensions/renderer/api_event_listeners_unittest.cc b/extensions/renderer/bindings/api_event_listeners_unittest.cc
similarity index 98%
rename from extensions/renderer/api_event_listeners_unittest.cc
rename to extensions/renderer/bindings/api_event_listeners_unittest.cc
index 2e79c5f..4439728 100644
--- a/extensions/renderer/api_event_listeners_unittest.cc
+++ b/extensions/renderer/bindings/api_event_listeners_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_event_listeners.h"
+#include "extensions/renderer/bindings/api_event_listeners.h"
 
 #include "base/test/mock_callback.h"
 #include "base/values.h"
 #include "extensions/common/event_filter.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace extensions {
diff --git a/extensions/renderer/api_invocation_errors.cc b/extensions/renderer/bindings/api_invocation_errors.cc
similarity index 98%
rename from extensions/renderer/api_invocation_errors.cc
rename to extensions/renderer/bindings/api_invocation_errors.cc
index 2b255f4..a6cf7149 100644
--- a/extensions/renderer/api_invocation_errors.cc
+++ b/extensions/renderer/bindings/api_invocation_errors.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
 
 #include <vector>
 
diff --git a/extensions/renderer/api_invocation_errors.h b/extensions/renderer/bindings/api_invocation_errors.h
similarity index 92%
rename from extensions/renderer/api_invocation_errors.h
rename to extensions/renderer/bindings/api_invocation_errors.h
index 254c151..498866f 100644
--- a/extensions/renderer/api_invocation_errors.h
+++ b/extensions/renderer/bindings/api_invocation_errors.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_INVOCATION_ERRORS_H_
-#define EXTENSIONS_RENDERER_API_INVOCATION_ERRORS_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_INVOCATION_ERRORS_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_INVOCATION_ERRORS_H_
 
 #include <set>
 #include <string>
@@ -69,4 +69,4 @@
 }  // namespace api_errors
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_INVOCATION_ERRORS_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_INVOCATION_ERRORS_H_
diff --git a/extensions/renderer/api_invocation_errors_unittest.cc b/extensions/renderer/bindings/api_invocation_errors_unittest.cc
similarity index 96%
rename from extensions/renderer/api_invocation_errors_unittest.cc
rename to extensions/renderer/bindings/api_invocation_errors_unittest.cc
index 3fedb23..32be963 100644
--- a/extensions/renderer/api_invocation_errors_unittest.cc
+++ b/extensions/renderer/bindings/api_invocation_errors_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/extensions/renderer/api_last_error.cc b/extensions/renderer/bindings/api_last_error.cc
similarity index 99%
rename from extensions/renderer/api_last_error.cc
rename to extensions/renderer/bindings/api_last_error.cc
index fbf516b5..95c9cbdb 100644
--- a/extensions/renderer/api_last_error.cc
+++ b/extensions/renderer/bindings/api_last_error.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_last_error.h"
+#include "extensions/renderer/bindings/api_last_error.h"
 
 #include "gin/converter.h"
 #include "gin/handle.h"
diff --git a/extensions/renderer/api_last_error.h b/extensions/renderer/bindings/api_last_error.h
similarity index 90%
rename from extensions/renderer/api_last_error.h
rename to extensions/renderer/bindings/api_last_error.h
index 686adcc..f079458 100644
--- a/extensions/renderer/api_last_error.h
+++ b/extensions/renderer/bindings/api_last_error.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_LAST_ERROR_H_
-#define EXTENSIONS_RENDERER_API_LAST_ERROR_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_LAST_ERROR_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_LAST_ERROR_H_
 
 #include <string>
 
@@ -50,4 +50,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_LAST_ERROR_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_LAST_ERROR_H_
diff --git a/extensions/renderer/api_last_error_unittest.cc b/extensions/renderer/bindings/api_last_error_unittest.cc
similarity index 97%
rename from extensions/renderer/api_last_error_unittest.cc
rename to extensions/renderer/bindings/api_last_error_unittest.cc
index dbe8ff2c..09f42aa 100644
--- a/extensions/renderer/api_last_error_unittest.cc
+++ b/extensions/renderer/bindings/api_last_error_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_last_error.h"
+#include "extensions/renderer/bindings/api_last_error.h"
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/optional.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
 #include "gin/converter.h"
 #include "gin/public/context_holder.h"
 
diff --git a/extensions/renderer/api_request_handler.cc b/extensions/renderer/bindings/api_request_handler.cc
similarity index 98%
rename from extensions/renderer/api_request_handler.cc
rename to extensions/renderer/bindings/api_request_handler.cc
index bcc1c0e..e13c9e58 100644
--- a/extensions/renderer/api_request_handler.cc
+++ b/extensions/renderer/bindings/api_request_handler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_request_handler.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
 
 #include "base/bind.h"
 #include "base/guid.h"
diff --git a/extensions/renderer/api_request_handler.h b/extensions/renderer/bindings/api_request_handler.h
similarity index 93%
rename from extensions/renderer/api_request_handler.h
rename to extensions/renderer/bindings/api_request_handler.h
index 10ede68..c395aa7a 100644
--- a/extensions/renderer/api_request_handler.h
+++ b/extensions/renderer/bindings/api_request_handler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_REQUEST_HANDLER_H_
-#define EXTENSIONS_RENDERER_API_REQUEST_HANDLER_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_REQUEST_HANDLER_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_REQUEST_HANDLER_H_
 
 #include <map>
 #include <memory>
@@ -11,8 +11,8 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/api_last_error.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_last_error.h"
 #include "third_party/WebKit/public/web/WebUserGestureToken.h"
 #include "v8/include/v8.h"
 
@@ -126,4 +126,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_REQUEST_HANDLER_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_REQUEST_HANDLER_H_
diff --git a/extensions/renderer/api_request_handler_unittest.cc b/extensions/renderer/bindings/api_request_handler_unittest.cc
similarity index 98%
rename from extensions/renderer/api_request_handler_unittest.cc
rename to extensions/renderer/bindings/api_request_handler_unittest.cc
index e646a98..ffe963b 100644
--- a/extensions/renderer/api_request_handler_unittest.cc
+++ b/extensions/renderer/bindings/api_request_handler_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_request_handler.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/optional.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
 #include "gin/converter.h"
 #include "gin/function_template.h"
 #include "gin/public/context_holder.h"
diff --git a/extensions/renderer/api_signature.cc b/extensions/renderer/bindings/api_signature.cc
similarity index 98%
rename from extensions/renderer/api_signature.cc
rename to extensions/renderer/bindings/api_signature.cc
index c07705fb..5c2eb5f 100644
--- a/extensions/renderer/api_signature.cc
+++ b/extensions/renderer/bindings/api_signature.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_signature.h"
+#include "extensions/renderer/bindings/api_signature.h"
 
 #include <algorithm>
 
@@ -11,8 +11,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
-#include "extensions/renderer/api_invocation_errors.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/arguments.h"
 
 namespace extensions {
diff --git a/extensions/renderer/api_signature.h b/extensions/renderer/bindings/api_signature.h
similarity index 94%
rename from extensions/renderer/api_signature.h
rename to extensions/renderer/bindings/api_signature.h
index a8f3fa8..8eeee0e 100644
--- a/extensions/renderer/api_signature.h
+++ b/extensions/renderer/bindings/api_signature.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_SIGNATURE_H_
-#define EXTENSIONS_RENDERER_API_SIGNATURE_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_SIGNATURE_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_SIGNATURE_H_
 
 #include <memory>
 #include <string>
@@ -77,4 +77,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_SIGNATURE_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_SIGNATURE_H_
diff --git a/extensions/renderer/api_signature_unittest.cc b/extensions/renderer/bindings/api_signature_unittest.cc
similarity index 96%
rename from extensions/renderer/api_signature_unittest.cc
rename to extensions/renderer/bindings/api_signature_unittest.cc
index 34ac719..03b152e0 100644
--- a/extensions/renderer/api_signature_unittest.cc
+++ b/extensions/renderer/bindings/api_signature_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_signature.h"
+#include "extensions/renderer/bindings/api_signature.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_invocation_errors.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/argument_spec.h"
-#include "extensions/renderer/argument_spec_builder.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/argument_spec.h"
+#include "extensions/renderer/bindings/argument_spec_builder.h"
 #include "gin/converter.h"
 
 namespace extensions {
diff --git a/extensions/renderer/api_type_reference_map.cc b/extensions/renderer/bindings/api_type_reference_map.cc
similarity index 93%
rename from extensions/renderer/api_type_reference_map.cc
rename to extensions/renderer/bindings/api_type_reference_map.cc
index 33898c09..dfe5b064 100644
--- a/extensions/renderer/api_type_reference_map.cc
+++ b/extensions/renderer/bindings/api_type_reference_map.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/api_type_reference_map.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
 
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 
 namespace extensions {
 
diff --git a/extensions/renderer/api_type_reference_map.h b/extensions/renderer/bindings/api_type_reference_map.h
similarity index 93%
rename from extensions/renderer/api_type_reference_map.h
rename to extensions/renderer/bindings/api_type_reference_map.h
index 45a975a3..ddc1f68 100644
--- a/extensions/renderer/api_type_reference_map.h
+++ b/extensions/renderer/bindings/api_type_reference_map.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_API_TYPE_REFERENCE_MAP_H_
-#define EXTENSIONS_RENDERER_API_TYPE_REFERENCE_MAP_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_API_TYPE_REFERENCE_MAP_H_
+#define EXTENSIONS_RENDERER_BINDINGS_API_TYPE_REFERENCE_MAP_H_
 
 #include <map>
 #include <memory>
@@ -72,4 +72,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_API_TYPE_REFERENCE_MAP_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_API_TYPE_REFERENCE_MAP_H_
diff --git a/extensions/renderer/argument_spec.cc b/extensions/renderer/bindings/argument_spec.cc
similarity index 98%
rename from extensions/renderer/argument_spec.cc
rename to extensions/renderer/bindings/argument_spec.cc
index 1ecb1dad..cd105bf 100644
--- a/extensions/renderer/argument_spec.cc
+++ b/extensions/renderer/bindings/argument_spec.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_piece.h"
@@ -10,8 +10,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
-#include "extensions/renderer/api_invocation_errors.h"
-#include "extensions/renderer/api_type_reference_map.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
 #include "gin/converter.h"
 #include "gin/dictionary.h"
 
diff --git a/extensions/renderer/argument_spec.h b/extensions/renderer/bindings/argument_spec.h
similarity index 97%
rename from extensions/renderer/argument_spec.h
rename to extensions/renderer/bindings/argument_spec.h
index 0d51773..4425568 100644
--- a/extensions/renderer/argument_spec.h
+++ b/extensions/renderer/bindings/argument_spec.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_ARGUMENT_SPEC_H_
-#define EXTENSIONS_RENDERER_ARGUMENT_SPEC_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_ARGUMENT_SPEC_H_
+#define EXTENSIONS_RENDERER_BINDINGS_ARGUMENT_SPEC_H_
 
 #include <map>
 #include <memory>
@@ -179,4 +179,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_ARGUMENT_SPEC_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_ARGUMENT_SPEC_H_
diff --git a/extensions/renderer/argument_spec_builder.cc b/extensions/renderer/bindings/argument_spec_builder.cc
similarity index 96%
rename from extensions/renderer/argument_spec_builder.cc
rename to extensions/renderer/bindings/argument_spec_builder.cc
index 1805a0b..a9b3c98b 100644
--- a/extensions/renderer/argument_spec_builder.cc
+++ b/extensions/renderer/bindings/argument_spec_builder.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/argument_spec_builder.h"
+#include "extensions/renderer/bindings/argument_spec_builder.h"
 
 #include "base/memory/ptr_util.h"
 
diff --git a/extensions/renderer/argument_spec_builder.h b/extensions/renderer/bindings/argument_spec_builder.h
similarity index 86%
rename from extensions/renderer/argument_spec_builder.h
rename to extensions/renderer/bindings/argument_spec_builder.h
index 0f0b8760..e0737c95 100644
--- a/extensions/renderer/argument_spec_builder.h
+++ b/extensions/renderer/bindings/argument_spec_builder.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_ARGUMENT_SPEC_BUILDER_H_
-#define EXTENSIONS_RENDERER_ARGUMENT_SPEC_BUILDER_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_ARGUMENT_SPEC_BUILDER_H_
+#define EXTENSIONS_RENDERER_BINDINGS_ARGUMENT_SPEC_BUILDER_H_
 
 #include <memory>
 #include <set>
@@ -11,7 +11,7 @@
 
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 
 namespace extensions {
 
@@ -47,4 +47,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_ARGUMENT_SPEC_BUILDER_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_ARGUMENT_SPEC_BUILDER_H_
diff --git a/extensions/renderer/argument_spec_unittest.cc b/extensions/renderer/bindings/argument_spec_unittest.cc
similarity index 98%
rename from extensions/renderer/argument_spec_unittest.cc
rename to extensions/renderer/bindings/argument_spec_unittest.cc
index 60110a79..85a0a70 100644
--- a/extensions/renderer/argument_spec_unittest.cc
+++ b/extensions/renderer/bindings/argument_spec_unittest.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/argument_spec.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_invocation_errors.h"
-#include "extensions/renderer/api_type_reference_map.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/converter.h"
 #include "gin/public/isolate_holder.h"
 #include "gin/test/v8_test.h"
diff --git a/extensions/renderer/binding_access_checker.cc b/extensions/renderer/bindings/binding_access_checker.cc
similarity index 94%
rename from extensions/renderer/binding_access_checker.cc
rename to extensions/renderer/bindings/binding_access_checker.cc
index d7bb9ad..8f0fd55 100644
--- a/extensions/renderer/binding_access_checker.cc
+++ b/extensions/renderer/bindings/binding_access_checker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 
 #include "base/strings/stringprintf.h"
 #include "gin/converter.h"
diff --git a/extensions/renderer/binding_access_checker.h b/extensions/renderer/bindings/binding_access_checker.h
similarity index 86%
rename from extensions/renderer/binding_access_checker.h
rename to extensions/renderer/bindings/binding_access_checker.h
index b0122a8..7f9ccc25 100644
--- a/extensions/renderer/binding_access_checker.h
+++ b/extensions/renderer/bindings/binding_access_checker.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_BINDING_ACCESS_CHECKER_H_
-#define EXTENSIONS_RENDERER_BINDING_ACCESS_CHECKER_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_BINDING_ACCESS_CHECKER_H_
+#define EXTENSIONS_RENDERER_BINDINGS_BINDING_ACCESS_CHECKER_H_
 
 #include <string>
 
@@ -42,4 +42,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_BINDING_ACCESS_CHECKER_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_BINDING_ACCESS_CHECKER_H_
diff --git a/extensions/renderer/binding_access_checker_unittest.cc b/extensions/renderer/bindings/binding_access_checker_unittest.cc
similarity index 92%
rename from extensions/renderer/binding_access_checker_unittest.cc
rename to extensions/renderer/bindings/binding_access_checker_unittest.cc
index cba77bb..7b11538 100644
--- a/extensions/renderer/binding_access_checker_unittest.cc
+++ b/extensions/renderer/bindings/binding_access_checker_unittest.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 
 #include "base/bind.h"
-#include "extensions/renderer/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
 #include "gin/converter.h"
 
 namespace extensions {
diff --git a/extensions/renderer/declarative_event.cc b/extensions/renderer/bindings/declarative_event.cc
similarity index 95%
rename from extensions/renderer/declarative_event.cc
rename to extensions/renderer/bindings/declarative_event.cc
index 531b111..29e60ab 100644
--- a/extensions/renderer/declarative_event.cc
+++ b/extensions/renderer/bindings/declarative_event.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/declarative_event.h"
+#include "extensions/renderer/bindings/declarative_event.h"
 
 #include <algorithm>
 #include <memory>
@@ -10,11 +10,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "extensions/renderer/api_event_listeners.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/api_event_listeners.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/object_template_builder.h"
 #include "gin/per_context_data.h"
 
diff --git a/extensions/renderer/declarative_event.h b/extensions/renderer/bindings/declarative_event.h
similarity index 90%
rename from extensions/renderer/declarative_event.h
rename to extensions/renderer/bindings/declarative_event.h
index b0a7bcba..5566fa8 100644
--- a/extensions/renderer/declarative_event.h
+++ b/extensions/renderer/bindings/declarative_event.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_DECLARATIVE_EVENT_H_
-#define EXTENSIONS_RENDERER_DECLARATIVE_EVENT_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_DECLARATIVE_EVENT_H_
+#define EXTENSIONS_RENDERER_BINDINGS_DECLARATIVE_EVENT_H_
 
 #include <vector>
 
@@ -60,4 +60,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_DECLARATIVE_EVENT_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_DECLARATIVE_EVENT_H_
diff --git a/extensions/renderer/declarative_event_unittest.cc b/extensions/renderer/bindings/declarative_event_unittest.cc
similarity index 93%
rename from extensions/renderer/declarative_event_unittest.cc
rename to extensions/renderer/bindings/declarative_event_unittest.cc
index 60be826..4bb29d06 100644
--- a/extensions/renderer/declarative_event_unittest.cc
+++ b/extensions/renderer/bindings/declarative_event_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/declarative_event.h"
+#include "extensions/renderer/bindings/declarative_event.h"
 
 #include <memory>
 
@@ -11,14 +11,14 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "extensions/common/extension_api.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_bindings_system.h"
-#include "extensions/renderer/api_bindings_system_unittest.h"
-#include "extensions/renderer/api_last_error.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_bindings_system.h"
+#include "extensions/renderer/bindings/api_bindings_system_unittest.h"
+#include "extensions/renderer/bindings/api_last_error.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/handle.h"
 
 namespace extensions {
diff --git a/extensions/renderer/event_emitter.cc b/extensions/renderer/bindings/event_emitter.cc
similarity index 98%
rename from extensions/renderer/event_emitter.cc
rename to extensions/renderer/bindings/event_emitter.cc
index c4f8fef..4d9a391 100644
--- a/extensions/renderer/event_emitter.cc
+++ b/extensions/renderer/bindings/event_emitter.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/event_emitter.h"
+#include "extensions/renderer/bindings/event_emitter.h"
 
 #include <algorithm>
 
-#include "extensions/renderer/api_event_listeners.h"
+#include "extensions/renderer/bindings/api_event_listeners.h"
 #include "gin/data_object_builder.h"
 #include "gin/object_template_builder.h"
 #include "gin/per_context_data.h"
diff --git a/extensions/renderer/event_emitter.h b/extensions/renderer/bindings/event_emitter.h
similarity index 91%
rename from extensions/renderer/event_emitter.h
rename to extensions/renderer/bindings/event_emitter.h
index bcd8208f..9f9cbe5e 100644
--- a/extensions/renderer/event_emitter.h
+++ b/extensions/renderer/bindings/event_emitter.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef EXTENSIONS_RENDERER_EVENT_EMITTER_H_
-#define EXTENSIONS_RENDERER_EVENT_EMITTER_H_
+#ifndef EXTENSIONS_RENDERER_BINDINGS_EVENT_EMITTER_H_
+#define EXTENSIONS_RENDERER_BINDINGS_EVENT_EMITTER_H_
 
 #include <vector>
 
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "gin/wrappable.h"
 #include "v8/include/v8.h"
 
@@ -82,4 +82,4 @@
 
 }  // namespace extensions
 
-#endif  // EXTENSIONS_RENDERER_EVENT_EMITTER_H_
+#endif  // EXTENSIONS_RENDERER_BINDINGS_EVENT_EMITTER_H_
diff --git a/extensions/renderer/event_emitter_unittest.cc b/extensions/renderer/bindings/event_emitter_unittest.cc
similarity index 94%
rename from extensions/renderer/event_emitter_unittest.cc
rename to extensions/renderer/bindings/event_emitter_unittest.cc
index 53a12d9..4f0395d7 100644
--- a/extensions/renderer/event_emitter_unittest.cc
+++ b/extensions/renderer/bindings/event_emitter_unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "extensions/renderer/event_emitter.h"
+#include "extensions/renderer/bindings/event_emitter.h"
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_event_listeners.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_event_listeners.h"
 #include "gin/handle.h"
 
 namespace extensions {
diff --git a/extensions/renderer/chrome_setting.cc b/extensions/renderer/chrome_setting.cc
index 0f5b5f0d6..7d30cb27 100644
--- a/extensions/renderer/chrome_setting.cc
+++ b/extensions/renderer/chrome_setting.cc
@@ -7,11 +7,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "extensions/renderer/api_event_handler.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/api_event_handler.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 #include "gin/arguments.h"
 #include "gin/handle.h"
 #include "gin/object_template_builder.h"
diff --git a/extensions/renderer/chrome_setting.h b/extensions/renderer/chrome_setting.h
index 76724f1..411e4f1 100644
--- a/extensions/renderer/chrome_setting.h
+++ b/extensions/renderer/chrome_setting.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/wrappable.h"
 #include "v8/include/v8.h"
 
diff --git a/extensions/renderer/content_setting.cc b/extensions/renderer/content_setting.cc
index 51495cd..0f998267 100644
--- a/extensions/renderer/content_setting.cc
+++ b/extensions/renderer/content_setting.cc
@@ -8,10 +8,10 @@
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "content/public/common/console_message_level.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 #include "extensions/renderer/console.h"
 #include "extensions/renderer/script_context_set.h"
 #include "gin/arguments.h"
diff --git a/extensions/renderer/content_setting.h b/extensions/renderer/content_setting.h
index ac3619ca..4998fe2 100644
--- a/extensions/renderer/content_setting.h
+++ b/extensions/renderer/content_setting.h
@@ -8,8 +8,8 @@
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/wrappable.h"
 #include "v8/include/v8.h"
 
diff --git a/extensions/renderer/declarative_content_hooks_delegate.cc b/extensions/renderer/declarative_content_hooks_delegate.cc
index 6c68ff2..b1ce10f4 100644
--- a/extensions/renderer/declarative_content_hooks_delegate.cc
+++ b/extensions/renderer/declarative_content_hooks_delegate.cc
@@ -7,8 +7,8 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "extensions/common/api/declarative/declarative_constants.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/argument_spec.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/argument_spec.h"
 #include "gin/arguments.h"
 #include "gin/converter.h"
 #include "third_party/WebKit/public/platform/WebString.h"
diff --git a/extensions/renderer/declarative_content_hooks_delegate.h b/extensions/renderer/declarative_content_hooks_delegate.h
index 8fd200c6..9479a6a8 100644
--- a/extensions/renderer/declarative_content_hooks_delegate.h
+++ b/extensions/renderer/declarative_content_hooks_delegate.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_hooks_delegate.h"
+#include "extensions/renderer/bindings/api_binding_hooks_delegate.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 9431880..94d10aa 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -13,9 +13,9 @@
 #include "extensions/common/extension_api.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/features/feature_provider.h"
-#include "extensions/renderer/api_binding_bridge.h"
-#include "extensions/renderer/api_binding_hooks.h"
-#include "extensions/renderer/api_binding_js_util.h"
+#include "extensions/renderer/bindings/api_binding_bridge.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_js_util.h"
 #include "extensions/renderer/chrome_setting.h"
 #include "extensions/renderer/console.h"
 #include "extensions/renderer/content_setting.h"
diff --git a/extensions/renderer/native_extension_bindings_system.h b/extensions/renderer/native_extension_bindings_system.h
index 48634b7..a606ba7 100644
--- a/extensions/renderer/native_extension_bindings_system.h
+++ b/extensions/renderer/native_extension_bindings_system.h
@@ -10,9 +10,9 @@
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
-#include "extensions/renderer/api_binding_types.h"
-#include "extensions/renderer/api_bindings_system.h"
-#include "extensions/renderer/event_emitter.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
+#include "extensions/renderer/bindings/api_bindings_system.h"
+#include "extensions/renderer/bindings/event_emitter.h"
 #include "extensions/renderer/extension_bindings_system.h"
 #include "v8/include/v8.h"
 
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index 698beb96..85dbc1a 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -14,9 +14,9 @@
 #include "extensions/common/manifest.h"
 #include "extensions/common/permissions/permissions_data.h"
 #include "extensions/common/value_builder.h"
-#include "extensions/renderer/api_binding_test.h"
-#include "extensions/renderer/api_binding_test_util.h"
-#include "extensions/renderer/api_invocation_errors.h"
+#include "extensions/renderer/bindings/api_binding_test.h"
+#include "extensions/renderer/bindings/api_binding_test_util.h"
+#include "extensions/renderer/bindings/api_invocation_errors.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/safe_builtins.h"
 #include "extensions/renderer/script_context.h"
diff --git a/extensions/renderer/storage_area.cc b/extensions/renderer/storage_area.cc
index bf684b8..8e72702 100644
--- a/extensions/renderer/storage_area.cc
+++ b/extensions/renderer/storage_area.cc
@@ -7,10 +7,10 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "extensions/common/api/storage.h"
-#include "extensions/renderer/api_request_handler.h"
-#include "extensions/renderer/api_signature.h"
-#include "extensions/renderer/api_type_reference_map.h"
-#include "extensions/renderer/binding_access_checker.h"
+#include "extensions/renderer/bindings/api_request_handler.h"
+#include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/bindings/api_type_reference_map.h"
+#include "extensions/renderer/bindings/binding_access_checker.h"
 #include "gin/arguments.h"
 #include "gin/handle.h"
 #include "gin/object_template_builder.h"
diff --git a/extensions/renderer/web_request_hooks.cc b/extensions/renderer/web_request_hooks.cc
index 0f833278..ef04d13 100644
--- a/extensions/renderer/web_request_hooks.cc
+++ b/extensions/renderer/web_request_hooks.cc
@@ -7,7 +7,7 @@
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
 #include "extensions/common/extension_api.h"
-#include "extensions/renderer/api_binding_hooks.h"
+#include "extensions/renderer/bindings/api_binding_hooks.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/script_context_set.h"
diff --git a/extensions/renderer/web_request_hooks.h b/extensions/renderer/web_request_hooks.h
index 1ab17175..bf947eb9 100644
--- a/extensions/renderer/web_request_hooks.h
+++ b/extensions/renderer/web_request_hooks.h
@@ -8,8 +8,8 @@
 #include <string>
 
 #include "base/macros.h"
-#include "extensions/renderer/api_binding_hooks_delegate.h"
-#include "extensions/renderer/api_binding_types.h"
+#include "extensions/renderer/bindings/api_binding_hooks_delegate.h"
+#include "extensions/renderer/bindings/api_binding_types.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.cc b/extensions/shell/browser/shell_desktop_controller_aura.cc
index 5f9c7cd..794a0ce 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.cc
+++ b/extensions/shell/browser/shell_desktop_controller_aura.cc
@@ -134,10 +134,10 @@
     }
   }
 
-  void SetCursorSet(ui::CursorSetType cursor_set,
-                    wm::NativeCursorManagerDelegate* delegate) override {
-    image_cursors_->SetCursorSet(cursor_set);
-    delegate->CommitCursorSet(cursor_set);
+  void SetCursorSize(ui::CursorSize cursor_size,
+                     wm::NativeCursorManagerDelegate* delegate) override {
+    image_cursors_->SetCursorSize(cursor_size);
+    delegate->CommitCursorSize(cursor_size);
     if (delegate->IsCursorVisible())
       SetCursor(delegate->GetCursor(), delegate);
   }
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index 7938ed2..1b82549 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -448,7 +448,7 @@
       timer_->Start(
           FROM_HERE,
           base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs) - time_elapsed,
-          this, &GpuChannelMessageQueue::UpdatePreemptionState);
+          base::Bind(&GpuChannelMessageQueue::UpdatePreemptionState, this));
     } else {
       timer_->Stop();
       if (!scheduled_)
@@ -530,9 +530,9 @@
 
   preemption_state_ = WAITING;
 
-  timer_->Start(FROM_HERE,
-                base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs), this,
-                &GpuChannelMessageQueue::UpdatePreemptionState);
+  timer_->Start(
+      FROM_HERE, base::TimeDelta::FromMilliseconds(kPreemptWaitTimeMs),
+      base::Bind(&GpuChannelMessageQueue::UpdatePreemptionState, this));
 }
 
 void GpuChannelMessageQueue::TransitionToChecking() {
@@ -561,8 +561,9 @@
 
   DCHECK_LE(max_preemption_time_,
             base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs));
-  timer_->Start(FROM_HERE, max_preemption_time_, this,
-                &GpuChannelMessageQueue::UpdatePreemptionState);
+  timer_->Start(
+      FROM_HERE, max_preemption_time_,
+      base::Bind(&GpuChannelMessageQueue::UpdatePreemptionState, this));
 }
 
 void GpuChannelMessageQueue::TransitionToWouldPreemptDescheduled() {
diff --git a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
index 8449dd95..58e87b3 100644
--- a/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
+++ b/ios/chrome/browser/ntp_tiles/ios_popular_sites_factory.cc
@@ -7,25 +7,20 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
-#include "base/path_service.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "components/ntp_tiles/json_unsafe_parser.h"
 #include "components/ntp_tiles/popular_sites_impl.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/chrome_paths.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/web/public/web_thread.h"
 
 std::unique_ptr<ntp_tiles::PopularSites>
 IOSPopularSitesFactory::NewForBrowserState(
     ios::ChromeBrowserState* browser_state) {
-  base::FilePath popular_sites_path;
-  base::PathService::Get(ios::DIR_USER_DATA, &popular_sites_path);
   return base::MakeUnique<ntp_tiles::PopularSitesImpl>(
-      web::WebThread::GetBlockingPool(), browser_state->GetPrefs(),
+      browser_state->GetPrefs(),
       ios::TemplateURLServiceFactory::GetForBrowserState(browser_state),
       GetApplicationContext()->GetVariationsService(),
-      browser_state->GetRequestContext(), popular_sites_path,
+      browser_state->GetRequestContext(),
       base::Bind(ntp_tiles::JsonUnsafeParser::Parse));
 }
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index a676ae0..436344e 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -277,7 +277,7 @@
         try {
             mFlushed = true;
             mMediaCodec.flush();
-        } catch (IllegalStateException e) {
+        } catch (Exception e) {
             Log.e(TAG, "Failed to flush MediaCodec", e);
             return MediaCodecStatus.ERROR;
         }
diff --git a/media/mojo/clients/mojo_video_decoder.cc b/media/mojo/clients/mojo_video_decoder.cc
index ff22797..37135b8a 100644
--- a/media/mojo/clients/mojo_video_decoder.cc
+++ b/media/mojo/clients/mojo_video_decoder.cc
@@ -110,10 +110,16 @@
 
 void MojoVideoDecoder::OnVideoFrameDecoded(
     const scoped_refptr<VideoFrame>& frame,
+    bool can_read_without_stalling,
     const base::Optional<base::UnguessableToken>& release_token) {
   DVLOG(2) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
+  // TODO(sandersd): Prove that all paths read this value again after running
+  // |output_cb_|. In practice this isn't very important, since all decoders
+  // running via MojoVideoDecoder currently use a static value.
+  can_read_without_stalling_ = can_read_without_stalling;
+
   if (release_token) {
     frame->SetReleaseMailboxCB(
         BindToCurrentLoop(base::Bind(&MojoVideoDecoder::OnReleaseMailbox,
@@ -172,7 +178,7 @@
 
 bool MojoVideoDecoder::CanReadWithoutStalling() const {
   DVLOG(3) << __func__;
-  return true;
+  return can_read_without_stalling_;
 }
 
 int MojoVideoDecoder::GetMaxDecodeRequests() const {
diff --git a/media/mojo/clients/mojo_video_decoder.h b/media/mojo/clients/mojo_video_decoder.h
index ebd96b33..1f2f9f8 100644
--- a/media/mojo/clients/mojo_video_decoder.h
+++ b/media/mojo/clients/mojo_video_decoder.h
@@ -50,6 +50,7 @@
   // mojom::VideoDecoderClient implementation.
   void OnVideoFrameDecoded(
       const scoped_refptr<VideoFrame>& frame,
+      bool can_read_without_stalling,
       const base::Optional<base::UnguessableToken>& release_token) final;
 
  private:
@@ -90,6 +91,7 @@
 
   bool initialized_ = false;
   bool needs_bitstream_conversion_ = false;
+  bool can_read_without_stalling_ = true;
   int32_t max_decode_requests_ = 1;
 
   base::WeakPtr<MojoVideoDecoder> weak_this_;
diff --git a/media/mojo/interfaces/video_decoder.mojom b/media/mojo/interfaces/video_decoder.mojom
index cade79c..36ae91f 100644
--- a/media/mojo/interfaces/video_decoder.mojom
+++ b/media/mojo/interfaces/video_decoder.mojom
@@ -75,9 +75,16 @@
 };
 
 interface VideoDecoderClient {
-  // Output a decoded frame. Frames must be output in presentation order. If
-  // |release_token| is provided, the client should call OnReleaseMailbox() when
-  // it is finished with the frame.
+  // Output a decoded frame. Frames must be output in presentation order.
+  //
+  // When |can_read_without_stalling| is false, preroll is disabled. This is
+  // necessary if the decoder cannot guarantee that it can output another frame,
+  // for example if output buffers are limited or configuration changes require
+  // the return of all outstanding frames.
+  //
+  // If |release_token| is provided, the client shall call OnReleaseMailbox()
+  // when it is finished using the frame.
   OnVideoFrameDecoded(VideoFrame frame,
+                      bool can_read_without_stalling,
                       mojo.common.mojom.UnguessableToken? release_token);
 };
diff --git a/media/mojo/services/mojo_video_decoder_service.cc b/media/mojo/services/mojo_video_decoder_service.cc
index a6154ec..2c4885c 100644
--- a/media/mojo/services/mojo_video_decoder_service.cc
+++ b/media/mojo/services/mojo_video_decoder_service.cc
@@ -36,9 +36,10 @@
     mojom::CommandBufferIdPtr command_buffer_id) {
   DVLOG(1) << __func__;
 
-  // TODO(sandersd): Close the channel.
-  if (decoder_)
+  if (decoder_) {
+    // TODO(sandersd): Close the channel.
     return;
+  }
 
   decoder_ = mojo_media_client_->CreateVideoDecoder(
       base::ThreadTaskRunnerHandle::Get(), std::move(command_buffer_id),
@@ -106,8 +107,8 @@
 void MojoVideoDecoderService::OnDecoderRead(
     const DecodeCallback& callback,
     scoped_refptr<DecoderBuffer> buffer) {
-  // TODO(sandersd): Close the channel.
   if (!buffer) {
+    // TODO(sandersd): Close the channel.
     callback.Run(DecodeStatus::DECODE_ERROR);
     return;
   }
@@ -120,8 +121,6 @@
 void MojoVideoDecoderService::OnDecoderDecoded(const DecodeCallback& callback,
                                                DecodeStatus status) {
   DVLOG(2) << __func__;
-  DCHECK(decoder_);
-  DCHECK(decoder_->CanReadWithoutStalling());
   callback.Run(status);
 }
 
@@ -135,6 +134,7 @@
     const scoped_refptr<VideoFrame>& frame) {
   DVLOG(2) << __func__;
   DCHECK(client_);
+  DCHECK(decoder_);
 
   base::Optional<base::UnguessableToken> release_token;
   if (release_cb) {
@@ -142,7 +142,8 @@
     release_mailbox_cbs_[*release_token] = std::move(release_cb);
   }
 
-  client_->OnVideoFrameDecoded(frame, std::move(release_token));
+  client_->OnVideoFrameDecoded(frame, decoder_->CanReadWithoutStalling(),
+                               std::move(release_token));
 }
 
 void MojoVideoDecoderService::OnReleaseMailbox(
diff --git a/net/dns/host_cache.cc b/net/dns/host_cache.cc
index 19a2192..ce95a31 100644
--- a/net/dns/host_cache.cc
+++ b/net/dns/host_cache.cc
@@ -248,6 +248,13 @@
   ++network_changes_;
 }
 
+void HostCache::set_persistence_delegate(PersistenceDelegate* delegate) {
+  // A PersistenceDelegate shouldn't be added if there already was one, and
+  // shouldn't be removed (by setting to nullptr) if it wasn't previously there.
+  DCHECK_NE(delegate == nullptr, delegate_ == nullptr);
+  delegate_ = delegate;
+}
+
 void HostCache::clear() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   RecordEraseAll(ERASE_CLEAR, base::TimeTicks::Now());
@@ -288,9 +295,10 @@
     delegate_->ScheduleWrite();
 }
 
-std::unique_ptr<base::ListValue> HostCache::GetAsListValue(
-    bool include_staleness) const {
-  std::unique_ptr<base::ListValue> entry_list(new base::ListValue());
+void HostCache::GetAsListValue(base::ListValue* entry_list,
+                               bool include_staleness) const {
+  DCHECK(entry_list);
+  entry_list->Clear();
 
   for (const auto& pair : entries_) {
     const Key& key = pair.first;
@@ -332,8 +340,6 @@
 
     entry_list->Append(std::move(entry_dict));
   }
-
-  return entry_list;
 }
 
 // TODO(mgersh): Add histograms to track failures.
diff --git a/net/dns/host_cache.h b/net/dns/host_cache.h
index 13042e3..0045b37 100644
--- a/net/dns/host_cache.h
+++ b/net/dns/host_cache.h
@@ -167,9 +167,7 @@
     eviction_callback_ = callback;
   }
 
-  void set_persistence_delegate(PersistenceDelegate* delegate) {
-    delegate_ = delegate;
-  }
+  void set_persistence_delegate(PersistenceDelegate* delegate);
 
   // Empties the cache.
   void clear();
@@ -178,9 +176,11 @@
   void ClearForHosts(
       const base::Callback<bool(const std::string&)>& host_filter);
 
-  // Returns the contents of the cache represented as a base::ListValue for
-  // serialization.
-  std::unique_ptr<base::ListValue> GetAsListValue(bool include_staleness) const;
+  // Fills the provided base::ListValue with the contents of the cache for
+  // serialization. |entry_list| must be non-null and will be cleared before
+  // adding the cache contents.
+  void GetAsListValue(base::ListValue* entry_list,
+                      bool include_staleness) const;
   // Takes a base::ListValue representing cache entries and stores them in the
   // cache, skipping any that already have entries. Returns true on success,
   // false on failure.
diff --git a/net/dns/host_cache_unittest.cc b/net/dns/host_cache_unittest.cc
index 66c0faa..f1ac984 100644
--- a/net/dns/host_cache_unittest.cc
+++ b/net/dns/host_cache_unittest.cc
@@ -704,8 +704,8 @@
   // Advance to t=12, ansd serialize the cache.
   now += base::TimeDelta::FromSeconds(7);
 
-  std::unique_ptr<base::ListValue> serialized_cache =
-      cache.GetAsListValue(/*include_staleness=*/false);
+  base::ListValue serialized_cache;
+  cache.GetAsListValue(&serialized_cache, /*include_staleness=*/false);
   HostCache restored_cache(kMaxCacheEntries);
 
   // Add entries for "foobar3.com" and "foobar4.com" to the cache before
@@ -720,7 +720,7 @@
   EXPECT_TRUE(restored_cache.Lookup(key4, now));
   EXPECT_EQ(2u, restored_cache.size());
 
-  restored_cache.RestoreFromListValue(*serialized_cache);
+  restored_cache.RestoreFromListValue(serialized_cache);
 
   HostCache::EntryStaleness stale;
 
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 9575055..ad295243 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -64,7 +64,7 @@
 // Experiment to preconnect only one connection if HttpServerProperties is
 // not supported or initialized.
 const base::Feature kLimitEarlyPreconnectsExperiment{
-    "LimitEarlyPreconnects", base::FEATURE_DISABLED_BY_DEFAULT};
+    "LimitEarlyPreconnects", base::FEATURE_ENABLED_BY_DEFAULT};
 void DoNothingAsyncCallback(int result) {}
 void RecordChannelIDKeyMatch(SSLClientSocket* ssl_socket,
                              ChannelIDService* channel_id_service,
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc
index 9758db52b..42b823e 100644
--- a/net/http/http_stream_factory_impl_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc
@@ -2004,9 +2004,9 @@
       public ::testing::WithParamInterface<bool> {
  protected:
   void SetUp() override {
-    if (GetParam()) {
-      scoped_feature_list_.InitFromCommandLine("LimitEarlyPreconnects",
-                                               std::string());
+    if (!GetParam()) {
+      scoped_feature_list_.InitFromCommandLine(std::string(),
+                                               "LimitEarlyPreconnects");
     }
   }
 
diff --git a/net/log/net_log_util.cc b/net/log/net_log_util.cc
index 8cda4082..5d6dcd1e 100644
--- a/net/log/net_log_util.cc
+++ b/net/log/net_log_util.cc
@@ -383,13 +383,16 @@
         dict->Set("dns_config", std::move(dns_config));
 
       auto cache_info_dict = base::MakeUnique<base::DictionaryValue>();
+      auto cache_contents_list = base::MakeUnique<base::ListValue>();
 
       cache_info_dict->SetInteger("capacity",
                                   static_cast<int>(cache->max_entries()));
       cache_info_dict->SetInteger("network_changes", cache->network_changes());
 
-      cache_info_dict->Set("entries",
-                           cache->GetAsListValue(/*include_staleness=*/true));
+      cache->GetAsListValue(cache_contents_list.get(),
+                            /*include_staleness=*/true);
+      cache_info_dict->Set("entries", std::move(cache_contents_list));
+
       dict->Set("cache", std::move(cache_info_dict));
       net_info_dict->Set(NetInfoSourceToString(NET_INFO_HOST_RESOLVER),
                          std::move(dict));
diff --git a/remoting/android/client_java_tmpl.gni b/remoting/android/client_java_tmpl.gni
index 705ce45..4a99d7c 100644
--- a/remoting/android/client_java_tmpl.gni
+++ b/remoting/android/client_java_tmpl.gni
@@ -84,7 +84,7 @@
       "//third_party/android_tools:android_support_core_ui_java",
       "//third_party/android_tools:android_support_v7_appcompat_java",
       "//third_party/android_tools:android_support_v7_mediarouter_java",
-      "//ui/android:ui_java",
+      "//ui/android:ui_utils_java",
     ]
 
     deps += [ invoker.remoting_google_play_services_library ]
diff --git a/services/ui/public/interfaces/cursor/cursor.mojom b/services/ui/public/interfaces/cursor/cursor.mojom
index c228539a..a4f5806 100644
--- a/services/ui/public/interfaces/cursor/cursor.mojom
+++ b/services/ui/public/interfaces/cursor/cursor.mojom
@@ -60,6 +60,13 @@
   kCustom
 };
 
+// Whether we use normal or large cursors. These are the same as Chrome's
+// ui::CursorSize.
+enum CursorSize {
+  kNormal,
+  kLarge
+};
+
 // A description of a cursor.
 struct CursorData {
   // The type of cursor. If CUSTOM, the rest of the fields are relevant.
diff --git a/services/ui/public/interfaces/cursor/cursor.typemap b/services/ui/public/interfaces/cursor/cursor.typemap
index e82b51d..c4d6181 100644
--- a/services/ui/public/interfaces/cursor/cursor.typemap
+++ b/services/ui/public/interfaces/cursor/cursor.typemap
@@ -3,7 +3,10 @@
 # found in the LICENSE file.
 
 mojom = "//services/ui/public/interfaces/cursor/cursor.mojom"
-public_headers = [ "//ui/base/cursor/cursor_data.h" ]
+public_headers = [
+  "//ui/base/cursor/cursor_type.h",
+  "//ui/base/cursor/cursor_data.h",
+]
 traits_headers =
     [ "//services/ui/public/interfaces/cursor/cursor_struct_traits.h" ]
 sources = [
@@ -16,4 +19,8 @@
   "//ui/gfx/geometry",
 ]
 
-type_mappings = [ "ui.mojom.CursorData=ui::CursorData[copyable_pass_by_value]" ]
+type_mappings = [
+  "ui.mojom.CursorType=ui::CursorType",
+  "ui.mojom.CursorSize=ui::CursorSize",
+  "ui.mojom.CursorData=ui::CursorData[copyable_pass_by_value]",
+]
diff --git a/services/ui/public/interfaces/cursor/cursor_struct_traits.cc b/services/ui/public/interfaces/cursor/cursor_struct_traits.cc
index 63c6e6a4..dc13478 100644
--- a/services/ui/public/interfaces/cursor/cursor_struct_traits.cc
+++ b/services/ui/public/interfaces/cursor/cursor_struct_traits.cc
@@ -9,7 +9,6 @@
 #include "services/ui/public/interfaces/cursor/cursor.mojom.h"
 #include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/cursor/cursor.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 
 namespace mojo {
@@ -269,6 +268,38 @@
 }
 
 // static
+ui::mojom::CursorSize
+EnumTraits<ui::mojom::CursorSize, ui::CursorSize>::ToMojom(
+    ui::CursorSize input) {
+  switch (input) {
+    case ui::CursorSize::kNormal:
+      return ui::mojom::CursorSize::kNormal;
+    case ui::CursorSize::kLarge:
+      return ui::mojom::CursorSize::kLarge;
+  }
+
+  NOTREACHED();
+  return ui::mojom::CursorSize::kNormal;
+}
+
+// static
+bool EnumTraits<ui::mojom::CursorSize, ui::CursorSize>::FromMojom(
+    ui::mojom::CursorSize input,
+    ui::CursorSize* out) {
+  switch (input) {
+    case ui::mojom::CursorSize::kNormal:
+      *out = ui::CursorSize::kNormal;
+      return true;
+    case ui::mojom::CursorSize::kLarge:
+      *out = ui::CursorSize::kLarge;
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+// static
 const base::TimeDelta&
 StructTraits<ui::mojom::CursorDataDataView, ui::CursorData>::frame_delay(
     const ui::CursorData& c) {
diff --git a/services/ui/public/interfaces/cursor/cursor_struct_traits.h b/services/ui/public/interfaces/cursor/cursor_struct_traits.h
index e7e8fa2..8c29aa3 100644
--- a/services/ui/public/interfaces/cursor/cursor_struct_traits.h
+++ b/services/ui/public/interfaces/cursor/cursor_struct_traits.h
@@ -7,6 +7,7 @@
 
 #include "services/ui/public/interfaces/cursor/cursor.mojom-shared.h"
 #include "ui/base/cursor/cursor_data.h"
+#include "ui/base/cursor/cursor_type.h"
 
 namespace mojo {
 
@@ -17,6 +18,12 @@
 };
 
 template <>
+struct EnumTraits<ui::mojom::CursorSize, ui::CursorSize> {
+  static ui::mojom::CursorSize ToMojom(ui::CursorSize input);
+  static bool FromMojom(ui::mojom::CursorSize input, ui::CursorSize* out);
+};
+
+template <>
 struct StructTraits<ui::mojom::CursorDataDataView, ui::CursorData> {
   static ui::CursorType cursor_type(const ui::CursorData& c) {
     return c.cursor_type();
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom
index 09a909f..f6c6e216 100644
--- a/services/ui/public/interfaces/window_manager.mojom
+++ b/services/ui/public/interfaces/window_manager.mojom
@@ -323,6 +323,9 @@
   // Shows and hides the cursor globally. Used during window management tasks.
   WmSetCursorVisible(bool visible);
 
+  // Sets whether we're using normal or large cursors.
+  WmSetCursorSize(CursorSize cursor_size);
+
   // Sets a global cursor which overrides per-window cursors. Pass null to
   // clear.
   WmSetGlobalOverrideCursor(CursorData? cursor);
diff --git a/services/ui/ws/cursor_state.cc b/services/ui/ws/cursor_state.cc
index 7e17d13..c73687a6 100644
--- a/services/ui/ws/cursor_state.cc
+++ b/services/ui/ws/cursor_state.cc
@@ -14,10 +14,9 @@
 
 class CursorState::StateSnapshot {
  public:
-  StateSnapshot()
-      : cursor_data_(ui::CursorData(ui::CursorType::kNull)), visible_(true) {}
+  StateSnapshot() = default;
   StateSnapshot(const StateSnapshot& rhs) = default;
-  ~StateSnapshot() {}
+  ~StateSnapshot() = default;
 
   const base::Optional<ui::CursorData>& global_override_cursor() const {
     return global_override_cursor_;
@@ -32,16 +31,24 @@
   bool visible() const { return visible_; }
   void set_visible(bool visible) { visible_ = visible; }
 
+  ui::CursorSize cursor_size() const { return cursor_size_; }
+  void set_cursor_size(ui::CursorSize cursor_size) {
+    cursor_size_ = cursor_size;
+  }
+
  private:
   // An optional cursor set by the window manager which overrides per-window
   // requests.
   base::Optional<ui::CursorData> global_override_cursor_;
 
   // The last cursor set. Used to track whether we need to change the cursor.
-  ui::CursorData cursor_data_;
+  ui::CursorData cursor_data_ = ui::CursorData(ui::CursorType::kNull);
+
+  // Which cursor set to use.
+  ui::CursorSize cursor_size_ = CursorSize::kNormal;
 
   // Whether the cursor is visible.
-  bool visible_;
+  bool visible_ = true;
 };
 
 CursorState::CursorState(DisplayManager* display_manager)
@@ -73,6 +80,7 @@
     return;
 
   *current_state_ = *state_on_unlock_;
+  SetPlatformCursorSize();
   SetPlatformCursor();
 }
 
@@ -94,6 +102,22 @@
   }
 }
 
+void CursorState::SetCursorSize(ui::CursorSize cursor_size) {
+  state_on_unlock_->set_cursor_size(cursor_size);
+  if (cursor_lock_count_ == 0 &&
+      current_state_->cursor_size() != state_on_unlock_->cursor_size()) {
+    current_state_->set_cursor_size(cursor_size);
+    SetPlatformCursorSize();
+    SetPlatformCursor();
+  }
+}
+
+void CursorState::SetPlatformCursorSize() {
+  DisplayManager* manager = display_manager_;
+  for (Display* display : manager->displays())
+    display->SetNativeCursorSize(current_state_->cursor_size());
+}
+
 void CursorState::SetPlatformCursor() {
   DisplayManager* manager = display_manager_;
   auto set_on_all = [manager](const ui::CursorData& cursor) {
diff --git a/services/ui/ws/cursor_state.h b/services/ui/ws/cursor_state.h
index b6af262..7fd12c4 100644
--- a/services/ui/ws/cursor_state.h
+++ b/services/ui/ws/cursor_state.h
@@ -11,6 +11,9 @@
 #include "ui/base/cursor/cursor_data.h"
 
 namespace ui {
+
+enum class CursorSize;
+
 namespace ws {
 
 class DisplayManager;
@@ -36,11 +39,17 @@
   // Sets a cursor globally, which overrides the per-window cursors.
   void SetGlobalOverrideCursor(const base::Optional<ui::CursorData>& cursor);
 
+  // Sets the cursor size.
+  void SetCursorSize(ui::CursorSize cursor_size);
+
  private:
   // A snapshot of the cursor state at a specific time.
   class StateSnapshot;
 
-  // Synchronizes |current_state_| with all the platform displays.
+  // Synchronizes cursor set data with all platform displays.
+  void SetPlatformCursorSize();
+
+  // Synchronizes the current cursor state with all the platform displays.
   void SetPlatformCursor();
 
   // Contains are the displays we notify on cursor changes.
diff --git a/services/ui/ws/display.cc b/services/ui/ws/display.cc
index a355f19..00bf5ad9 100644
--- a/services/ui/ws/display.cc
+++ b/services/ui/ws/display.cc
@@ -202,6 +202,10 @@
   platform_display_->SetCursor(cursor);
 }
 
+void Display::SetNativeCursorSize(ui::CursorSize cursor_size) {
+  platform_display_->SetCursorSize(cursor_size);
+}
+
 void Display::SetSize(const gfx::Size& size) {
   platform_display_->SetViewportSize(size);
 }
diff --git a/services/ui/ws/display.h b/services/ui/ws/display.h
index 27e212c..9cd3a75c 100644
--- a/services/ui/ws/display.h
+++ b/services/ui/ws/display.h
@@ -152,6 +152,9 @@
   // Sets the native cursor to |cursor|.
   void SetNativeCursor(const ui::CursorData& curosor);
 
+  // Sets the native cursor size to |cursor_size|.
+  void SetNativeCursorSize(ui::CursorSize cursor_size);
+
   // mojom::WindowTreeHost:
   void SetSize(const gfx::Size& size) override;
   void SetTitle(const std::string& title) override;
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h
index a33f638..fb567d73 100644
--- a/services/ui/ws/platform_display.h
+++ b/services/ui/ws/platform_display.h
@@ -18,6 +18,7 @@
 
 namespace ui {
 
+enum class CursorSize;
 struct TextInputState;
 
 namespace ws {
@@ -50,6 +51,8 @@
 
   virtual void MoveCursorTo(const gfx::Point& window_pixel_location) = 0;
 
+  virtual void SetCursorSize(const ui::CursorSize& cursor_size) = 0;
+
   virtual void UpdateTextInputState(const ui::TextInputState& state) = 0;
   virtual void SetImeVisibility(bool visible) = 0;
 
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc
index a807396a..f26e1d0 100644
--- a/services/ui/ws/platform_display_default.cc
+++ b/services/ui/ws/platform_display_default.cc
@@ -144,6 +144,10 @@
   platform_window_->MoveCursorTo(window_pixel_location);
 }
 
+void PlatformDisplayDefault::SetCursorSize(const ui::CursorSize& cursor_size) {
+  image_cursors_->SetCursorSize(cursor_size);
+}
+
 void PlatformDisplayDefault::UpdateTextInputState(
     const ui::TextInputState& state) {
   ui::PlatformImeController* ime = platform_window_->GetPlatformImeController();
diff --git a/services/ui/ws/platform_display_default.h b/services/ui/ws/platform_display_default.h
index 5f942b1..fe00e6b3 100644
--- a/services/ui/ws/platform_display_default.h
+++ b/services/ui/ws/platform_display_default.h
@@ -45,6 +45,7 @@
   void ReleaseCapture() override;
   void SetCursor(const ui::CursorData& cursor) override;
   void MoveCursorTo(const gfx::Point& window_pixel_location) override;
+  void SetCursorSize(const ui::CursorSize& cursor_size) override;
   void UpdateTextInputState(const ui::TextInputState& state) override;
   void SetImeVisibility(bool visible) override;
   void UpdateViewportMetrics(const display::ViewportMetrics& metrics) override;
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc
index 50400536..0a96497 100644
--- a/services/ui/ws/test_utils.cc
+++ b/services/ui/ws/test_utils.cc
@@ -48,6 +48,7 @@
   void SetCursor(const ui::CursorData& cursor) override {
     *cursor_storage_ = cursor;
   }
+  void SetCursorSize(const ui::CursorSize& cursor_size) override {}
   void MoveCursorTo(const gfx::Point& window_pixel_location) override {}
   void UpdateTextInputState(const ui::TextInputState& state) override {}
   void SetImeVisibility(bool visible) override {}
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index ee3cbc1..e57adb8f 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -2356,6 +2356,11 @@
   window_manager_state_->cursor_state().SetCursorVisible(visible);
 }
 
+void WindowTree::WmSetCursorSize(ui::CursorSize cursor_size) {
+  DCHECK(window_manager_state_);
+  window_manager_state_->cursor_state().SetCursorSize(cursor_size);
+}
+
 void WindowTree::WmSetGlobalOverrideCursor(
     base::Optional<ui::CursorData> cursor) {
   DCHECK(window_manager_state_);
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h
index 3bbcd09b..3aef1350 100644
--- a/services/ui/ws/window_tree.h
+++ b/services/ui/ws/window_tree.h
@@ -537,6 +537,7 @@
   void WmLockCursor() override;
   void WmUnlockCursor() override;
   void WmSetCursorVisible(bool visible) override;
+  void WmSetCursorSize(ui::CursorSize cursor_size) override;
   void WmSetGlobalOverrideCursor(
       base::Optional<ui::CursorData> cursor) override;
   void WmMoveCursorToDisplayLocation(const gfx::Point& display_pixels,
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter
index bf9fe67..e698354c 100644
--- a/testing/buildbot/filters/ash_unittests_mash.filter
+++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -2,7 +2,7 @@
 -NativeCursorManagerAshTest.FractionalScale
 -NativeCursorManagerAshTest.LockCursor
 -NativeCursorManagerAshTest.SetCursor
--NativeCursorManagerAshTest.SetCursorSet
+-NativeCursorManagerAshTest.SetCursorSize
 -NativeCursorManagerAshTest.SetDeviceScaleFactorAndRotation
 -NativeCursorManagerAshTest.UIScaleShouldNotChangeCursor
 -CursorWindowControllerTest.DSF
diff --git a/testing/buildbot/filters/ash_unittests_mus.filter b/testing/buildbot/filters/ash_unittests_mus.filter
index d26416b..ab6e24f 100644
--- a/testing/buildbot/filters/ash_unittests_mus.filter
+++ b/testing/buildbot/filters/ash_unittests_mus.filter
@@ -2,13 +2,10 @@
 # http://crbug.com/734806.
 # The following fail as they use wm::CursorManager:
 -NativeCursorManagerAshTest.LockCursor
--NativeCursorManagerAshTest.SetCursorSet
 -ExtendedDesktopTest.TestCursor
 -LockStateControllerTest.LegacyLockAndShutDown
 -LockStateControllerTest.RequestShutdownFromLockScreen
 -LockStateControllerTest.RequestShutdownFromLoginScreen
--WindowManagerTest.TestCursorClientObserver
--WindowSelectorTest.Basic
 
 # TODO: fix these. They fail because ShellPortMash::IsMouseEventsEnabled() isn't
 # implemented. http://crbug.com/734808.
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 4132ffe..feab373e 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -622,6 +622,18 @@
             ]
         }
     ],
+    "DataReductionProxyPreviewsBlacklistTransition": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled"
+                }
+            ]
+        }
+    ],
     "DataReductionProxyServerExperiments": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index a85b9499..5c93a62 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -4289,7 +4289,7 @@
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-non-replaced-width-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-replaced-width-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/blocks-025.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/height-114.xht [ Crash Failure ]
+crbug.com/591099 external/wpt/css/CSS2/normal-flow/height-114.xht [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-block-non-replaced-height-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-block-valign-001.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-block-valign-002.xht [ Failure ]
@@ -4371,6 +4371,35 @@
 crbug.com/591099 external/wpt/css/CSS2/positioning/top-103.xht [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/positioning/top-104.xht [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/positioning/top-113.xht [ Crash Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-align-white-space-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-align-white-space-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-007.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-008.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-009.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-010.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-011.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-014.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-015.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-indent-012.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-indent-intrinsic-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-indent-intrinsic-003.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-indent-intrinsic-004.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-indent-percent-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/text-transform-capitalize-003.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-003.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-004.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-align-3/distribution-values/space-evenly-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-flex-002-inline.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-list-001-inline.html [ Failure ]
@@ -5224,7 +5253,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-horiz-002.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-horiz-004.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-vert-002.xhtml [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-vert-003.xhtml [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-vert-003.xhtml [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-vert-004.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-margin-auto-horiz-001.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-margin-auto-horiz-002.xhtml [ Failure ]
@@ -5257,6 +5286,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-006a.html [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-007.html [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/cssom-view/HTMLBody-ScrollArea_quirksmode.html [ Failure Pass ]
+crbug.com/591099 external/wpt/cssom-view/cssom-getClientRects-002.html [ Failure ]
 crbug.com/591099 external/wpt/cssom-view/elementFromPoint.html [ Crash ]
 crbug.com/591099 external/wpt/cssom-view/elementsFromPoint.html [ Crash ]
 crbug.com/591099 external/wpt/cssom-view/scrolling-quirks-vs-nonquirks.html [ Crash ]
@@ -5344,11 +5374,13 @@
 crbug.com/591099 external/wpt/editing/run/superscript.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/underline.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/encoding/api-invalid-label.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-decode-extra.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ]
 crbug.com/591099 external/wpt/eventsource/eventsource-onmessage-realm.htm [ Crash ]
 crbug.com/591099 external/wpt/fetch/api/request/multi-globals/url-parsing.html [ Crash ]
 crbug.com/591099 external/wpt/fetch/api/response/multi-globals/url-parsing.html [ Crash ]
 crbug.com/591099 external/wpt/fetch/security/dangling-markup-mitigation.tentative.html [ Crash ]
+crbug.com/591099 external/wpt/fetch/security/embedded-credentials.tentative.sub.html [ Crash ]
 crbug.com/591099 external/wpt/fullscreen/api/element-request-fullscreen-and-remove-iframe-manual.html [ Crash ]
 crbug.com/591099 external/wpt/fullscreen/model/move-to-iframe-manual.html [ Crash ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Crash Failure ]
@@ -5456,8 +5488,14 @@
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-embed-element/embed-ignored-in-media-element.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-embed-element/embed-in-object-fallback.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/change_parentage.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/content_document_changes_only_after_load_matures.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation-2.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_ancestor-1.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_ancestor-2.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_descendants.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_navigate_itself.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-iframe-element/same_origin_parentage.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/error.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-img-element/delay-load-event.html [ Crash ]
@@ -5488,6 +5526,7 @@
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-action-submission-with-base-url.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-action-submission.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-autocomplete.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-elements-filter.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-elements-matches.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-elements-nameditem-01.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/forms/the-form-element/form-elements-sameobject.html [ Crash ]
@@ -5555,6 +5594,7 @@
 crbug.com/591099 external/wpt/html/semantics/selectors/pseudo-classes/indeterminate-radio.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/selectors/pseudo-classes/readwrite-readonly.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/selectors/pseudo-classes/valid-invalid.html [ Crash ]
+crbug.com/591099 external/wpt/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html [ Crash ]
 crbug.com/591099 external/wpt/html/semantics/text-level-semantics/the-bdi-element/bdi-neutral-wrapped.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/semantics/text-level-semantics/the-br-element/br-bidi-in-inline-ancestors.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/text-level-semantics/the-wbr-element/wbr-element.html [ Failure ]
@@ -6384,6 +6424,7 @@
 crbug.com/591099 external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html [ Crash ]
 crbug.com/591099 external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html [ Crash ]
 crbug.com/591099 external/wpt/service-workers/service-worker/activation.https.html [ Crash ]
+crbug.com/591099 external/wpt/service-workers/service-worker/claim-fetch.https.html [ Crash ]
 crbug.com/591099 external/wpt/service-workers/service-worker/claim-not-using-registration.https.html [ Crash ]
 crbug.com/591099 external/wpt/service-workers/service-worker/client-id.https.html [ Crash ]
 crbug.com/591099 external/wpt/service-workers/service-worker/clients-get-cross-origin.https.html [ Crash ]
@@ -14719,6 +14760,7 @@
 crbug.com/591099 http/tests/images/image-with-dpr-natural-dimensions.html [ Crash ]
 crbug.com/591099 http/tests/images/image-with-origin-header.html [ Failure ]
 crbug.com/591099 http/tests/images/png-partial-load-as-document.html [ Failure Pass ]
+crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure Pass ]
 crbug.com/591099 http/tests/incremental/doc-write-before-end.pl [ Crash Pass ]
 crbug.com/591099 http/tests/incremental/frame-focus-before-load.html [ Failure Timeout ]
 crbug.com/591099 http/tests/incremental/slow-utf8-css.html [ Failure ]
@@ -16185,7 +16227,7 @@
 crbug.com/591099 http/tests/xmlhttprequest/simple-cross-origin-progress-events.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/state-after-network-error.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/status-after-abort.html [ Failure ]
-crbug.com/591099 http/tests/xmlhttprequest/supported-xml-content-types-invalid-1.html [ Failure ]
+crbug.com/591099 http/tests/xmlhttprequest/supported-xml-content-types-invalid-1.html [ Failure Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/supported-xml-content-types-invalid-2.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/supported-xml-content-types-strange-valid-1.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/supported-xml-content-types-strange-valid-2.html [ Failure ]
@@ -16475,8 +16517,8 @@
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-buttons.js [ Crash Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-img-figure.js [ Crash Failure Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js [ Crash Timeout ]
-crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input.js [ Crash Timeout ]
-crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Crash Timeout ]
+crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input.js [ Crash Failure Timeout ]
+crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Crash Failure Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-visiblity.js [ Crash Timeout ]
 crbug.com/591099 inspector-protocol/css/css-add-rule.html [ Timeout ]
 crbug.com/591099 inspector-protocol/css/css-coverage-poll.html [ Failure ]
@@ -18638,7 +18680,7 @@
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
 crbug.com/591099 scrollbars/basic-scrollbar.html [ Failure ]
 crbug.com/591099 scrollbars/border-box-rect-clips-scrollbars.html [ Failure ]
-crbug.com/591099 scrollbars/custom-scrollbar-changing-style-relayout-body-scrollablearea.html [ Crash Pass ]
+crbug.com/591099 scrollbars/custom-scrollbar-changing-style-relayout-body-scrollablearea.html [ Crash Pass Timeout ]
 crbug.com/591099 scrollbars/custom-scrollbar-changing-style-relayout-div-body-scrollablearea.html [ Crash Pass ]
 crbug.com/591099 scrollbars/custom-scrollbar-enable-changes-thickness-with-iframe.html [ Failure Pass ]
 crbug.com/591099 scrollbars/custom-scrollbar-not-inherited-by-iframe.html [ Crash ]
@@ -22155,7 +22197,7 @@
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-inline-003r.xht [ Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/linebox/empty-inline-002.xht [ Crash Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-replaced-width-006.xht [ Failure ]
-crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/height-114.xht [ Crash Failure ]
+crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/height-114.xht [ Crash Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-019.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-020.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/positioning/top-031.xht [ Crash Failure ]
@@ -22249,6 +22291,7 @@
 crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html [ Crash ]
 crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html [ Crash ]
 crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/activation.https.html [ Crash ]
+crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/claim-fetch.https.html [ Crash ]
 crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/claim-not-using-registration.https.html [ Crash ]
 crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/client-id.https.html [ Crash ]
 crbug.com/591099 virtual/off-main-thread-fetch/external/wpt/service-workers/service-worker/clients-get-cross-origin.https.html [ Crash ]
@@ -23291,3 +23334,7 @@
 crbug.com/591099 webmidi/send-messages.html [ Failure ]
 crbug.com/591099 webmidi/send-system-messages.html [ Failure ]
 crbug.com/591099 xmlviewer/extensions-api.html [ Failure ]
+crbug.com/591099 css3/flexbox/bug527039.html [ Failure ]
+crbug.com/591099 fast/html/draggable-controls.html [ Failure ]
+crbug.com/591099 hittesting/culled-inline-crash.html [ Failure ]
+crbug.com/591099 svg/as-list-image/svg-list-image-intrinsic-size-zoom.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
index 682d0cb1..3544d15 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -3339,6 +3339,7 @@
 Bug(none) webaudio/dom-exceptions.html [ Timeout ]
 Bug(none) webaudio/internals/audiocontext-close.html [ Timeout ]
 Bug(none) webaudio/internals/audiocontext-lock-threading-race.html [ Timeout ]
+Bug(none) webaudio/internals/audiosource-premature-gc.html [ Timeout ]
 Bug(none) webaudio/internals/audiosummingjunction-crash.html [ Timeout ]
 Bug(none) webaudio/internals/mediaelementaudiosourcenode-wrapper.html [ Timeout ]
 Bug(none) webaudio/test-basic.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations
index c748989..7e789f00 100644
--- a/third_party/WebKit/LayoutTests/MSANExpectations
+++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -22,6 +22,7 @@
 crbug.com/522315 [ Linux ] virtual/gpu/fast/canvas/quadraticCurveTo.xml [ Crash ]
 
 crbug.com/517704 [ Linux ] external/wpt/encoding/api-invalid-label.html [ Timeout Pass ]
+crbug.com/708175 [ Linux ] external/wpt/IndexedDB/interleaved-cursors.html [ Timeout ]
 
 crbug.com/701433 [ Linux ] crypto/subtle/worker-subtle-crypto-concurrent.html [ Timeout Pass ]
 crbug.com/701563 [ Linux ] external/wpt/svg/interfaces.html [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 9a0eac91..03afb62 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -379,7 +379,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-131.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-132.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-137.xht [ Skip ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-138.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-141.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-144.xht [ Failure ]
@@ -437,7 +436,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/block-replaced-width-006.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/blocks-017.xht [ Failure ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/blocks-025.xht [ Failure ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/height-114.xht [ Failure Crash ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-002.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-003.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/normal-flow/inline-block-004.xht [ Skip ]
@@ -2877,9 +2875,6 @@
 
 crbug.com/729836 [ Win ] fast/workers/worker-document-leak.html [ Pass Failure ]
 
-# Sheriff failures 2017-06-07
-crbug.com/727014 [ Linux ] external/wpt/IndexedDB/large-nested-cloning.html [ Pass Timeout ]
-
 # Sensor tests fail on Mac swarming
 crbug.com/731018 [ Mac ] sensor/accelerometer.html [ Failure Pass Crash ]
 crbug.com/731018 [ Mac ] sensor/ambient-light-sensor.html [ Failure Pass Crash ]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
deleted file mode 100644
index c955f024..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/large-nested-cloning.html
+++ /dev/null
@@ -1,288 +0,0 @@
-<!doctype html>
-<meta charset="utf8">
-<meta name="timeout" content="long">
-<title>IndexedDB: large nested objects are cloned correctly</title>
-<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
-<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="support-promises.js"></script>
-<script>
-'use strict';
-
-// Should be large enough to trigger large value handling in the IndexedDB
-// engines that have special code paths for large values.
-const wrapThreshold = 128 * 1024;
-
-// Returns an IndexedDB value created from a descriptor.
-//
-// See the bottom of the file for descriptor samples.
-function createValue(descriptor) {
-  if (typeof(descriptor) != 'object')
-    return descriptor;
-
-  if (Array.isArray(descriptor))
-    return descriptor.map((element) => createValue(element));
-
-  if (!descriptor.hasOwnProperty('type')) {
-    const value = {};
-    for (let property of Object.getOwnPropertyNames(descriptor))
-      value[property] = createValue(descriptor[property]);
-    return value;
-  }
-
-  switch (descriptor.type) {
-    case 'blob':
-      return new Blob(
-          [largeValue(descriptor.size, descriptor.seed)],
-          { type: descriptor.mimeType });
-    case 'buffer':
-      return largeValue(descriptor.size, descriptor.seed);
-  }
-}
-
-// Checks an IndexedDB value against a descriptor.
-//
-// Returns a Promise that resolves if the value passes the check.
-//
-// See the bottom of the file for descriptor samples.
-function checkValue(testCase, value, descriptor) {
-  if (typeof(descriptor) != 'object') {
-    assert_equals(
-        descriptor, value,
-        'IndexedDB result should match put() argument');
-    return Promise.resolve();
-  }
-
-  if (Array.isArray(descriptor)) {
-    assert_true(
-        Array.isArray(value),
-        'IndexedDB result type should match put() argument');
-    assert_equals(
-        descriptor.length, value.length,
-        'IndexedDB result array size should match put() argument');
-
-    const subChecks = [];
-    for (let i = 0; i < descriptor.length; ++i)
-      subChecks.push(checkValue(testCase, value[i], descriptor[i]));
-    return Promise.all(subChecks);
-  }
-
-  if (!descriptor.hasOwnProperty('type')) {
-    assert_array_equals(
-        Object.getOwnPropertyNames(value).sort(),
-        Object.getOwnPropertyNames(descriptor).sort(),
-        'IndexedDB result object properties should match put() argument');
-    const subChecks = [];
-    return Promise.all(Object.getOwnPropertyNames(descriptor).map(property =>
-        checkValue(testCase, value[property], descriptor[property])));
-  }
-
-  switch (descriptor.type) {
-    case 'blob':
-      assert_class_string(
-          value, 'Blob',
-          'IndexedDB result class should match put() argument');
-      assert_equals(
-          descriptor.mimeType, value.type,
-          'IndexedDB result Blob MIME type should match put() argument');
-      assert_equals(descriptor.size, value.size, 'incorrect Blob size');
-      return new Promise((resolve, reject) => {
-        const reader = new FileReader();
-        reader.onloadend = testCase.step_func(() => {
-          if (reader.error) {
-            reject(reader.error);
-            return;
-          }
-          const view = new Uint8Array(reader.result);
-          assert_equals(
-              view.join(','),
-              largeValue(descriptor.size, descriptor.seed).join(','),
-              'IndexedDB result Blob content should match put() argument');
-          resolve();
-        });
-        reader.readAsArrayBuffer(value);
-      });
-
-    case 'buffer':
-      assert_class_string(
-          value, 'Uint8Array',
-          'IndexedDB result type should match put() argument');
-      assert_equals(
-          value.join(','),
-          largeValue(descriptor.size, descriptor.seed).join(','),
-          'IndexedDB result typed array content should match put() argument');
-      return Promise.resolve();
-  }
-}
-
-// Performs a series of put()s and verifies that get()s and getAll() match.
-//
-// Each element of the valueDescriptors array is fed into createValue(), and the
-// resulting value is written to IndexedDB via a put() request. After the writes
-// complete, the values are read in the same order in which they were written.
-// Last, all the results are read one more time via a getAll().
-//
-// The test verifies that the get() / getAll() results match the arguments to
-// put() and that the order in which the get() result events are fired matches
-// the order of the get() requests.
-function cloningTest(label, valueDescriptors) {
-  promise_test(testCase => {
-    return createDatabase(testCase, (database, transaction) => {
-      const store = database.createObjectStore('test-store');
-      for (let i = 0; i < valueDescriptors.length; ++i) {
-        store.put(createValue(valueDescriptors[i]), i);
-      }
-    }).then(database => {
-      const transaction = database.transaction(['test-store'], 'readonly');
-      const store = transaction.objectStore('test-store');
-      const subChecks = [];
-      let resultIndex = 0;
-      for (let i = 0; i < valueDescriptors.length; ++i) {
-        subChecks.push(new Promise((resolve, reject) => {
-          const requestIndex = i;
-          const request = store.get(requestIndex);
-          request.onerror =
-              testCase.step_func(() => { reject(request.error); });
-          request.onsuccess = testCase.step_func(() => {
-            assert_equals(
-                resultIndex, requestIndex,
-                'IDBRequest success events should be fired in request order');
-            ++resultIndex;
-            resolve(checkValue(
-                testCase, request.result, valueDescriptors[requestIndex]));
-          });
-        }));
-      }
-
-      subChecks.push(new Promise((resolve, reject) => {
-        const requestIndex = valueDescriptors.length;
-        const request = store.getAll();
-        request.onerror =
-            testCase.step_func(() => { reject(request.error); });
-        request.onsuccess = testCase.step_func(() => {
-          assert_equals(
-              resultIndex, requestIndex,
-              'IDBRequest success events should be fired in request order');
-          ++resultIndex;
-          resolve(checkValue(
-              testCase, request.result, valueDescriptors));
-        });
-      }));
-
-      return Promise.all(subChecks);
-    });
-  }, label);
-}
-
-cloningTest('small typed array', [
-  { type: 'buffer', size: 64, seed: 1 },
-]);
-
-cloningTest('large typed array', [
-  { type: 'buffer', size: wrapThreshold, seed: 1 },
-])
-
-cloningTest('blob', [
-  { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-1', seed: 1 },
-]);
-
-cloningTest('blob with small typed array', [
-  {
-    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01',
-            seed: 1 },
-    buffer: { type: 'buffer', size: 64, seed: 2 },
-  },
-]);
-
-cloningTest('blob with large typed array', [
-  {
-    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01',
-            seed: 1 },
-    buffer: { type: 'buffer', size: wrapThreshold, seed: 2 },
-  },
-]);
-
-cloningTest('blob array', [
-  [
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-1', seed: 1 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-2', seed: 2 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-3', seed: 3 },
-  ],
-]);
-
-cloningTest('array of blobs and small typed arrays', [
-  [
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01', seed: 1 },
-    { type: 'buffer', size: 64, seed: 2 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-03', seed: 3 },
-    { type: 'buffer', size: 64, seed: 4 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-05', seed: 5 },
-  ],
-]);
-
-cloningTest('array of blobs and large typed arrays', [
-  [
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01', seed: 1 },
-    { type: 'buffer', size: wrapThreshold, seed: 2 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-03', seed: 3 },
-    { type: 'buffer', size: wrapThreshold, seed: 4 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-05', seed: 5 },
-  ],
-]);
-
-cloningTest('object with blobs and large typed arrays', [
-  {
-    blob: { type: 'blob', size: wrapThreshold,
-            mimeType: 'text/x-blink1', seed: 1 },
-    more: [
-      { type: 'buffer', size: wrapThreshold, seed: 2 },
-      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink3', seed: 3 },
-      { type: 'buffer', size: wrapThreshold, seed: 4 },
-    ],
-    blob2: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink5',
-             seed: 5 },
-  },
-]);
-
-cloningTest('multiple requests of objects with blobs and large typed arrays', [
-  {
-    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink1',
-            seed: 1 },
-    more: [
-      { type: 'buffer', size: wrapThreshold, seed: 2 },
-      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink3', seed: 3 },
-      { type: 'buffer', size: wrapThreshold, seed: 4 },
-    ],
-    blob2: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink5',
-             seed: 5 },
-  },
-  [
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink06', seed: 6 },
-    { type: 'buffer', size: wrapThreshold, seed: 7 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink08', seed: 8 },
-    { type: 'buffer', size: wrapThreshold, seed: 9 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink10', seed: 10 },
-  ],
-  {
-    data: [
-      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-11',
-        seed: 11 },
-      { type: 'buffer', size: wrapThreshold, seed: 12 },
-      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-13',
-        seed: 13 },
-      { type: 'buffer', size: wrapThreshold, seed: 14 },
-      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-15',
-        seed: 15 },
-    ],
-  },
-  [
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink16', seed: 16 },
-    { type: 'buffer', size: wrapThreshold, seed: 17 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink18', seed: 18 },
-    { type: 'buffer', size: wrapThreshold, seed: 19 },
-    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink20', seed: 20 },
-  ],
-]);
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-common.js b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-common.js
new file mode 100644
index 0000000..db5f710c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-common.js
@@ -0,0 +1,211 @@
+'use strict';
+
+// Should be large enough to trigger large value handling in the IndexedDB
+// engines that have special code paths for large values.
+const wrapThreshold = 128 * 1024;
+
+// Returns an IndexedDB value created from a descriptor.
+//
+// See the bottom of the file for descriptor samples.
+function createValue(descriptor) {
+  if (typeof(descriptor) != 'object')
+    return descriptor;
+
+  if (Array.isArray(descriptor))
+    return descriptor.map((element) => createValue(element));
+
+  if (!descriptor.hasOwnProperty('type')) {
+    const value = {};
+    for (let property of Object.getOwnPropertyNames(descriptor))
+      value[property] = createValue(descriptor[property]);
+    return value;
+  }
+
+  switch (descriptor.type) {
+    case 'blob':
+      return new Blob(
+          [largeValue(descriptor.size, descriptor.seed)],
+          { type: descriptor.mimeType });
+    case 'buffer':
+      return largeValue(descriptor.size, descriptor.seed);
+  }
+}
+
+// Checks an IndexedDB value against a descriptor.
+//
+// Returns a Promise that resolves if the value passes the check.
+//
+// See the bottom of the file for descriptor samples.
+function checkValue(testCase, value, descriptor) {
+  if (typeof(descriptor) != 'object') {
+    assert_equals(
+        descriptor, value,
+        'IndexedDB result should match put() argument');
+    return Promise.resolve();
+  }
+
+  if (Array.isArray(descriptor)) {
+    assert_true(
+        Array.isArray(value),
+        'IndexedDB result type should match put() argument');
+    assert_equals(
+        descriptor.length, value.length,
+        'IndexedDB result array size should match put() argument');
+
+    const subChecks = [];
+    for (let i = 0; i < descriptor.length; ++i)
+      subChecks.push(checkValue(testCase, value[i], descriptor[i]));
+    return Promise.all(subChecks);
+  }
+
+  if (!descriptor.hasOwnProperty('type')) {
+    assert_array_equals(
+        Object.getOwnPropertyNames(value).sort(),
+        Object.getOwnPropertyNames(descriptor).sort(),
+        'IndexedDB result object properties should match put() argument');
+    const subChecks = [];
+    return Promise.all(Object.getOwnPropertyNames(descriptor).map(property =>
+        checkValue(testCase, value[property], descriptor[property])));
+  }
+
+  switch (descriptor.type) {
+    case 'blob':
+      assert_class_string(
+          value, 'Blob',
+          'IndexedDB result class should match put() argument');
+      assert_equals(
+          descriptor.mimeType, value.type,
+          'IndexedDB result Blob MIME type should match put() argument');
+      assert_equals(descriptor.size, value.size, 'incorrect Blob size');
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.onloadend = testCase.step_func(() => {
+          if (reader.error) {
+            reject(reader.error);
+            return;
+          }
+          const view = new Uint8Array(reader.result);
+          assert_equals(
+              view.join(','),
+              largeValue(descriptor.size, descriptor.seed).join(','),
+              'IndexedDB result Blob content should match put() argument');
+          resolve();
+        });
+        reader.readAsArrayBuffer(value);
+      });
+
+    case 'buffer':
+      assert_class_string(
+          value, 'Uint8Array',
+          'IndexedDB result type should match put() argument');
+      assert_equals(
+          value.join(','),
+          largeValue(descriptor.size, descriptor.seed).join(','),
+          'IndexedDB result typed array content should match put() argument');
+      return Promise.resolve();
+  }
+}
+
+function cloningTestInternal(label, valueDescriptors, options) {
+  promise_test(testCase => {
+    return createDatabase(testCase, (database, transaction) => {
+      let store;
+      if (options.useKeyGenerator) {
+        store = database.createObjectStore(
+            'test-store', { keyPath: 'primaryKey', autoIncrement: true });
+      } else {
+        store = database.createObjectStore('test-store');
+      }
+      for (let i = 0; i < valueDescriptors.length; ++i) {
+        if (options.useKeyGenerator) {
+          store.put(createValue(valueDescriptors[i]));
+        } else {
+          store.put(createValue(valueDescriptors[i]), i + 1);
+        }
+      }
+    }).then(database => {
+      const transaction = database.transaction(['test-store'], 'readonly');
+      const store = transaction.objectStore('test-store');
+      const subChecks = [];
+      let resultIndex = 0;
+      for (let i = 0; i < valueDescriptors.length; ++i) {
+        subChecks.push(new Promise((resolve, reject) => {
+          const requestIndex = i;
+          const primaryKey = requestIndex + 1;
+          const request = store.get(primaryKey);
+          request.onerror =
+              testCase.step_func(() => { reject(request.error); });
+          request.onsuccess = testCase.step_func(() => {
+            assert_equals(
+                resultIndex, requestIndex,
+                'IDBRequest success events should be fired in request order');
+            ++resultIndex;
+
+            const result = request.result;
+            if (options.useKeyGenerator) {
+              assert_equals(
+                  result.primaryKey, primaryKey,
+                  'IndexedDB result should have auto-incremented primary key');
+              delete result.primaryKey;
+            }
+            resolve(checkValue(
+                testCase, result, valueDescriptors[requestIndex]));
+          });
+        }));
+      }
+
+      subChecks.push(new Promise((resolve, reject) => {
+        const requestIndex = valueDescriptors.length;
+        const request = store.getAll();
+        request.onerror =
+            testCase.step_func(() => { reject(request.error); });
+        request.onsuccess = testCase.step_func(() => {
+          assert_equals(
+              resultIndex, requestIndex,
+              'IDBRequest success events should be fired in request order');
+          ++resultIndex;
+          const result = request.result;
+          if (options.useKeyGenerator) {
+            for (let i = 0; i < valueDescriptors.length; ++i) {
+              const primaryKey = i + 1;
+              assert_equals(
+                  result[i].primaryKey, primaryKey,
+                  'IndexedDB result should have auto-incremented primary key');
+              delete result[i].primaryKey;
+            }
+          }
+          resolve(checkValue(testCase, result, valueDescriptors));
+        });
+      }));
+
+      return Promise.all(subChecks);
+    });
+  }, label);
+}
+
+// Performs a series of put()s and verifies that get()s and getAll() match.
+//
+// Each element of the valueDescriptors array is fed into createValue(), and the
+// resulting value is written to IndexedDB via a put() request. After the writes
+// complete, the values are read in the same order in which they were written.
+// Last, all the results are read one more time via a getAll().
+//
+// The test verifies that the get() / getAll() results match the arguments to
+// put() and that the order in which the get() result events are fired matches
+// the order of the get() requests.
+function cloningTest(label, valueDescriptors) {
+  cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
+}
+
+// cloningTest, with coverage for key generators.
+//
+// This creates two tests. One test performs a series of put()s and verifies
+// that get()s and getAll() match, exactly like cloningTestWithoutKeyGenerator.
+// The other test performs the same put()s in an object store with a key
+// generator, and checks that the key generator works properly.
+function cloningTestWithKeyGenerator(label, valueDescriptors) {
+  cloningTestInternal(label, valueDescriptors, { useKeyGenerator: false });
+  cloningTestInternal(
+      label + " with key generator", valueDescriptors,
+      { useKeyGenerator: true });
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-large-multiple.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-large-multiple.html
new file mode 100644
index 0000000..f263efbc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-large-multiple.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<meta charset="utf8">
+<meta name="timeout" content="long">
+<title>IndexedDB: large nested objects are cloned correctly</title>
+<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="nested-cloning-common.js"></script>
+<script>
+
+cloningTestWithKeyGenerator(
+    'multiple requests of objects with blobs and large typed arrays', [
+  {
+    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink1',
+            seed: 1 },
+    more: [
+      { type: 'buffer', size: wrapThreshold, seed: 2 },
+      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink3', seed: 3 },
+      { type: 'buffer', size: wrapThreshold, seed: 4 },
+    ],
+    blob2: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink5',
+             seed: 5 },
+  },
+  [
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink06', seed: 6 },
+    { type: 'buffer', size: wrapThreshold, seed: 7 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink08', seed: 8 },
+    { type: 'buffer', size: wrapThreshold, seed: 9 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink10', seed: 10 },
+  ],
+  {
+    data: [
+      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-11',
+        seed: 11 },
+      { type: 'buffer', size: wrapThreshold, seed: 12 },
+      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-13',
+        seed: 13 },
+      { type: 'buffer', size: wrapThreshold, seed: 14 },
+      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-15',
+        seed: 15 },
+    ],
+  },
+  [
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink16', seed: 16 },
+    { type: 'buffer', size: wrapThreshold, seed: 17 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink18', seed: 18 },
+    { type: 'buffer', size: wrapThreshold, seed: 19 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink20', seed: 20 },
+  ],
+]);
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-large.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-large.html
new file mode 100644
index 0000000..6e4f9be
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-large.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<meta charset="utf8">
+<meta name="timeout" content="long">
+<title>IndexedDB: large nested objects are cloned correctly</title>
+<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="nested-cloning-common.js"></script>
+<script>
+
+cloningTest('large typed array', [
+  { type: 'buffer', size: wrapThreshold, seed: 1 },
+])
+
+cloningTestWithKeyGenerator('blob with large typed array', [
+  {
+    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01',
+            seed: 1 },
+    buffer: { type: 'buffer', size: wrapThreshold, seed: 2 },
+  },
+]);
+
+cloningTestWithKeyGenerator('array of blobs and large typed arrays', [
+  [
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01', seed: 1 },
+    { type: 'buffer', size: wrapThreshold, seed: 2 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-03', seed: 3 },
+    { type: 'buffer', size: wrapThreshold, seed: 4 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-05', seed: 5 },
+  ],
+]);
+
+cloningTestWithKeyGenerator('object with blobs and large typed arrays', [
+  {
+    blob: { type: 'blob', size: wrapThreshold,
+            mimeType: 'text/x-blink1', seed: 1 },
+    more: [
+      { type: 'buffer', size: wrapThreshold, seed: 2 },
+      { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink3', seed: 3 },
+      { type: 'buffer', size: wrapThreshold, seed: 4 },
+    ],
+    blob2: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink5',
+             seed: 5 },
+  },
+]);
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-small.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-small.html
new file mode 100644
index 0000000..558415f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/nested-cloning-small.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf8">
+<meta name="timeout" content="long">
+<title>IndexedDB: small nested objects are cloned correctly</title>
+<link rel="help" href="https://w3c.github.io/IndexedDB/#abort-transaction">
+<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support-promises.js"></script>
+<script src="nested-cloning-common.js"></script>
+<script>
+
+cloningTest('small typed array', [
+  { type: 'buffer', size: 64, seed: 1 },
+]);
+
+cloningTest('blob', [
+  { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-1', seed: 1 },
+]);
+
+cloningTestWithKeyGenerator('blob with small typed array', [
+  {
+    blob: { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01',
+            seed: 1 },
+    buffer: { type: 'buffer', size: 64, seed: 2 },
+  },
+]);
+
+cloningTestWithKeyGenerator('blob array', [
+  [
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-1', seed: 1 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-2', seed: 2 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-3', seed: 3 },
+  ],
+]);
+
+cloningTestWithKeyGenerator('array of blobs and small typed arrays', [
+  [
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-01', seed: 1 },
+    { type: 'buffer', size: 64, seed: 2 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-03', seed: 3 },
+    { type: 'buffer', size: 64, seed: 4 },
+    { type: 'blob', size: wrapThreshold, mimeType: 'text/x-blink-05', seed: 5 },
+  ],
+]);
+
+</script>
diff --git a/third_party/WebKit/PerformanceTests/Skipped b/third_party/WebKit/PerformanceTests/Skipped
index 3f989ea..eaa8e1c 100644
--- a/third_party/WebKit/PerformanceTests/Skipped
+++ b/third_party/WebKit/PerformanceTests/Skipped
@@ -32,6 +32,8 @@
 inspector
 
 Canvas/drawimage.html
+# crbug.com/727919, crbug.com/736374
+Canvas/getImageDataColorManaged.html
 
 # Redundant with chromium's page cyclers.
 Replay
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 54d1d0f..45688101 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -167,10 +167,15 @@
     const WTF::Optional<NGLogicalOffset>& known_fragment_offset) {
   if (known_fragment_offset)
     return known_fragment_offset.value() - ContainerBfcOffset();
+
   LayoutUnit inline_offset =
       border_scrollbar_padding_.inline_start + child_margins.inline_start;
-  // TODO(ikilpatrick): Using the content_size_ here looks suspicious - check.
-  return {inline_offset, content_size_};
+
+  // If we've reached here, both the child and the current layout don't have a
+  // BFC offset yet. Children in this situation are always placed at a logical
+  // block offset of 0.
+  DCHECK(!container_builder_.BfcOffset());
+  return {inline_offset, LayoutUnit()};
 }
 
 RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
@@ -285,12 +290,14 @@
   //   Bottom margins of an in-flow block box doesn't collapse with its last
   //   in-flow block-level child's bottom margin if the box has bottom
   //   border/padding.
-  content_size_ += border_scrollbar_padding_.block_end;
   if (border_scrollbar_padding_.block_end ||
       ConstraintSpace().IsNewFormattingContext()) {
-    content_size_ += end_margin_strut.Sum();
+    content_size_ =
+        std::max(content_size_, previous_inflow_position.logical_block_offset +
+                                    end_margin_strut.Sum());
     end_margin_strut = NGMarginStrut();
   }
+  content_size_ += border_scrollbar_padding_.block_end;
 
   // Recompute the block-axis size now that we know our content size.
   size.block_size =
@@ -447,6 +454,8 @@
     child_bfc_offset = PositionWithBfcOffset(fragment);
   else if (container_builder_.BfcOffset())
     child_bfc_offset = PositionWithParentBfc(child_space, child_data, fragment);
+  else
+    DCHECK(!fragment.BlockSize());
 
   NGLogicalOffset logical_offset =
       CalculateLogicalOffset(child_data.margins, child_bfc_offset);
@@ -470,24 +479,29 @@
 
   container_builder_.AddChild(layout_result, logical_offset);
 
-  // Determine the child's end BFC block offset for the next child to use.
+  // Determine the child's end BFC block offset and logical offset, for the
+  // next child to use.
   LayoutUnit child_end_bfc_block_offset;
+  LayoutUnit logical_block_offset;
+
   if (child_bfc_offset) {
     // TODO(crbug.com/716930): I think the fragment.BfcOffset() condition here
     // can be removed once we've removed inline splitting.
     if (fragment.BlockSize() || fragment.BfcOffset()) {
       child_end_bfc_block_offset =
           child_bfc_offset.value().block_offset + fragment.BlockSize();
+      logical_block_offset = logical_offset.block_offset + fragment.BlockSize();
     } else {
       DCHECK_EQ(LayoutUnit(), fragment.BlockSize());
       child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
+      logical_block_offset = previous_inflow_position.logical_block_offset;
     }
   } else {
     child_end_bfc_block_offset = ConstraintSpace().BfcOffset().block_offset;
+    logical_block_offset = LayoutUnit();
   }
 
-  return {child_end_bfc_block_offset,
-          logical_offset.block_offset + fragment.BlockSize(), margin_strut};
+  return {child_end_bfc_block_offset, logical_block_offset, margin_strut};
 }
 
 NGLogicalOffset NGBlockLayoutAlgorithm::PositionNewFc(
@@ -573,19 +587,18 @@
   DCHECK(!fragment.BfcOffset());
   DCHECK_EQ(fragment.BlockSize(), LayoutUnit());
 
-  NGMarginStrut margin_strut = fragment.EndMarginStrut();
-  margin_strut.Append(child_data.margins.block_end);
-
-  NGLogicalOffset bfc_offset = {
+  NGLogicalOffset child_bfc_offset = {
       ConstraintSpace().BfcOffset().inline_offset +
           border_scrollbar_padding_.inline_start +
           child_data.margins.inline_start,
-      child_data.bfc_offset_estimate.block_offset + margin_strut.Sum()};
-  AdjustToClearance(space.ClearanceOffset(), &bfc_offset);
-  PositionPendingFloatsFromOffset(bfc_offset.block_offset,
-                                  bfc_offset.block_offset, &container_builder_,
-                                  MutableConstraintSpace());
-  return bfc_offset;
+      child_data.bfc_offset_estimate.block_offset +
+          fragment.EndMarginStrut().Sum()};
+
+  AdjustToClearance(space.ClearanceOffset(), &child_bfc_offset);
+  PositionPendingFloatsFromOffset(
+      child_bfc_offset.block_offset, child_bfc_offset.block_offset,
+      &container_builder_, MutableConstraintSpace());
+  return child_bfc_offset;
 }
 
 void NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index 9caa6d6d..ba2499a3 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -2526,5 +2526,79 @@
   EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(30)), child->Offset());
 }
 
+TEST_F(NGBlockLayoutAlgorithmTest, ZeroBlockSizeAboveEdge) {
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      #container { width: 200px; display: flow-root; }
+      #inflow { width: 50px; height: 50px; background: red; margin-top: -70px; }
+      #zero { width: 70px; margin: 10px 0 30px 0; }
+    </style>
+    <div id="container">
+      <div id="inflow"></div>
+      <div id="zero"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode node(ToLayoutBlockFlow(GetLayoutObjectByElementId("container")));
+  RefPtr<NGConstraintSpace> space = ConstructConstraintSpace(
+      kHorizontalTopBottom, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, true);
+
+  RefPtr<const NGPhysicalFragment> fragment =
+      NGBlockLayoutAlgorithm(node, space.Get()).Layout()->PhysicalFragment();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(200), LayoutUnit(10)), fragment->Size());
+
+  FragmentChildIterator iterator(ToNGPhysicalBoxFragment(fragment.Get()));
+
+  const NGPhysicalBoxFragment* child = iterator.NextChild();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(50), LayoutUnit(50)), child->Size());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(-70)), child->Offset());
+
+  child = iterator.NextChild();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(70), LayoutUnit(0)), child->Size());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(-10)), child->Offset());
+}
+
+TEST_F(NGBlockLayoutAlgorithmTest, NewFcFirstChildIsZeroBlockSize) {
+  SetBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      #container { width: 200px; display: flow-root; }
+      #zero1 { width: 50px; margin-top: -30px; margin-bottom: 10px; }
+      #zero2 { width: 70px; margin-top: 20px; margin-bottom: -40px; }
+      #inflow { width: 90px; height: 20px; margin-top: 30px; }
+    </style>
+    <div id="container">
+      <div id="zero1"></div>
+      <div id="zero2"></div>
+      <div id="inflow"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode node(ToLayoutBlockFlow(GetLayoutObjectByElementId("container")));
+  RefPtr<NGConstraintSpace> space = ConstructConstraintSpace(
+      kHorizontalTopBottom, TextDirection::kLtr,
+      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite), false, true);
+
+  RefPtr<const NGPhysicalFragment> fragment =
+      NGBlockLayoutAlgorithm(node, space.Get()).Layout()->PhysicalFragment();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(200), LayoutUnit(10)), fragment->Size());
+
+  FragmentChildIterator iterator(ToNGPhysicalBoxFragment(fragment.Get()));
+
+  const NGPhysicalBoxFragment* child = iterator.NextChild();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(50), LayoutUnit(0)), child->Size());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(-30)), child->Offset());
+
+  child = iterator.NextChild();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(70), LayoutUnit(0)), child->Size());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(-10)), child->Offset());
+
+  child = iterator.NextChild();
+  EXPECT_EQ(NGPhysicalSize(LayoutUnit(90), LayoutUnit(20)), child->Size());
+  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(0), LayoutUnit(-10)), child->Offset());
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
index c63e8c6..be4af1c 100644
--- a/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
+++ b/third_party/WebKit/Source/core/paint/ObjectPaintProperties.h
@@ -25,16 +25,17 @@
 // harden against use-after-free bugs. These paint properties are built/updated
 // by PaintPropertyTreeBuilder during the PrePaint lifecycle step.
 //
-// [update & clear implementation note] This class has update[property](...) and
-// clear[property]() helper functions for efficiently creating and updating
-// properties. These functions return true if the property tree structure
-// changes (e.g., a node is added or removed), and false otherwise. Property
-// nodes store parent pointers but not child pointers and these return values
-// are important for catching property tree structure changes which require
-// updating descendant's parent pointers. The update functions use a
-// create-or-update pattern of re-using existing properties for efficiency:
+// [update & clear implementation note] This class has Update[property](...) and
+// Clear[property]() helper functions for efficiently creating and updating
+// properties. The update functions returns a 3-state result to indicate whether
+// the value or the existence of the node has changed. They use a create-or-
+// update pattern of re-using existing properties for efficiency:
 // 1. It avoids extra allocations.
 // 2. It preserves existing child->parent pointers.
+// The clear functions return true if an existing node is removed. Property
+// nodes store parent pointers but not child pointers and these return values
+// are important for catching property tree structure changes which require
+// updating descendant's parent pointers.
 class CORE_EXPORT ObjectPaintProperties {
   WTF_MAKE_NONCOPYABLE(ObjectPaintProperties);
   USING_FAST_MALLOC(ObjectPaintProperties);
@@ -162,24 +163,32 @@
   bool ClearScrollTranslation() { return Clear(scroll_translation_); }
   bool ClearScrollbarPaintOffset() { return Clear(scrollbar_paint_offset_); }
 
-  // The following update* functions return true if the property tree structure
-  // changes (a new node was created), and false otherwise. See the class-level
-  // comment ("update & clear implementation note") for details about why this
-  // is needed for efficient updates.
+  class UpdateResult {
+   public:
+    bool ValueChanged() const { return result_ == kValueChanged; }
+    bool NewNodeCreated() const { return result_ == kNewNodeCreated; }
+
+   private:
+    friend class ObjectPaintProperties;
+    enum Result { kUnchanged, kValueChanged, kNewNodeCreated };
+    UpdateResult(Result r) : result_(r) {}
+    Result result_;
+  };
+
   template <typename... Args>
-  bool UpdatePaintOffsetTranslation(Args&&... args) {
+  UpdateResult UpdatePaintOffsetTranslation(Args&&... args) {
     return Update(paint_offset_translation_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateTransform(Args&&... args) {
+  UpdateResult UpdateTransform(Args&&... args) {
     return Update(transform_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdatePerspective(Args&&... args) {
+  UpdateResult UpdatePerspective(Args&&... args) {
     return Update(perspective_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateSvgLocalToBorderBoxTransform(Args&&... args) {
+  UpdateResult UpdateSvgLocalToBorderBoxTransform(Args&&... args) {
     DCHECK(!ScrollTranslation()) << "SVG elements cannot scroll so there "
                                     "should never be both a scroll translation "
                                     "and an SVG local to border box transform.";
@@ -187,52 +196,54 @@
                   std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateScrollTranslation(Args&&... args) {
+  UpdateResult UpdateScrollTranslation(Args&&... args) {
     DCHECK(!SvgLocalToBorderBoxTransform())
         << "SVG elements cannot scroll so there should never be both a scroll "
            "translation and an SVG local to border box transform.";
     if (scroll_translation_) {
-      scroll_translation_->UpdateScrollTranslation(std::forward<Args>(args)...);
-      return false;
+      return scroll_translation_->UpdateScrollTranslation(
+                 std::forward<Args>(args)...)
+                 ? UpdateResult::kValueChanged
+                 : UpdateResult::kUnchanged;
     }
     scroll_translation_ = TransformPaintPropertyNode::CreateScrollTranslation(
         std::forward<Args>(args)...);
-    return true;
+    return UpdateResult::kNewNodeCreated;
   }
   template <typename... Args>
-  bool UpdateScrollbarPaintOffset(Args&&... args) {
+  UpdateResult UpdateScrollbarPaintOffset(Args&&... args) {
     return Update(scrollbar_paint_offset_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateEffect(Args&&... args) {
+  UpdateResult UpdateEffect(Args&&... args) {
     return Update(effect_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateFilter(Args&&... args) {
+  UpdateResult UpdateFilter(Args&&... args) {
     return Update(filter_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateMask(Args&&... args) {
+  UpdateResult UpdateMask(Args&&... args) {
     return Update(mask_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateMaskClip(Args&&... args) {
+  UpdateResult UpdateMaskClip(Args&&... args) {
     return Update(mask_clip_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateCssClip(Args&&... args) {
+  UpdateResult UpdateCssClip(Args&&... args) {
     return Update(css_clip_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateCssClipFixedPosition(Args&&... args) {
+  UpdateResult UpdateCssClipFixedPosition(Args&&... args) {
     return Update(css_clip_fixed_position_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateInnerBorderRadiusClip(Args&&... args) {
+  UpdateResult UpdateInnerBorderRadiusClip(Args&&... args) {
     return Update(inner_border_radius_clip_, std::forward<Args>(args)...);
   }
   template <typename... Args>
-  bool UpdateOverflowClip(Args&&... args) {
+  UpdateResult UpdateOverflowClip(Args&&... args) {
     return Update(overflow_clip_, std::forward<Args>(args)...);
   }
 
@@ -293,13 +304,14 @@
   // created), and false otherwise. See the class-level comment ("update & clear
   // implementation note") for details about why this is needed for efficiency.
   template <typename PaintPropertyNode, typename... Args>
-  bool Update(RefPtr<PaintPropertyNode>& field, Args&&... args) {
+  UpdateResult Update(RefPtr<PaintPropertyNode>& field, Args&&... args) {
     if (field) {
-      field->Update(std::forward<Args>(args)...);
-      return false;
+      return field->Update(std::forward<Args>(args)...)
+                 ? UpdateResult::kValueChanged
+                 : UpdateResult::kUnchanged;
     }
     field = PaintPropertyNode::Create(std::forward<Args>(args)...);
-    return true;
+    return UpdateResult::kNewNodeCreated;
   }
 
   // ATTENTION! Make sure to keep FindPropertiesNeedingUpdate.h in sync when
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 441a240f..1ce1d4f9 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -276,12 +276,13 @@
         fractional_paint_offset = LayoutPoint();
     }
 
-    force_subtree_update |= properties.UpdatePaintOffsetTranslation(
+    auto result = properties.UpdatePaintOffsetTranslation(
         context.current.transform,
         TransformationMatrix().Translate(rounded_paint_offset.X(),
                                          rounded_paint_offset.Y()),
         FloatPoint3D(), context.current.should_flatten_inherited_transform,
         context.current.rendering_context_id);
+    force_subtree_update |= result.NewNodeCreated();
 
     context.current.transform = properties.PaintOffsetTranslation();
     context.current.paint_offset = fractional_paint_offset;
@@ -324,9 +325,10 @@
     AffineTransform transform = object.LocalToSVGParentTransform();
     if (NeedsTransformForNonRootSVG(object)) {
       // The origin is included in the local transform, so leave origin empty.
-      force_subtree_update |= properties.UpdateTransform(
-          context.current.transform, TransformationMatrix(transform),
-          FloatPoint3D());
+      auto result = properties.UpdateTransform(context.current.transform,
+                                               TransformationMatrix(transform),
+                                               FloatPoint3D());
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearTransform();
     }
@@ -420,12 +422,13 @@
         rendering_context_id = PtrHash<const LayoutObject>::GetHash(&object);
 
       auto& properties = *object.GetMutableForPainting().PaintProperties();
-      force_subtree_update |= properties.UpdateTransform(
+      auto result = properties.UpdateTransform(
           context.current.transform, matrix, TransformOrigin(box),
           context.current.should_flatten_inherited_transform,
           rendering_context_id, compositing_reasons,
           CompositorElementIdFromLayoutObjectId(
               object.UniqueId(), CompositorElementIdNamespace::kPrimary));
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearTransform();
     }
@@ -564,9 +567,10 @@
       bool has_mask = ComputeMaskParameters(
           mask_clip, mask_color_filter, object, context.current.paint_offset);
       if (has_mask) {
-        force_subtree_update |= properties.UpdateMaskClip(
-            context.current.clip, context.current.transform,
-            FloatRoundedRect(mask_clip));
+        auto result = properties.UpdateMaskClip(context.current.clip,
+                                                context.current.transform,
+                                                FloatRoundedRect(mask_clip));
+        force_subtree_update |= result.NewNodeCreated();
         output_clip = properties.MaskClip();
 
         // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
@@ -585,24 +589,26 @@
 
       DCHECK(!style.HasCurrentOpacityAnimation() ||
              compositing_reasons != kCompositingReasonNone);
-      force_subtree_update |= properties.UpdateEffect(
+      auto result = properties.UpdateEffect(
           context.current_effect, context.current.transform, output_clip,
           kColorFilterNone, CompositorFilterOperations(), style.Opacity(),
           blend_mode, compositing_reasons,
           CompositorElementIdFromLayoutObjectId(
               object.UniqueId(), CompositorElementIdNamespace::kPrimary));
+      force_subtree_update |= result.NewNodeCreated();
       if (has_mask) {
         // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
         // grouping (i.e. descendant-dependent compositing reason) properly
         // yet. Adding CompositingReasonSquashingDisallowed forces mask not
         // getting squashed into a child effect. Have no compositing reason
         // otherwise.
-        force_subtree_update |= properties.UpdateMask(
+        auto result = properties.UpdateMask(
             properties.Effect(), context.current.transform, output_clip,
             mask_color_filter, CompositorFilterOperations(), 1.f,
             SkBlendMode::kDstIn, kCompositingReasonSquashingDisallowed,
             CompositorElementIdFromLayoutObjectId(
                 object.UniqueId(), CompositorElementIdNamespace::kEffectMask));
+        force_subtree_update |= result.NewNodeCreated();
       } else {
         force_subtree_update |= properties.ClearMask();
       }
@@ -678,12 +684,13 @@
       DCHECK(!style.HasCurrentFilterAnimation() ||
              compositing_reasons != kCompositingReasonNone);
 
-      force_subtree_update |= properties.UpdateFilter(
+      auto result = properties.UpdateFilter(
           context.current_effect, context.current.transform, output_clip,
           kColorFilterNone, std::move(filter), 1.f, SkBlendMode::kSrcOver,
           compositing_reasons,
           CompositorElementIdFromLayoutObjectId(
               object.UniqueId(), CompositorElementIdNamespace::kEffectFilter));
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearFilter();
     }
@@ -717,9 +724,10 @@
       DCHECK(object.CanContainAbsolutePositionObjects());
       LayoutRect clip_rect =
           ToLayoutBox(object).ClipRect(context.current.paint_offset);
-      force_subtree_update |= properties.UpdateCssClip(
+      auto result = properties.UpdateCssClip(
           context.current.clip, context.current.transform,
           FloatRoundedRect(FloatRect(clip_rect)));
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearCssClip();
     }
@@ -772,8 +780,9 @@
         RoundedIntPoint(context.current.paint_offset);
     auto paint_offset = TransformationMatrix().Translate(
         rounded_paint_offset.X(), rounded_paint_offset.Y());
-    force_subtree_update |= properties.UpdateScrollbarPaintOffset(
+    auto result = properties.UpdateScrollbarPaintOffset(
         context.current.transform, paint_offset, FloatPoint3D());
+    force_subtree_update |= result.NewNodeCreated();
   } else {
     force_subtree_update |= properties.ClearScrollbarPaintOffset();
   }
@@ -799,16 +808,18 @@
       if (box.StyleRef().HasBorderRadius()) {
         auto inner_border = box.StyleRef().GetRoundedInnerBorderFor(
             LayoutRect(context.current.paint_offset, box.Size()));
-        force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
+        auto result = properties.UpdateInnerBorderRadiusClip(
             context.current.clip, context.current.transform, inner_border);
+        force_subtree_update |= result.NewNodeCreated();
         current_clip = properties.InnerBorderRadiusClip();
       } else {
         force_subtree_update |= properties.ClearInnerBorderRadiusClip();
       }
 
-      force_subtree_update |=
+      auto result =
           properties.UpdateOverflowClip(current_clip, context.current.transform,
                                         FloatRoundedRect(FloatRect(clip_rect)));
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearInnerBorderRadiusClip();
       force_subtree_update |= properties.ClearOverflowClip();
@@ -850,10 +861,11 @@
           TransformationMatrix().ApplyPerspective(style.Perspective());
       FloatPoint3D origin = PerspectiveOrigin(ToLayoutBox(object)) +
                             ToLayoutSize(context.current.paint_offset);
-      force_subtree_update |= properties.UpdatePerspective(
+      auto result = properties.UpdatePerspective(
           context.current.transform, matrix, origin,
           context.current.should_flatten_inherited_transform,
           context.current.rendering_context_id);
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearPerspective();
     }
@@ -883,8 +895,9 @@
             .TransformToPixelSnappedBorderBox(context.current.paint_offset);
     if (!transform_to_border_box.IsIdentity() &&
         NeedsSVGLocalToBorderBoxTransform(object)) {
-      force_subtree_update |= properties.UpdateSvgLocalToBorderBoxTransform(
+      auto result = properties.UpdateSvgLocalToBorderBoxTransform(
           context.current.transform, transform_to_border_box, FloatPoint3D());
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       force_subtree_update |= properties.ClearSvgLocalToBorderBoxTransform();
     }
@@ -954,7 +967,7 @@
 
       TransformationMatrix matrix = TransformationMatrix().Translate(
           -scroll_offset.Width(), -scroll_offset.Height());
-      force_subtree_update |= properties.UpdateScrollTranslation(
+      auto result = properties.UpdateScrollTranslation(
           context.current.transform, matrix, FloatPoint3D(),
           context.current.should_flatten_inherited_transform,
           context.current.rendering_context_id, kCompositingReasonNone,
@@ -964,6 +977,7 @@
           context.current.scroll, scroll_clip, scroll_bounds,
           user_scrollable_horizontal, user_scrollable_vertical, reasons,
           scrollable_area);
+      force_subtree_update |= result.NewNodeCreated();
     } else {
       // Ensure pre-existing properties are cleared.
       force_subtree_update |= properties.ClearScrollTranslation();
@@ -1020,11 +1034,12 @@
       context.fixed_position.clip = css_clip;
     } else {
       if (object.NeedsPaintPropertyUpdate() || force_subtree_update) {
-        force_subtree_update |= properties.UpdateCssClipFixedPosition(
+        auto result = properties.UpdateCssClipFixedPosition(
             context.fixed_position.clip,
             const_cast<TransformPaintPropertyNode*>(
                 css_clip->LocalTransformSpace()),
             css_clip->ClipRect());
+        force_subtree_update |= result.NewNodeCreated();
       }
       if (properties.CssClipFixedPosition())
         context.fixed_position.clip = properties.CssClipFixedPosition();
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h b/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h
index 6552fe45..eaf7360 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h
@@ -65,7 +65,8 @@
   bool multi_entry;
 };
 
-class IDBObjectStoreMetadata : public RefCounted<IDBObjectStoreMetadata> {
+class MODULES_EXPORT IDBObjectStoreMetadata
+    : public RefCounted<IDBObjectStoreMetadata> {
   USING_FAST_MALLOC(IDBObjectStoreMetadata);
 
  public:
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.h b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.h
index f91df7e..bf1abbc 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.h
@@ -48,8 +48,9 @@
 class IDBAny;
 class ExceptionState;
 
-class IDBObjectStore final : public GarbageCollectedFinalized<IDBObjectStore>,
-                             public ScriptWrappable {
+class MODULES_EXPORT IDBObjectStore final
+    : public GarbageCollectedFinalized<IDBObjectStore>,
+      public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
index 0f2e9073..1d6f188 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
@@ -36,6 +36,9 @@
 #include "modules/indexeddb/IDBDatabase.h"
 #include "modules/indexeddb/IDBDatabaseCallbacks.h"
 #include "modules/indexeddb/IDBKey.h"
+#include "modules/indexeddb/IDBKeyPath.h"
+#include "modules/indexeddb/IDBMetadata.h"
+#include "modules/indexeddb/IDBObjectStore.h"
 #include "modules/indexeddb/IDBOpenDBRequest.h"
 #include "modules/indexeddb/IDBTransaction.h"
 #include "modules/indexeddb/IDBValue.h"
@@ -80,13 +83,20 @@
     transaction_ = IDBTransaction::CreateNonVersionChange(
         scope.GetScriptState(), kTransactionId, transaction_scope,
         kWebIDBTransactionModeReadOnly, db_.Get());
+
+    IDBKeyPath store_key_path("primaryKey");
+    RefPtr<IDBObjectStoreMetadata> store_metadata = AdoptRef(
+        new IDBObjectStoreMetadata("store", kStoreId, store_key_path, true, 1));
+    store_ = IDBObjectStore::Create(store_metadata, transaction_);
   }
 
   WebURLLoaderMockFactory* url_loader_mock_factory_;
   Persistent<IDBDatabase> db_;
   Persistent<IDBTransaction> transaction_;
+  Persistent<IDBObjectStore> store_;
 
   static constexpr int64_t kTransactionId = 1234;
+  static constexpr int64_t kStoreId = 5678;
 };
 
 // The created value is an array of true. If create_wrapped_value is true, the
@@ -109,10 +119,12 @@
   wrapper.ExtractBlobDataHandles(blob_data_handles.get());
   Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
   RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes();
+  IDBKey* key = IDBKey::CreateNumber(42.0);
+  IDBKeyPath key_path(String("primaryKey"));
 
-  RefPtr<IDBValue> idb_value =
-      IDBValue::Create(wrapped_marker_buffer, std::move(blob_data_handles),
-                       WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos));
+  RefPtr<IDBValue> idb_value = IDBValue::Create(
+      wrapped_marker_buffer, std::move(blob_data_handles),
+      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
 
   DCHECK_EQ(create_wrapped_value,
             IDBValueUnwrapper::IsWrapped(idb_value.Get()));
@@ -148,7 +160,7 @@
   ASSERT_TRUE(transaction_);
 
   IDBRequest* request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
 
   EXPECT_EQ(request->readyState(), "pending");
@@ -169,7 +181,7 @@
   ASSERT_TRUE(transaction_);
 
   IDBRequest* request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   ASSERT_TRUE(!scope.GetExceptionState().HadException());
   ASSERT_TRUE(request->transaction());
@@ -189,7 +201,7 @@
   ASSERT_TRUE(transaction_);
 
   IDBRequest* request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   EXPECT_EQ(request->readyState(), "pending");
   ASSERT_TRUE(!scope.GetExceptionState().HadException());
@@ -212,10 +224,10 @@
   ASSERT_TRUE(transaction_);
 
   IDBRequest* request1 =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   IDBRequest* request2 =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   EXPECT_EQ(request1->readyState(), "pending");
   EXPECT_EQ(request2->readyState(), "pending");
@@ -237,7 +249,7 @@
   V8TestingScope scope;
   IDBTransaction* transaction = nullptr;
   IDBRequest* request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction, IDBRequest::AsyncTraceState());
   EXPECT_EQ(request->readyState(), "pending");
 
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
index f06ee92..2dcf0d32 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
@@ -39,6 +39,10 @@
 #include "core/events/EventQueue.h"
 #include "modules/indexeddb/IDBDatabase.h"
 #include "modules/indexeddb/IDBDatabaseCallbacks.h"
+#include "modules/indexeddb/IDBKey.h"
+#include "modules/indexeddb/IDBKeyPath.h"
+#include "modules/indexeddb/IDBMetadata.h"
+#include "modules/indexeddb/IDBObjectStore.h"
 #include "modules/indexeddb/IDBValue.h"
 #include "modules/indexeddb/IDBValueWrapping.h"
 #include "modules/indexeddb/MockWebIDBDatabase.h"
@@ -97,13 +101,20 @@
     transaction_ = IDBTransaction::CreateNonVersionChange(
         scope.GetScriptState(), kTransactionId, transaction_scope,
         kWebIDBTransactionModeReadOnly, db_.Get());
+
+    IDBKeyPath store_key_path("primaryKey");
+    RefPtr<IDBObjectStoreMetadata> store_metadata = AdoptRef(
+        new IDBObjectStoreMetadata("store", kStoreId, store_key_path, true, 1));
+    store_ = IDBObjectStore::Create(store_metadata, transaction_);
   }
 
   WebURLLoaderMockFactory* url_loader_mock_factory_;
   Persistent<IDBDatabase> db_;
   Persistent<IDBTransaction> transaction_;
+  Persistent<IDBObjectStore> store_;
 
   static constexpr int64_t kTransactionId = 1234;
+  static constexpr int64_t kStoreId = 5678;
 };
 
 // The created value is an array of true. If create_wrapped_value is true, the
@@ -126,10 +137,12 @@
   wrapper.ExtractBlobDataHandles(blob_data_handles.get());
   Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
   RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes();
+  IDBKey* key = IDBKey::CreateNumber(42.0);
+  IDBKeyPath key_path(String("primaryKey"));
 
-  RefPtr<IDBValue> idb_value =
-      IDBValue::Create(wrapped_marker_buffer, std::move(blob_data_handles),
-                       WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos));
+  RefPtr<IDBValue> idb_value = IDBValue::Create(
+      wrapped_marker_buffer, std::move(blob_data_handles),
+      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
 
   DCHECK_EQ(create_wrapped_value,
             IDBValueUnwrapper::IsWrapped(idb_value.Get()));
@@ -149,7 +162,7 @@
   EXPECT_EQ(1u, live_transactions.size());
 
   Persistent<IDBRequest> request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
 
   DeactivateNewTransactions(scope.GetIsolate());
@@ -163,6 +176,7 @@
   scope.GetExecutionContext()->NotifyContextDestroyed();
   transaction_->OnAbort(DOMException::Create(kAbortError, "Aborted"));
   transaction_.Clear();
+  store_.Clear();
 
   ThreadState::Current()->CollectAllGarbage();
   EXPECT_EQ(0U, live_transactions.size());
@@ -181,7 +195,7 @@
   EXPECT_EQ(1U, live_transactions.size());
 
   Persistent<IDBRequest> request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
@@ -197,6 +211,7 @@
   scope.GetExecutionContext()->NotifyContextDestroyed();
   transaction_->OnAbort(DOMException::Create(kAbortError, "Aborted"));
   transaction_.Clear();
+  store_.Clear();
 
   // The request completed, so it has enqueued a success event. Discard the
   // event, so that the transaction can go away.
@@ -220,7 +235,7 @@
   EXPECT_EQ(1U, live_transactions.size());
 
   Persistent<IDBRequest> request =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
@@ -235,6 +250,7 @@
   scope.GetExecutionContext()->NotifyContextDestroyed();
   transaction_->OnAbort(DOMException::Create(kAbortError, "Aborted"));
   transaction_.Clear();
+  store_.Clear();
 
   url_loader_mock_factory_->ServeAsynchronousRequests();
 
@@ -255,10 +271,10 @@
   EXPECT_EQ(1U, live_transactions.size());
 
   Persistent<IDBRequest> request1 =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   Persistent<IDBRequest> request2 =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
@@ -275,6 +291,7 @@
   scope.GetExecutionContext()->NotifyContextDestroyed();
   transaction_->OnAbort(DOMException::Create(kAbortError, "Aborted"));
   transaction_.Clear();
+  store_.Clear();
 
   url_loader_mock_factory_->ServeAsynchronousRequests();
 
@@ -297,10 +314,10 @@
   EXPECT_EQ(1U, live_transactions.size());
 
   Persistent<IDBRequest> request1 =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   Persistent<IDBRequest> request2 =
-      IDBRequest::Create(scope.GetScriptState(), IDBAny::CreateUndefined(),
+      IDBRequest::Create(scope.GetScriptState(), IDBAny::Create(store_.Get()),
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
@@ -317,6 +334,7 @@
   scope.GetDocument().Shutdown();
   transaction_->OnAbort(DOMException::Create(kAbortError, "Aborted"));
   transaction_.Clear();
+  store_.Clear();
 
   url_loader_mock_factory_->ServeAsynchronousRequests();
 
@@ -343,6 +361,7 @@
   EXPECT_EQ(1U, live_transactions.size());
 
   transaction_.Clear();
+  store_.Clear();
 
   ThreadState::Current()->CollectAllGarbage();
   EXPECT_EQ(1U, live_transactions.size());
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp
index 66ae7a81..f4eb6d04 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp
@@ -62,10 +62,14 @@
 
 IDBValue::IDBValue(RefPtr<SharedBuffer> unwrapped_data,
                    std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data,
-                   std::unique_ptr<Vector<WebBlobInfo>> blob_info)
+                   std::unique_ptr<Vector<WebBlobInfo>> blob_info,
+                   const IDBKey* primary_key,
+                   const IDBKeyPath& key_path)
     : data_(std::move(unwrapped_data)),
       blob_data_(std::move(blob_data)),
-      blob_info_(std::move(blob_info)) {}
+      blob_info_(std::move(blob_info)),
+      primary_key_(primary_key),
+      key_path_(key_path) {}
 
 IDBValue::~IDBValue() {
   if (isolate_)
@@ -90,9 +94,11 @@
 PassRefPtr<IDBValue> IDBValue::Create(
     PassRefPtr<SharedBuffer> unwrapped_data,
     std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data,
-    std::unique_ptr<Vector<WebBlobInfo>> blob_info) {
+    std::unique_ptr<Vector<WebBlobInfo>> blob_info,
+    const IDBKey* primary_key,
+    const IDBKeyPath& key_path) {
   return AdoptRef(new IDBValue(std::move(unwrapped_data), std::move(blob_data),
-                               std::move(blob_info)));
+                               std::move(blob_info), primary_key, key_path));
 }
 
 Vector<String> IDBValue::GetUUIDs() const {
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValue.h b/third_party/WebKit/Source/modules/indexeddb/IDBValue.h
index fb7f4a65..8c7d2b3 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValue.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValue.h
@@ -32,7 +32,9 @@
   static PassRefPtr<IDBValue> Create(
       PassRefPtr<SharedBuffer> unwrapped_data,
       std::unique_ptr<Vector<RefPtr<BlobDataHandle>>>,
-      std::unique_ptr<Vector<WebBlobInfo>>);
+      std::unique_ptr<Vector<WebBlobInfo>>,
+      const IDBKey*,
+      const IDBKeyPath&);
 
   ~IDBValue();
 
@@ -55,14 +57,16 @@
   IDBValue(const IDBValue*, IDBKey*, const IDBKeyPath&);
   IDBValue(RefPtr<SharedBuffer> unwrapped_data,
            std::unique_ptr<Vector<RefPtr<BlobDataHandle>>>,
-           std::unique_ptr<Vector<WebBlobInfo>>);
+           std::unique_ptr<Vector<WebBlobInfo>>,
+           const IDBKey*,
+           const IDBKeyPath&);
 
   // Keep this private to prevent new refs because we manually bookkeep the
   // memory to V8.
   const RefPtr<SharedBuffer> data_;
   const std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data_;
   const std::unique_ptr<Vector<WebBlobInfo>> blob_info_;
-  const Persistent<IDBKey> primary_key_;
+  const Persistent<const IDBKey> primary_key_;
   const IDBKeyPath key_path_;
   int64_t external_allocated_size_ = 0;
   // Used to register memory externally allocated by the WebIDBValue, and to
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
index bc0011f..83e6774 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
@@ -201,7 +201,8 @@
   }
 
   return IDBValue::Create(std::move(wrapper_blob_content), std::move(blob_data),
-                          std::move(blob_info));
+                          std::move(blob_info), wrapped_value->PrimaryKey(),
+                          wrapped_value->KeyPath());
 }
 
 bool IDBValueUnwrapper::Parse(IDBValue* value) {
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
index 15c1312..44753b9 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
@@ -6,6 +6,8 @@
 
 #include "bindings/core/v8/V8BindingForTesting.h"
 #include "core/fileapi/Blob.h"
+#include "modules/indexeddb/IDBKey.h"
+#include "modules/indexeddb/IDBKeyPath.h"
 #include "modules/indexeddb/IDBValue.h"
 #include "platform/wtf/PtrUtil.h"
 #include "platform/wtf/RefPtr.h"
@@ -27,11 +29,13 @@
   wrapper.ExtractBlobDataHandles(&blob_data_handles);
   Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
   RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes();
+  IDBKey* key = IDBKey::CreateNumber(42.0);
+  IDBKeyPath key_path(String("primaryKey"));
 
   RefPtr<IDBValue> wrapped_value = IDBValue::Create(
       wrapped_marker_buffer,
       WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>(blob_data_handles),
-      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos));
+      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
   EXPECT_TRUE(IDBValueUnwrapper::IsWrapped(wrapped_value.Get()));
 
   Vector<char> wrapped_marker_bytes(wrapped_marker_buffer->size());
@@ -46,7 +50,7 @@
     RefPtr<IDBValue> mutant_value = IDBValue::Create(
         SharedBuffer::Create(wrapped_marker_bytes.data(), i),
         WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>(blob_data_handles),
-        WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos));
+        WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
 
     EXPECT_FALSE(IDBValueUnwrapper::IsWrapped(mutant_value.Get()));
   }
@@ -62,7 +66,7 @@
           SharedBuffer::Create(wrapped_marker_bytes.data(),
                                wrapped_marker_bytes.size()),
           WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>(blob_data_handles),
-          WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos));
+          WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
       EXPECT_FALSE(IDBValueUnwrapper::IsWrapped(mutant_value.Get()));
 
       wrapped_marker_bytes[i] ^= mask;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index c887b77d..5ca48a5 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -435,7 +435,6 @@
 // Parses basic-card data to avoid parsing JSON in the browser.
 void SetBasicCardMethodData(const ScriptValue& input,
                             PaymentMethodDataPtr& output,
-                            ExecutionContext& execution_context,
                             ExceptionState& exception_state) {
   BasicCardRequest basic_card;
   V8BasicCardRequest::toImpl(input.GetIsolate(), input.V8Value(), basic_card,
@@ -484,12 +483,6 @@
         }
       }
     }
-
-    if (output->supported_types.size() != arraysize(kBasicCardTypes)) {
-      execution_context.AddConsoleMessage(ConsoleMessage::Create(
-          kJSMessageSource, kWarningMessageLevel,
-          "Cannot yet distinguish credit, debit, and prepaid cards."));
-    }
   }
 }
 
@@ -497,7 +490,6 @@
     const Vector<String>& supported_methods,
     const ScriptValue& input,
     PaymentMethodDataPtr& output,
-    ExecutionContext& execution_context,
     ExceptionState& exception_state) {
   DCHECK(!input.IsEmpty());
   v8::Local<v8::String> value;
@@ -530,11 +522,15 @@
   }
   if (RuntimeEnabledFeatures::PaymentRequestBasicCardEnabled() &&
       supported_methods.Contains("basic-card")) {
-    SetBasicCardMethodData(input, output, execution_context, exception_state);
+    SetBasicCardMethodData(input, output, exception_state);
     if (exception_state.HadException())
       exception_state.ClearException();
   }
+}
 
+void CountPaymentRequestNetworkNameInSupportedMethods(
+    const Vector<String>& supported_methods,
+    ExecutionContext& execution_context) {
   for (size_t i = 0; i < arraysize(kBasicCardNetworks); ++i) {
     if (supported_methods.Contains(kBasicCardNetworks[i].name)) {
       Deprecation::CountDeprecation(
@@ -594,6 +590,8 @@
         return;
       }
     }
+    CountPaymentRequestNetworkNameInSupportedMethods(
+        modifier.supportedMethods(), execution_context);
 
     output.back()->method_data =
         payments::mojom::blink::PaymentMethodData::New();
@@ -602,7 +600,7 @@
     if (modifier.hasData() && !modifier.data().IsEmpty()) {
       StringifyAndParseMethodSpecificData(
           modifier.supportedMethods(), modifier.data(),
-          output.back()->method_data, execution_context, exception_state);
+          output.back()->method_data, exception_state);
     } else {
       output.back()->method_data->stringified_data = "";
     }
@@ -723,6 +721,9 @@
       }
     }
 
+    CountPaymentRequestNetworkNameInSupportedMethods(
+        payment_method_data.supportedMethods(), execution_context);
+
     output.push_back(payments::mojom::blink::PaymentMethodData::New());
     output.back()->supported_methods = payment_method_data.supportedMethods();
 
@@ -730,7 +731,7 @@
         !payment_method_data.data().IsEmpty()) {
       StringifyAndParseMethodSpecificData(
           payment_method_data.supportedMethods(), payment_method_data.data(),
-          output.back(), execution_context, exception_state);
+          output.back(), exception_state);
     } else {
       output.back()->stringified_data = "";
     }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 3ab939b5..aab0c50 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1099,6 +1099,7 @@
     "graphics/paint/PaintController.cpp",
     "graphics/paint/PaintController.h",
     "graphics/paint/PaintFlags.h",
+    "graphics/paint/PaintPropertyNode.h",
     "graphics/paint/PaintRecord.h",
     "graphics/paint/PaintRecordBuilder.cpp",
     "graphics/paint/PaintRecordBuilder.h",
diff --git a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp
index 017019b..0a6c835 100644
--- a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp
+++ b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.cpp
@@ -35,14 +35,19 @@
 
 void ReverbInputBuffer::Write(const float* source_p, size_t number_of_frames) {
   size_t buffer_length = buffer_.size();
-  size_t index = WriteIndex();
-  size_t new_index = index + number_of_frames;
+  bool is_copy_safe = write_index_ + number_of_frames <= buffer_length;
+  DCHECK(is_copy_safe);
+  if (!is_copy_safe)
+    return;
 
-  CHECK_LE(new_index, buffer_length);
+  memcpy(buffer_.Data() + write_index_, source_p,
+         sizeof(float) * number_of_frames);
 
-  memcpy(buffer_.Data() + index, source_p, sizeof(float) * number_of_frames);
+  write_index_ += number_of_frames;
+  DCHECK_LE(write_index_, buffer_length);
 
-  SetWriteIndex(new_index);
+  if (write_index_ >= buffer_length)
+    write_index_ = 0;
 }
 
 float* ReverbInputBuffer::DirectReadFrom(int* read_index,
@@ -70,7 +75,7 @@
 
 void ReverbInputBuffer::Reset() {
   buffer_.Zero();
-  SetWriteIndex(0);
+  write_index_ = 0;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h
index d6c5008..e50602c 100644
--- a/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h
+++ b/third_party/WebKit/Source/platform/audio/ReverbInputBuffer.h
@@ -32,7 +32,6 @@
 #include "platform/PlatformExport.h"
 #include "platform/audio/AudioArray.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Atomics.h"
 #include "platform/wtf/Noncopyable.h"
 
 namespace blink {
@@ -53,8 +52,7 @@
   void Write(const float* source_p, size_t number_of_frames);
 
   // Background threads can call this to check if there's anything to read...
-  size_t WriteIndex() const { return AcquireLoad(&write_index_); }
-  void SetWriteIndex(size_t value) { ReleaseStore(&write_index_, value); }
+  size_t WriteIndex() const { return write_index_; }
 
   // The individual background threads read here (and hope that they can keep up
   // with the buffer writing).
@@ -68,10 +66,6 @@
 
  private:
   AudioFloatArray buffer_;
-
-  // write_index_ can be accessed from several threads.  Only use the
-  // getter and the setter to access it atomically.  Don't access
-  // write_index_ directly!
   size_t write_index_;
 };
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp
index 1d17f9d..bd9b6f7 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp
@@ -20,7 +20,7 @@
 String ClipPaintPropertyNode::ToString() const {
   return String::Format(
       "parent=%p localTransformSpace=%p rect=%s directCompositingReasons=%s",
-      parent_.Get(), local_transform_space_.Get(),
+      Parent(), local_transform_space_.Get(),
       clip_rect_.ToString().Ascii().data(),
       CompositingReasonsAsString(direct_compositing_reasons_).Ascii().data());
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
index 0244dc9..afbb61d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
@@ -8,10 +8,8 @@
 #include "platform/PlatformExport.h"
 #include "platform/geometry/FloatRoundedRect.h"
 #include "platform/graphics/paint/GeometryMapperClipCache.h"
+#include "platform/graphics/paint/PaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
-#include "platform/wtf/PassRefPtr.h"
-#include "platform/wtf/RefCounted.h"
-#include "platform/wtf/RefPtr.h"
 #include "platform/wtf/text/WTFString.h"
 
 #include <iosfwd>
@@ -27,7 +25,7 @@
 // The clip tree is rooted at a node with no parent. This root node should
 // not be modified.
 class PLATFORM_EXPORT ClipPaintPropertyNode
-    : public RefCounted<ClipPaintPropertyNode> {
+    : public PaintPropertyNode<ClipPaintPropertyNode> {
  public:
   // This node is really a sentinel, and does not represent a real clip
   // space.
@@ -43,15 +41,19 @@
         direct_compositing_reasons));
   }
 
-  void Update(
+  bool Update(
       PassRefPtr<const ClipPaintPropertyNode> parent,
       PassRefPtr<const TransformPaintPropertyNode> local_transform_space,
       const FloatRoundedRect& clip_rect) {
-    DCHECK(!IsRoot());
-    DCHECK(parent != this);
-    parent_ = std::move(parent);
+    bool parent_changed = PaintPropertyNode::Update(std::move(parent));
+
+    if (local_transform_space == local_transform_space_ &&
+        clip_rect == clip_rect_)
+      return parent_changed;
+
     local_transform_space_ = std::move(local_transform_space);
     clip_rect_ = clip_rect;
+    return true;
   }
 
   const TransformPaintPropertyNode* LocalTransformSpace() const {
@@ -59,15 +61,11 @@
   }
   const FloatRoundedRect& ClipRect() const { return clip_rect_; }
 
-  // Reference to inherited clips, or nullptr if this is the only clip.
-  const ClipPaintPropertyNode* Parent() const { return parent_.Get(); }
-  bool IsRoot() const { return !parent_; }
-
 #if DCHECK_IS_ON()
   // The clone function is used by FindPropertiesNeedingUpdate.h for recording
   // a clip node before it has been updated, to later detect changes.
   PassRefPtr<ClipPaintPropertyNode> Clone() const {
-    return AdoptRef(new ClipPaintPropertyNode(parent_, local_transform_space_,
+    return AdoptRef(new ClipPaintPropertyNode(Parent(), local_transform_space_,
                                               clip_rect_,
                                               direct_compositing_reasons_));
   }
@@ -75,7 +73,7 @@
   // The equality operator is used by FindPropertiesNeedingUpdate.h for checking
   // if a clip node has changed.
   bool operator==(const ClipPaintPropertyNode& o) const {
-    return parent_ == o.parent_ &&
+    return Parent() == o.Parent() &&
            local_transform_space_ == o.local_transform_space_ &&
            clip_rect_ == o.clip_rect_ &&
            direct_compositing_reasons_ == o.direct_compositing_reasons_;
@@ -96,12 +94,12 @@
       PassRefPtr<const TransformPaintPropertyNode> local_transform_space,
       const FloatRoundedRect& clip_rect,
       CompositingReasons direct_compositing_reasons)
-      : parent_(std::move(parent)),
+      : PaintPropertyNode(std::move(parent)),
         local_transform_space_(std::move(local_transform_space)),
         clip_rect_(clip_rect),
         direct_compositing_reasons_(direct_compositing_reasons) {}
 
-  // For access to getClipCache();
+  // For access to GetClipCache();
   friend class GeometryMapper;
   friend class GeometryMapperTest;
 
@@ -115,7 +113,6 @@
     return *geometry_mapper_clip_cache_.get();
   }
 
-  RefPtr<const ClipPaintPropertyNode> parent_;
   RefPtr<const TransformPaintPropertyNode> local_transform_space_;
   FloatRoundedRect clip_rect_;
   CompositingReasons direct_compositing_reasons_;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
index 85bfced..f481473d3 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
@@ -38,7 +38,7 @@
       "parent=%p localTransformSpace=%p outputClip=%p opacity=%f filter=%s "
       "blendMode=%s directCompositingReasons=%s compositorElementId=%lu "
       "paintOffset=%s",
-      parent_.Get(), local_transform_space_.Get(), output_clip_.Get(), opacity_,
+      Parent(), local_transform_space_.Get(), output_clip_.Get(), opacity_,
       filter_.ToString().Ascii().data(), SkBlendMode_Name(blend_mode_),
       CompositingReasonsAsString(direct_compositing_reasons_).Ascii().data(),
       static_cast<unsigned long>(compositor_element_id_.id_),
diff --git a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
index 287821c..de68bcb 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
@@ -11,10 +11,8 @@
 #include "platform/graphics/CompositorFilterOperations.h"
 #include "platform/graphics/GraphicsTypes.h"
 #include "platform/graphics/paint/ClipPaintPropertyNode.h"
+#include "platform/graphics/paint/PaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
-#include "platform/wtf/PassRefPtr.h"
-#include "platform/wtf/RefCounted.h"
-#include "platform/wtf/RefPtr.h"
 #include "platform/wtf/text/WTFString.h"
 
 #include <iosfwd>
@@ -27,7 +25,7 @@
 // The effect tree is rooted at a node with no parent. This root node should
 // not be modified.
 class PLATFORM_EXPORT EffectPaintPropertyNode
-    : public RefCounted<EffectPaintPropertyNode> {
+    : public PaintPropertyNode<EffectPaintPropertyNode> {
  public:
   // This node is really a sentinel, and does not represent a real effect.
   static EffectPaintPropertyNode* Root();
@@ -50,7 +48,7 @@
         paint_offset));
   }
 
-  void Update(
+  bool Update(
       PassRefPtr<const EffectPaintPropertyNode> parent,
       PassRefPtr<const TransformPaintPropertyNode> local_transform_space,
       PassRefPtr<const ClipPaintPropertyNode> output_clip,
@@ -61,9 +59,16 @@
       CompositingReasons direct_compositing_reasons = kCompositingReasonNone,
       const CompositorElementId& compositor_element_id = CompositorElementId(),
       const FloatPoint& paint_offset = FloatPoint()) {
-    DCHECK(!IsRoot());
-    DCHECK(parent != this);
-    parent_ = std::move(parent);
+    bool parent_changed = PaintPropertyNode::Update(std::move(parent));
+
+    if (local_transform_space == local_transform_space_ &&
+        output_clip == output_clip_ && color_filter == color_filter_ &&
+        filter == filter_ && opacity == opacity_ && blend_mode == blend_mode_ &&
+        direct_compositing_reasons == direct_compositing_reasons_ &&
+        compositor_element_id == compositor_element_id_ &&
+        paint_offset == paint_offset_)
+      return parent_changed;
+
     local_transform_space_ = std::move(local_transform_space);
     output_clip_ = std::move(output_clip);
     color_filter_ = color_filter;
@@ -73,6 +78,7 @@
     direct_compositing_reasons_ = direct_compositing_reasons;
     compositor_element_id_ = compositor_element_id;
     paint_offset_ = paint_offset;
+    return true;
   }
 
   const TransformPaintPropertyNode* LocalTransformSpace() const {
@@ -85,10 +91,6 @@
   const CompositorFilterOperations& Filter() const { return filter_; }
   ColorFilter GetColorFilter() const { return color_filter_; }
 
-  // Parent effect or nullptr if this is the root effect.
-  const EffectPaintPropertyNode* Parent() const { return parent_.Get(); }
-  bool IsRoot() const { return !parent_; }
-
   bool HasFilterThatMovesPixels() const {
     return filter_.HasFilterThatMovesPixels();
   }
@@ -104,7 +106,7 @@
   // an effect node before it has been updated, to later detect changes.
   PassRefPtr<EffectPaintPropertyNode> Clone() const {
     return AdoptRef(new EffectPaintPropertyNode(
-        parent_, local_transform_space_, output_clip_, color_filter_, filter_,
+        Parent(), local_transform_space_, output_clip_, color_filter_, filter_,
         opacity_, blend_mode_, direct_compositing_reasons_,
         compositor_element_id_, paint_offset_));
   }
@@ -113,7 +115,7 @@
   // if an effect node has changed. It ignores changes of reference filters
   // because SkImageFilter doesn't have an equality operator.
   bool operator==(const EffectPaintPropertyNode& o) const {
-    return parent_ == o.parent_ &&
+    return Parent() == o.Parent() &&
            local_transform_space_ == o.local_transform_space_ &&
            output_clip_ == o.output_clip_ && color_filter_ == o.color_filter_ &&
            filter_.EqualsIgnoringReferenceFilters(o.filter_) &&
@@ -152,7 +154,7 @@
       CompositingReasons direct_compositing_reasons,
       CompositorElementId compositor_element_id,
       const FloatPoint& paint_offset)
-      : parent_(std::move(parent)),
+      : PaintPropertyNode(std::move(parent)),
         local_transform_space_(std::move(local_transform_space)),
         output_clip_(std::move(output_clip)),
         color_filter_(color_filter),
@@ -163,7 +165,6 @@
         compositor_element_id_(compositor_element_id),
         paint_offset_(paint_offset) {}
 
-  RefPtr<const EffectPaintPropertyNode> parent_;
   // The local transform space serves two purposes:
   // 1. Assign a depth mapping for 3D depth sorting against other paint chunks
   //    and effects under the same parent.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h
new file mode 100644
index 0000000..daf0137
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PaintPropertyNode_h
+#define PaintPropertyNode_h
+
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/RefCounted.h"
+#include "platform/wtf/RefPtr.h"
+
+namespace blink {
+
+template <typename NodeType>
+class PaintPropertyNode : public RefCounted<NodeType> {
+ public:
+  // Parent property node, or nullptr if this is the root node.
+  const NodeType* Parent() const { return parent_.Get(); }
+  bool IsRoot() const { return !parent_; }
+
+ protected:
+  PaintPropertyNode(PassRefPtr<const NodeType> parent)
+      : parent_(std::move(parent)) {}
+
+  bool Update(PassRefPtr<const NodeType> parent) {
+    DCHECK(!IsRoot());
+    DCHECK(parent != this);
+    if (parent == parent_)
+      return false;
+
+    parent_ = std::move(parent);
+    return true;
+  }
+
+ private:
+  RefPtr<const NodeType> parent_;
+};
+
+}  // namespace blink
+
+#endif  // PaintPropertyNode_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
index 1ee28001..38a9fb6 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
@@ -19,7 +19,7 @@
 String ScrollPaintPropertyNode::ToString() const {
   StringBuilder text;
   text.Append("parent=");
-  text.Append(String::Format("%p", parent_.Get()));
+  text.Append(String::Format("%p", Parent()));
   text.Append(" clip=");
   text.Append(clip_.ToString());
   text.Append(" bounds=");
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
index 05162ba..b7f54b2 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
@@ -7,10 +7,8 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/geometry/FloatSize.h"
+#include "platform/graphics/paint/PaintPropertyNode.h"
 #include "platform/scroll/MainThreadScrollingReason.h"
-#include "platform/wtf/PassRefPtr.h"
-#include "platform/wtf/RefCounted.h"
-#include "platform/wtf/RefPtr.h"
 #include "platform/wtf/text/WTFString.h"
 
 #include <iosfwd>
@@ -33,7 +31,7 @@
 // geometry directly. We may want to rename this class to reflect that it is
 // more like rare scroll data for TransformPaintPropertyNode.
 class PLATFORM_EXPORT ScrollPaintPropertyNode
-    : public RefCounted<ScrollPaintPropertyNode> {
+    : public PaintPropertyNode<ScrollPaintPropertyNode> {
  public:
   // This node is really a sentinel, and does not represent a real scroll.
   static ScrollPaintPropertyNode* Root();
@@ -52,27 +50,31 @@
         scroll_client));
   }
 
-  void Update(PassRefPtr<const ScrollPaintPropertyNode> parent,
+  bool Update(PassRefPtr<const ScrollPaintPropertyNode> parent,
               const IntSize& clip,
               const IntSize& bounds,
               bool user_scrollable_horizontal,
               bool user_scrollable_vertical,
               MainThreadScrollingReasons main_thread_scrolling_reasons,
               WebLayerScrollClient* scroll_client) {
-    DCHECK(!IsRoot());
-    DCHECK(parent != this);
-    parent_ = std::move(parent);
+    bool parent_changed = PaintPropertyNode::Update(std::move(parent));
+
+    if (clip == clip_ && bounds == bounds_ &&
+        user_scrollable_horizontal == user_scrollable_horizontal_ &&
+        user_scrollable_vertical == user_scrollable_vertical_ &&
+        main_thread_scrolling_reasons == main_thread_scrolling_reasons_ &&
+        scroll_client == scroll_client_)
+      return parent_changed;
+
     clip_ = clip;
     bounds_ = bounds;
     user_scrollable_horizontal_ = user_scrollable_horizontal;
     user_scrollable_vertical_ = user_scrollable_vertical;
     main_thread_scrolling_reasons_ = main_thread_scrolling_reasons;
     scroll_client_ = scroll_client;
+    return true;
   }
 
-  const ScrollPaintPropertyNode* Parent() const { return parent_.Get(); }
-  bool IsRoot() const { return !parent_; }
-
   // The clipped area that contains the scrolled content.
   const IntSize& Clip() const { return clip_; }
 
@@ -107,7 +109,7 @@
   PassRefPtr<ScrollPaintPropertyNode> Clone() const {
     RefPtr<ScrollPaintPropertyNode> cloned =
         AdoptRef(new ScrollPaintPropertyNode(
-            parent_, clip_, bounds_, user_scrollable_horizontal_,
+            Parent(), clip_, bounds_, user_scrollable_horizontal_,
             user_scrollable_vertical_, main_thread_scrolling_reasons_,
             scroll_client_));
     return cloned;
@@ -116,7 +118,7 @@
   // The equality operator is used by FindPropertiesNeedingUpdate.h for checking
   // if a scroll node has changed.
   bool operator==(const ScrollPaintPropertyNode& o) const {
-    return parent_ == o.parent_ && clip_ == o.clip_ && bounds_ == o.bounds_ &&
+    return Parent() == o.Parent() && clip_ == o.clip_ && bounds_ == o.bounds_ &&
            user_scrollable_horizontal_ == o.user_scrollable_horizontal_ &&
            user_scrollable_vertical_ == o.user_scrollable_vertical_ &&
            main_thread_scrolling_reasons_ == o.main_thread_scrolling_reasons_ &&
@@ -137,7 +139,7 @@
       bool user_scrollable_vertical,
       MainThreadScrollingReasons main_thread_scrolling_reasons,
       WebLayerScrollClient* scroll_client)
-      : parent_(std::move(parent)),
+      : PaintPropertyNode(std::move(parent)),
         clip_(clip),
         bounds_(bounds),
         user_scrollable_horizontal_(user_scrollable_horizontal),
@@ -145,7 +147,6 @@
         main_thread_scrolling_reasons_(main_thread_scrolling_reasons),
         scroll_client_(scroll_client) {}
 
-  RefPtr<const ScrollPaintPropertyNode> parent_;
   IntSize clip_;
   IntSize bounds_;
   bool user_scrollable_horizontal_ : 1;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp
index ab43c96a..ea109ca 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp
@@ -40,7 +40,7 @@
       "parent=%p transform=%s origin=%s flattensInheritedTransform=%s "
       "renderingContextId=%x directCompositingReasons=%s "
       "compositorElementId=%lu",
-      parent_.Get(), matrix_.ToString().Ascii().data(),
+      Parent(), matrix_.ToString().Ascii().data(),
       origin_.ToString().Ascii().data(),
       flattens_inherited_transform_ ? "yes" : "no", rendering_context_id_,
       CompositingReasonsAsString(direct_compositing_reasons_).Ascii().data(),
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
index 3ac42f2..d94c7b9 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
@@ -10,11 +10,9 @@
 #include "platform/graphics/CompositingReasons.h"
 #include "platform/graphics/CompositorElementId.h"
 #include "platform/graphics/paint/GeometryMapperTransformCache.h"
+#include "platform/graphics/paint/PaintPropertyNode.h"
 #include "platform/graphics/paint/ScrollPaintPropertyNode.h"
 #include "platform/transforms/TransformationMatrix.h"
-#include "platform/wtf/PassRefPtr.h"
-#include "platform/wtf/RefCounted.h"
-#include "platform/wtf/RefPtr.h"
 #include "platform/wtf/text/WTFString.h"
 
 #include <iosfwd>
@@ -30,7 +28,7 @@
 // The transform tree is rooted at a node with no parent. This root node should
 // not be modified.
 class PLATFORM_EXPORT TransformPaintPropertyNode
-    : public RefCounted<TransformPaintPropertyNode> {
+    : public PaintPropertyNode<TransformPaintPropertyNode> {
  public:
   // This node is really a sentinel, and does not represent a real transform
   // space.
@@ -77,7 +75,7 @@
             scroll_client)));
   }
 
-  void Update(
+  bool Update(
       PassRefPtr<const TransformPaintPropertyNode> parent,
       const TransformationMatrix& matrix,
       const FloatPoint3D& origin,
@@ -85,18 +83,25 @@
       unsigned rendering_context_id = 0,
       CompositingReasons direct_compositing_reasons = kCompositingReasonNone,
       CompositorElementId compositor_element_id = CompositorElementId()) {
-    DCHECK(!IsRoot());
-    DCHECK(parent != this);
-    parent_ = std::move(parent);
+    bool parent_changed = PaintPropertyNode::Update(std::move(parent));
+
+    if (matrix == matrix_ && origin == origin_ &&
+        flattens_inherited_transform == flattens_inherited_transform_ &&
+        rendering_context_id == rendering_context_id_ &&
+        direct_compositing_reasons == direct_compositing_reasons_ &&
+        compositor_element_id == compositor_element_id_)
+      return parent_changed;
+
     matrix_ = matrix;
     origin_ = origin;
     flattens_inherited_transform_ = flattens_inherited_transform;
     rendering_context_id_ = rendering_context_id;
     direct_compositing_reasons_ = direct_compositing_reasons;
     compositor_element_id_ = compositor_element_id;
+    return true;
   }
 
-  void UpdateScrollTranslation(
+  bool UpdateScrollTranslation(
       PassRefPtr<const TransformPaintPropertyNode> parent,
       const TransformationMatrix& matrix,
       const FloatPoint3D& origin,
@@ -111,24 +116,20 @@
       bool user_scrollable_vertical,
       MainThreadScrollingReasons main_thread_scrolling_reasons,
       WebLayerScrollClient* scroll_client) {
-    Update(std::move(parent), matrix, origin, flattens_inherited_transform,
-           rendering_context_id, direct_compositing_reasons,
-           compositor_element_id);
+    bool changed = Update(std::move(parent), matrix, origin,
+                          flattens_inherited_transform, rendering_context_id,
+                          direct_compositing_reasons, compositor_element_id);
     DCHECK(scroll_);
     DCHECK(matrix.IsIdentityOr2DTranslation());
-    scroll_->Update(std::move(parent_scroll), clip, bounds,
-                    user_scrollable_horizontal, user_scrollable_vertical,
-                    main_thread_scrolling_reasons, scroll_client);
+    changed |= scroll_->Update(
+        std::move(parent_scroll), clip, bounds, user_scrollable_horizontal,
+        user_scrollable_vertical, main_thread_scrolling_reasons, scroll_client);
+    return changed;
   }
 
   const TransformationMatrix& Matrix() const { return matrix_; }
   const FloatPoint3D& Origin() const { return origin_; }
 
-  // Parent transform that this transform is relative to, or nullptr if this
-  // is the root transform.
-  const TransformPaintPropertyNode* Parent() const { return parent_.Get(); }
-  bool IsRoot() const { return !parent_; }
-
   // True if this transform is for the scroll offset translation.
   bool IsScrollTranslation() const { return !!scroll_; }
   // The associated scroll node if this transform is the scroll offset for
@@ -169,7 +170,7 @@
   // a transform node before it has been updated, to later detect changes.
   PassRefPtr<TransformPaintPropertyNode> Clone() const {
     return AdoptRef(new TransformPaintPropertyNode(
-        parent_, matrix_, origin_, flattens_inherited_transform_,
+        Parent(), matrix_, origin_, flattens_inherited_transform_,
         rendering_context_id_, direct_compositing_reasons_,
         compositor_element_id_, scroll_ ? scroll_->Clone() : nullptr));
   }
@@ -179,7 +180,7 @@
   bool operator==(const TransformPaintPropertyNode& o) const {
     if (scroll_ && o.scroll_ && !(*scroll_ == *o.scroll_))
       return false;
-    return parent_ == o.parent_ && matrix_ == o.matrix_ &&
+    return Parent() == o.Parent() && matrix_ == o.matrix_ &&
            origin_ == o.origin_ &&
            flattens_inherited_transform_ == o.flattens_inherited_transform_ &&
            rendering_context_id_ == o.rendering_context_id_ &&
@@ -203,7 +204,7 @@
       CompositingReasons direct_compositing_reasons,
       CompositorElementId compositor_element_id,
       PassRefPtr<ScrollPaintPropertyNode> scroll = nullptr)
-      : parent_(std::move(parent)),
+      : PaintPropertyNode(std::move(parent)),
         matrix_(matrix),
         origin_(origin),
         flattens_inherited_transform_(flattens_inherited_transform),
@@ -227,7 +228,6 @@
     return *geometry_mapper_transform_cache_.get();
   }
 
-  RefPtr<const TransformPaintPropertyNode> parent_;
   TransformationMatrix matrix_;
   FloatPoint3D origin_;
   bool flattens_inherited_transform_;
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py
index 3397743..a92c8df 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/chromium_commit_mock.py
@@ -7,10 +7,14 @@
 
 class MockChromiumCommit(object):
 
-    def __init__(self, host, position='refs/heads/master@{#123}'):
+    def __init__(self, host, position='refs/heads/master@{#123}',
+                 message='Fake commit message',
+                 patch='Fake patch contents'):
         self.host = host
         self.position = position
         self.sha = hashlib.sha1(position).hexdigest()
+        self._message = message
+        self._patch = patch
 
     @property
     def short_sha(self):
@@ -24,3 +28,12 @@
 
     def url(self):
         return 'https://fake-chromium-commit-viewer.org/+/%s' % self.short_sha
+
+    def message(self):
+        return self._message
+
+    def subject(self):
+        return self._message
+
+    def format_patch(self):
+        return self._patch
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py
index 2260237..e38082a8 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common.py
@@ -29,15 +29,36 @@
 _log = logging.getLogger(__name__)
 
 
-def _exportable_commits_since(chromium_commit_hash, host, local_wpt):
+def exportable_commits_over_last_n_commits(
+        host, local_wpt, wpt_github, number=DEFAULT_COMMIT_HISTORY_WINDOW):
+    """Lists exportable commits after a certain point.
+
+    Args:
+        number: The number of commits back to look. The commits to check will
+            include all commits starting from the commit before HEAD~n, up
+            to and including HEAD.
+        host: A Host object.
+        local_wpt: A LocalWPT instance, used to see whether a Chromium commit
+            can be applied cleanly in the upstream repo.
+        wpt_github: A WPTGitHub instance, used to check whether PRs are closed.
+
+    Returns:
+        A list of ChromiumCommit objects for commits that are exportable after
+        the given commit, in chronological order.
+    """
+    start_commit = 'HEAD~{}'.format(number + 1)
+    return _exportable_commits_since(start_commit, host, local_wpt, wpt_github)
+
+
+def _exportable_commits_since(chromium_commit_hash, host, local_wpt, wpt_github):
     """Lists exportable commits after a certain point.
 
     Args:
         chromium_commit_hash: The SHA of the Chromium commit from which this
             method will look. This commit is not included in the commits searched.
         host: A Host object.
-        local_wpt: A LocalWPT instance, used to see whether a Chromium commit
-            can be applied cleanly in the upstream repo.
+        local_wpt: A LocalWPT instance.
+        wpt_github: A WPTGitHub instance.
 
     Returns:
         A list of ChromiumCommit objects for commits that are exportable after
@@ -53,32 +74,22 @@
         'git', 'rev-list', commit_range, '--reverse', '--', wpt_path
     ], cwd=absolute_chromium_dir(host)).splitlines()
     chromium_commits = [ChromiumCommit(host, sha=sha) for sha in commit_hashes]
-    return [commit for commit in chromium_commits if is_exportable(commit, local_wpt)]
+    exportable_commits = []
+    for commit in chromium_commits:
+        if is_exportable(commit, local_wpt, wpt_github):
+            exportable_commits.append(commit)
+    return exportable_commits
 
 
-def exportable_commits_over_last_n_commits(host, local_wpt, number=DEFAULT_COMMIT_HISTORY_WINDOW):
-    """Lists exportable commits after a certain point.
-
-    Args:
-        number: Number of commits back to look. The commits to check will
-            include all commits starting from the commit before HEAD~n, up
-            to and including HEAD.
-        host: A Host object.
-        local_wpt: A LocalWPT instance, used to see whether a Chromium commit
-            can be applied cleanly in the upstream repo.
-
-    Returns:
-        A list of ChromiumCommit objects for commits that are exportable after
-        the given commit, in chronological order.
-    """
-    return _exportable_commits_since('HEAD~{}'.format(number + 1), host, local_wpt)
-
-
-def is_exportable(chromium_commit, local_wpt):
+def is_exportable(chromium_commit, local_wpt, wpt_github):
     """Checks whether a given patch is exportable and can be applied."""
+    message = chromium_commit.message()
+    if 'NOEXPORT=true' in message or message.startswith('Import'):
+        return False
     patch = chromium_commit.format_patch()
-
-    return ('NOEXPORT=true' not in chromium_commit.message() and
-            not chromium_commit.message().startswith('Import') and
-            patch and
-            local_wpt.test_patch(patch, chromium_commit))
+    if not (patch and local_wpt.test_patch(patch, chromium_commit)):
+        return False
+    pull_request = wpt_github.pr_with_position(chromium_commit.position)
+    if pull_request and pull_request.state == 'closed':
+        return False
+    return True
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py
index b1fc2c0..5cb07c9 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/common_unittest.py
@@ -7,17 +7,23 @@
 from webkitpy.common.host_mock import MockHost
 from webkitpy.common.system.executive_mock import mock_git_commands
 from webkitpy.w3c.chromium_commit import ChromiumCommit
+from webkitpy.w3c.chromium_commit_mock import MockChromiumCommit
 from webkitpy.w3c.common import _exportable_commits_since
+from webkitpy.w3c.common import is_exportable
+from webkitpy.w3c.wpt_github import PullRequest
+from webkitpy.w3c.wpt_github_mock import MockWPTGitHub
 
 
 class MockLocalWPT(object):
 
-    def test_patch(self, patch, chromium_commit):  # pylint: disable=unused-argument
+    def test_patch(self, *_):
         return 'patch'
 
 
 class CommonTest(unittest.TestCase):
 
+    # TODO(qyearsley): Add a test for exportable_commits_over_last_n_commits.
+
     def test_exportable_commits_since(self):
         host = MockHost()
         host.executive = mock_git_commands({
@@ -31,7 +37,8 @@
             'footers': 'cr-rev-position',
         })
 
-        commits = _exportable_commits_since('beefcafe', host, MockLocalWPT())
+        commits = _exportable_commits_since(
+            'beefcafe', host, MockLocalWPT(), MockWPTGitHub(pull_requests=[]))
         self.assertEqual(len(commits), 1)
         self.assertIsInstance(commits[0], ChromiumCommit)
         self.assertEqual(host.executive.calls, [
@@ -39,74 +46,49 @@
             ['git', 'rev-list', 'beefcafe..HEAD', '--reverse', '--',
              'add087a97844f4b9e307d9a216940582d96db306/third_party/WebKit/LayoutTests/external/wpt/'],
             ['git', 'footers', '--position', 'add087a97844f4b9e307d9a216940582d96db306'],
+            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306'],
             ['git', 'diff-tree', '--name-only', '--no-commit-id', '-r', 'add087a97844f4b9e307d9a216940582d96db306', '--',
              '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'],
             ['git', 'format-patch', '-1', '--stdout', 'add087a97844f4b9e307d9a216940582d96db306', '--', 'some', 'files'],
-            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306'],
-            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306']
         ])
 
-    def test_ignores_commits_with_noexport_true(self):
-        host = MockHost()
-        host.executive = mock_git_commands({
-            'show': 'Commit message\nNOEXPORT=true',
-            'rev-list': 'add087a97844f4b9e307d9a216940582d96db306',
-            'rev-parse': 'add087a97844f4b9e307d9a216940582d96db306',
-            'footers': 'cr-rev-position',
-        })
+    def test_is_exportable(self):
+        commit = MockChromiumCommit(MockHost(), message='Message')
+        github = MockWPTGitHub(pull_requests=[])
+        self.assertTrue(is_exportable(commit, MockLocalWPT(), github))
 
-        commits = _exportable_commits_since('add087a97844f4b9e307d9a216940582d96db306', host, MockLocalWPT())
-        self.assertEqual(commits, [])
-        self.assertEqual(host.executive.calls, [
-            ['git', 'rev-parse', '--show-toplevel'],
-            ['git', 'rev-list', 'add087a97844f4b9e307d9a216940582d96db306..HEAD', '--reverse', '--',
-             'add087a97844f4b9e307d9a216940582d96db306/third_party/WebKit/LayoutTests/external/wpt/'],
-            ['git', 'footers', '--position', 'add087a97844f4b9e307d9a216940582d96db306'],
-            ['git', 'diff-tree', '--name-only', '--no-commit-id', '-r', 'add087a97844f4b9e307d9a216940582d96db306', '--',
-             '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'],
-            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306']
+    def test_commit_with_noexport_is_not_exportable(self):
+        commit = MockChromiumCommit(MockHost(), message='Message\nNOEXPORT=true')
+        github = MockWPTGitHub(pull_requests=[])
+        self.assertFalse(is_exportable(commit, MockLocalWPT(), github))
+
+        # A NOEXPORT tag in a revert CL also makes it non-exportable.
+        revert = MockChromiumCommit(MockHost(), message='Revert of Message\n> NOEXPORT=true')
+        self.assertFalse(is_exportable(revert, MockLocalWPT(), github))
+
+    def test_commit_that_starts_with_import_is_not_exportable(self):
+        commit = MockChromiumCommit(MockHost(), message='Import message')
+        github = MockWPTGitHub(pull_requests=[])
+        self.assertFalse(is_exportable(commit, MockLocalWPT(), github))
+
+    def test_commit_that_has_open_pr_is_exportable(self):
+        commit = MockChromiumCommit(
+            MockHost(),
+            message='Message\nCr-Commit-Position: refs/heads/master@{#423}',
+            position='refs/heads/master@{#423}')
+        github = MockWPTGitHub(pull_requests=[
+            PullRequest('Early PR', 3, 'Commit body\nCr-Commit-Position: refs/heads/master@{#11}', 'closed'),
+            PullRequest('Export PR', 12, 'Commit body\nCr-Commit-Position: refs/heads/master@{#423}', 'open'),
         ])
+        self.assertTrue(is_exportable(commit, MockLocalWPT(), github))
 
-    def test_ignores_reverted_commits_with_noexport_true(self):
-        host = MockHost()
-        host.executive = mock_git_commands({
-            'show': 'Commit message\n> NOEXPORT=true',
-            'rev-list': 'add087a97844f4b9e307d9a216940582d96db306',
-            'rev-parse': 'add087a97844f4b9e307d9a216940582d96db306',
-            'footers': 'cr-rev-position',
-            'diff-tree': '',
-        }, strict=True)
-
-        commits = _exportable_commits_since('add087a97844f4b9e307d9a216940582d96db306', host, MockLocalWPT())
-        self.assertEqual(len(commits), 0)
-        self.assertEqual(host.executive.calls, [
-            ['git', 'rev-parse', '--show-toplevel'],
-            ['git', 'rev-list', 'add087a97844f4b9e307d9a216940582d96db306..HEAD', '--reverse', '--',
-             'add087a97844f4b9e307d9a216940582d96db306/third_party/WebKit/LayoutTests/external/wpt/'],
-            ['git', 'footers', '--position', 'add087a97844f4b9e307d9a216940582d96db306'],
-            ['git', 'diff-tree', '--name-only', '--no-commit-id', '-r', 'add087a97844f4b9e307d9a216940582d96db306', '--',
-             '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'],
-            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306']
+    def test_commit_that_has_closed_pr_is_not_exportable(self):
+        commit = MockChromiumCommit(
+            MockHost(),
+            message='Message\nCr-Commit-Position: refs/heads/master@{#423}',
+            position='refs/heads/master@{#423}')
+        github = MockWPTGitHub(pull_requests=[
+            PullRequest('Early PR', 3, 'Commit body\nCr-Commit-Position: refs/heads/master@{#11}', 'closed'),
+            PullRequest('Export PR', 12, 'Commit body\nCr-Commit-Position: refs/heads/master@{#423}', 'closed'),
         ])
-
-    def test_ignores_commits_that_start_with_import(self):
-        host = MockHost()
-        host.executive = mock_git_commands({
-            'show': 'Import rutabaga@deadbeef',
-            'rev-list': 'add087a97844f4b9e307d9a216940582d96db306',
-            'rev-parse': 'add087a97844f4b9e307d9a216940582d96db306',
-            'footers': 'cr-rev-position',
-        })
-
-        commits = _exportable_commits_since('beefcafe', host, MockLocalWPT())
-        self.assertEqual(commits, [])
-        self.assertEqual(host.executive.calls, [
-            ['git', 'rev-parse', '--show-toplevel'],
-            ['git', 'rev-list', 'beefcafe..HEAD', '--reverse', '--',
-             'add087a97844f4b9e307d9a216940582d96db306/third_party/WebKit/LayoutTests/external/wpt/'],
-            ['git', 'footers', '--position', 'add087a97844f4b9e307d9a216940582d96db306'],
-            ['git', 'diff-tree', '--name-only', '--no-commit-id', '-r', 'add087a97844f4b9e307d9a216940582d96db306', '--',
-             '/mock-checkout/third_party/WebKit/LayoutTests/external/wpt'],
-            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306'],
-            ['git', 'show', '--format=%B', '--no-patch', 'add087a97844f4b9e307d9a216940582d96db306'],
-        ])
+        self.assertFalse(is_exportable(commit, MockLocalWPT(), github))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
index c934c5b..f35640c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/local_wpt.py
@@ -134,13 +134,10 @@
             self.run(['git', 'add', '.'])
             output = self.run(['git', 'diff', 'origin/master'])
         except ScriptError:
-            _log.warning('Patch did not apply cleanly, skipping.')
+            _log.debug('Patch did not apply cleanly for the following commit, skipping:')
             if chromium_commit:
-                _log.info('Commit: %s', chromium_commit.url())
-                _log.info('  Commit subject: "%s"', chromium_commit.subject())
-                _log.info('  Modified files in wpt directory in this commit:')
-                for path in chromium_commit.filtered_changed_files():
-                    _log.info('    %s', path)
+                _log.debug('Commit: %s', chromium_commit.url())
+                _log.debug('Commit subject: "%s"', chromium_commit.subject())
             output = ''
 
         self.clean()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
index 03764d6e..fe7b61236 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
@@ -78,7 +78,8 @@
                 self.create_or_update_pull_request_from_cl(cl)
 
     def get_exportable_commits(self):
-        return exportable_commits_over_last_n_commits(self.host, self.local_wpt)
+        return exportable_commits_over_last_n_commits(
+            self.host, self.local_wpt, self.wpt_github)
 
     def merge_pull_request(self, pull_request):
         _log.info('In-flight PR found: %s', pull_request.title)
@@ -130,7 +131,8 @@
         _log.info('chromium@%s', chromium_commit.sha)
         _log.info('(%d behind chromium@origin/master)', chromium_commit.num_behind_master())
 
-        exportable_commits = exportable_commits_since(chromium_commit.sha, self.host, self.local_wpt)
+        exportable_commits = exportable_commits_over_last_n_commits(
+            chromium_commit.sha, self.host, self.local_wpt, self.wpt_github)
 
         if not exportable_commits:
             _log.info('No exportable commits found in Chromium, stopping.')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
index ff0a0cc..44453cad 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
@@ -78,6 +78,9 @@
 
         self.assertEqual(test_exporter.wpt_github.calls, [
             'pr_with_position',
+            'pr_with_position',
+            'pr_with_position',
+            'pr_with_position',
             'pr_with_change_id',
             'create_pr',
             'add_label "default"',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index be23651..4ebf2fc 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -22,6 +22,7 @@
 from webkitpy.w3c.common import WPT_REPO_URL, WPT_DEST_NAME, exportable_commits_over_last_n_commits
 from webkitpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor
 from webkitpy.w3c.local_wpt import LocalWPT
+from webkitpy.w3c.wpt_github import WPTGitHub
 from webkitpy.w3c.test_copier import TestCopier
 from webkitpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater
 from webkitpy.w3c.wpt_manifest import WPTManifest
@@ -35,13 +36,14 @@
 
 class TestImporter(object):
 
-    def __init__(self, host):
+    def __init__(self, host, wpt_github=None):
         self.host = host
         self.executive = host.executive
         self.fs = host.filesystem
         self.finder = PathFinder(self.fs)
         self.verbose = False
         self.git_cl = None
+        self.wpt_github = wpt_github or WPTGitHub(self.host)
 
     def main(self, argv=None):
         options = self.parse_args(argv)
@@ -71,17 +73,19 @@
         if not options.ignore_exportable_commits:
             commits = self.exportable_but_not_exported_commits(temp_repo_path)
             if commits:
-                # If there are exportable commits, then there's no more work
-                # to do for now. This isn't really an error case; we expect
-                # to hit this case some of the time.
-
                 _log.info('There were exportable but not-yet-exported commits:')
                 for commit in commits:
                     _log.info('Commit: %s', commit.url())
+                    _log.info('Subject: %s', commit.subject().strip())
+                    pull_request = self.wpt_github.pr_with_position(commit.position)
+                    if pull_request:
+                        _log.info('PR: https://github.com/w3c/web-platform-tests/pull/%d', pull_request.number)
+                    else:
+                        _log.warning('No pull request found.')
                     _log.info('Modified files in wpt directory in this commit:')
                     for path in commit.filtered_changed_files():
                         _log.info('  %s', path)
-                _log.info('Aborting import to prevent clobbering these commits.')
+                _log.info('Aborting import to prevent clobbering commits.')
                 self.clean_up_temp_repo(temp_repo_path)
                 return 0
 
@@ -142,7 +146,7 @@
         return True
 
     def exportable_but_not_exported_commits(self, wpt_path):
-        """Checks for commits that might be overwritten by importing.
+        """Checks for commits that might be overwritten by importing and lists them.
 
         Args:
             wpt_path: The path to a local checkout of web-platform-tests.
@@ -153,7 +157,8 @@
         """
         assert self.host.filesystem.exists(wpt_path)
         local_wpt = LocalWPT(self.host, path=wpt_path)
-        return exportable_commits_over_last_n_commits(self.host, local_wpt)
+        return exportable_commits_over_last_n_commits(
+            self.host, local_wpt, self.wpt_github)
 
     def clean_up_temp_repo(self, temp_repo_path):
         """Removes the temporary copy of the wpt repo that was downloaded."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
index 5da78937..30112c599 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -8,15 +8,20 @@
 from webkitpy.common.system.log_testing import LoggingTestCase
 from webkitpy.w3c.test_importer import TestImporter
 from webkitpy.w3c.chromium_commit_mock import MockChromiumCommit
+from webkitpy.w3c.wpt_github_mock import MockWPTGitHub
+from webkitpy.w3c.wpt_github import PullRequest
 
 
 class TestImporterTest(LoggingTestCase):
 
-    def test_abort_on_exportable_commits(self):
+    def test_abort_on_exportable_commits_pr_found(self):
         host = MockHost()
-        importer = TestImporter(host)
+        wpt_github = MockWPTGitHub(pull_requests=[
+            PullRequest('Title', 5, 'Commit body\nCr-Commit-Position: refs/heads/master@{#431}', 'open'),
+        ])
+        importer = TestImporter(host, wpt_github=wpt_github)
         importer.exportable_but_not_exported_commits = lambda _: [
-            MockChromiumCommit(host, position='refs/heads/master@{#431915}')
+            MockChromiumCommit(host, position='refs/heads/master@{#431}')
         ]
         importer.checkout_is_okay = lambda _: True
         return_code = importer.main([])
@@ -25,11 +30,37 @@
             'INFO: Cloning repo: https://chromium.googlesource.com/external/w3c/web-platform-tests.git\n',
             'INFO: Local path: /mock-checkout/third_party/WebKit/LayoutTests/wpt\n',
             'INFO: There were exportable but not-yet-exported commits:\n',
-            'INFO: Commit: https://fake-chromium-commit-viewer.org/+/5e9a83004a\n',
+            'INFO: Commit: https://fake-chromium-commit-viewer.org/+/fa2de685c0\n',
+            'INFO: Subject: Fake commit message\n',
+            'INFO: PR: https://github.com/w3c/web-platform-tests/pull/5\n',
             'INFO: Modified files in wpt directory in this commit:\n',
             'INFO:   third_party/WebKit/LayoutTests/external/wpt/one.html\n',
             'INFO:   third_party/WebKit/LayoutTests/external/wpt/two.html\n',
-            'INFO: Aborting import to prevent clobbering these commits.\n',
+            'INFO: Aborting import to prevent clobbering commits.\n',
+            'INFO: Deleting temp repo directory /mock-checkout/third_party/WebKit/LayoutTests/wpt.\n',
+        ])
+
+    def test_abort_on_exportable_commits_no_pr_found(self):
+        host = MockHost()
+        wpt_github = MockWPTGitHub(pull_requests=[])
+        importer = TestImporter(host, wpt_github=wpt_github)
+        importer.exportable_but_not_exported_commits = lambda _: [
+            MockChromiumCommit(host, position='refs/heads/master@{#431}')
+        ]
+        importer.checkout_is_okay = lambda _: True
+        return_code = importer.main([])
+        self.assertEqual(return_code, 0)
+        self.assertLog([
+            'INFO: Cloning repo: https://chromium.googlesource.com/external/w3c/web-platform-tests.git\n',
+            'INFO: Local path: /mock-checkout/third_party/WebKit/LayoutTests/wpt\n',
+            'INFO: There were exportable but not-yet-exported commits:\n',
+            'INFO: Commit: https://fake-chromium-commit-viewer.org/+/fa2de685c0\n',
+            'INFO: Subject: Fake commit message\n',
+            'WARNING: No pull request found.\n',
+            'INFO: Modified files in wpt directory in this commit:\n',
+            'INFO:   third_party/WebKit/LayoutTests/external/wpt/one.html\n',
+            'INFO:   third_party/WebKit/LayoutTests/external/wpt/two.html\n',
+            'INFO: Aborting import to prevent clobbering commits.\n',
             'INFO: Deleting temp repo directory /mock-checkout/third_party/WebKit/LayoutTests/wpt.\n',
         ])
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
index 15387d00..8056fda 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
@@ -22,15 +22,18 @@
     This class contains methods for sending requests to the GitHub API.
     """
 
-    def __init__(self, host, user, token, pr_history_window=30):
+    def __init__(self, host, user=None, token=None, pr_history_window=30):
         self.host = host
         self.user = user
         self.token = token
-        assert self.user and self.token
 
         self._pr_history_window = pr_history_window
 
+    def has_credentials(self):
+        return self.user and self.token
+
     def auth_token(self):
+        assert self.has_credentials()
         return base64.b64encode('{}:{}'.format(self.user, self.token))
 
     def request(self, path, method, body=None):
@@ -39,14 +42,16 @@
         if body:
             body = json.dumps(body)
 
+        headers = {'Accept': 'application/vnd.github.v3+json'}
+
+        if self.has_credentials():
+            headers['Authorization'] = 'Basic {}'.format(self.auth_token())
+
         response = self.host.web.request(
             method=method,
             url=API_BASE + path,
             data=body,
-            headers={
-                'Accept': 'application/vnd.github.v3+json',
-                'Authorization': 'Basic {}'.format(self.auth_token()),
-            },
+            headers=headers
         )
 
         status_code = response.getcode()
@@ -148,8 +153,11 @@
             EXPORT_LABEL,
             self._pr_history_window
         )
+
         data, status_code = self.request(path, method='GET')
         if status_code == 200:
+            for item in data['items']:
+                print item['state'], item['number']
             return [self.make_pr_from_item(item) for item in data['items']]
         else:
             raise Exception('Non-200 status code (%s): %s' % (status_code, data))
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index d62e4807..a1273615 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -396,15 +396,9 @@
 def UpdateClang(args):
   print 'Updating Clang to %s...' % PACKAGE_VERSION
 
-  need_gold_plugin = 'LLVM_DOWNLOAD_GOLD_PLUGIN' in os.environ or (
-      sys.platform.startswith('linux') and
-      'buildtype=Official' in os.environ.get('GYP_DEFINES', ''))
-
   if ReadStampFile() == PACKAGE_VERSION and not args.force_local_build:
     print 'Clang is already up to date.'
-    if not need_gold_plugin or os.path.exists(
-        os.path.join(LLVM_BUILD_DIR, "lib/LLVMgold.so")):
-      return 0
+    return 0
 
   # Reset the stamp file in case the build is unsuccessful.
   WriteStampFile('')
@@ -427,11 +421,6 @@
       print 'clang %s unpacked' % PACKAGE_VERSION
       if sys.platform == 'win32':
         CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin'))
-      # Download the gold plugin if requested to by an environment variable.
-      # This is used by the CFI ClusterFuzz bot, and it's required for official
-      # builds on linux.
-      if need_gold_plugin:
-        RunCommand(['python', CHROMIUM_DIR+'/build/download_gold_plugin.py'])
       WriteStampFile(PACKAGE_VERSION)
       return 0
     except urllib2.URLError:
diff --git a/tools/gn/analyzer.cc b/tools/gn/analyzer.cc
index aa0eca4d..d1f2d524 100644
--- a/tools/gn/analyzer.cc
+++ b/tools/gn/analyzer.cc
@@ -395,7 +395,9 @@
 void Analyzer::AddTargetsDirectlyReferringToFileTo(const SourceFile* file,
                                                    TargetSet* matches) const {
   for (auto* target : all_targets_) {
-    if (TargetRefersToFile(target, file))
+    // Only handles targets in the default toolchain.
+    if ((target->label().GetToolchainLabel() == default_toolchain_) &&
+        TargetRefersToFile(target, file))
       matches->insert(target);
   }
 }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1ae3b91..d9373ed 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -29793,6 +29793,16 @@
   <int value="5" label="Infobar dismissed by tab closure"/>
 </enum>
 
+<enum name="PreviewsInfoBarTimestamp">
+  <int value="0" label="Timestamp shown"/>
+  <int value="1" label="Timestamp not shown because the preview was not stale"/>
+  <int value="2"
+      label="Timestamp not shown because the staleness was negative."/>
+  <int value="3"
+      label="Timestamp not shown because the staleness was greater than the
+             max"/>
+</enum>
+
 <enum name="PreviewsUserOptedOut">
   <int value="0" label="The user did not choose to reload the full page."/>
   <int value="1" label="The user chose to reload the full page."/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index aad0556..b99d769 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -58100,6 +58100,14 @@
   </summary>
 </histogram>
 
+<histogram name="Previews.InfoBarTimestamp" enum="PreviewsInfoBarTimestamp">
+  <owner>megjablon@chromium.org</owner>
+  <summary>
+    Whether the timestamp for a stale preview was shown on the infobar. If the
+    timestamp was not shown, states the reason why.
+  </summary>
+</histogram>
+
 <histogram name="Previews.OptOut.DBRowCount" units="rows">
   <owner>ryansturm@chromium.org</owner>
   <summary>
@@ -65696,8 +65704,8 @@
   <summary>
     Time between starting raster work on the pending tree and when it is ready
     to activate. Unlike PendingTreeDuration which - includes the time to commit
-    to this tree, the raster duration and the time for which the pending
-    tree waits before it can be activated - this only measures the time taken to
+    to this tree, the raster duration and the time for which the pending tree
+    waits before it can be activated - this only measures the time taken to
     rasterize tiles required for activation.
 
     The interval is recorded each time we are notifed that a pending tree is
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 163136ff..11f19bc 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -269,6 +269,14 @@
             'structured-clone-long-string-serialize.html',
             [story.expectations.ALL_ANDROID],
             'crbug.com/528472')
+        self.DisableStory(
+            'structured-clone-json-serialize.html',
+            [story.expectations.ANDROID_ONE],
+            'crbug.com/736123')
+        self.DisableStory(
+            'structured-clone-json-deserialize.html',
+            [story.expectations.ANDROID_ONE],
+            'crbug.com/736123')
     return StoryExpectations()
 
 
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 22deece..7ddbe98 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -167,7 +167,26 @@
   ]
 }
 
-android_library("ui_java") {
+java_group("ui_java") {
+  deps = [
+    ":ui_full_java",
+    ":ui_utils_java",
+  ]
+}
+
+# This is created explicitly for remoting_apk to avoid including
+# unused JNI functions.
+android_library("ui_utils_java") {
+  java_files = [
+    "java/src/org/chromium/ui/PhotoPickerListener.java",
+    "java/src/org/chromium/ui/UiUtils.java",
+  ]
+  deps = [
+    "//base:base_java",
+  ]
+}
+
+android_library("ui_full_java") {
   java_files = [
     "java/src/org/chromium/ui/DropdownAdapter.java",
     "java/src/org/chromium/ui/DropdownDividerDrawable.java",
@@ -176,8 +195,6 @@
     "java/src/org/chromium/ui/DropdownPopupWindow.java",
     "java/src/org/chromium/ui/HorizontalListDividerDrawable.java",
     "java/src/org/chromium/ui/OverscrollRefreshHandler.java",
-    "java/src/org/chromium/ui/PhotoPickerListener.java",
-    "java/src/org/chromium/ui/UiUtils.java",
     "java/src/org/chromium/ui/VSyncMonitor.java",
     "java/src/org/chromium/ui/base/ActivityWindowAndroid.java",
     "java/src/org/chromium/ui/base/AndroidPermissionDelegate.java",
@@ -225,6 +242,7 @@
   ]
   deps = [
     ":ui_java_resources",
+    ":ui_utils_java",
     "//base:base_java",
     "//third_party/android_tools:android_support_annotations_java",
     "//third_party/android_tools:android_support_v7_appcompat_java",
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index 3fc07b5..b71f40c 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -190,7 +190,7 @@
 
   float dip_scale = GetDipScale();
   int left_margin = std::round(bounds.x() * dip_scale);
-  int top_margin = std::round((content_offset().y() + bounds.y()) * dip_scale);
+  int top_margin = std::round((content_offset() + bounds.y()) * dip_scale);
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_ViewAndroidDelegate_setViewPosition(
       env, delegate, anchor, bounds.x(), bounds.y(), bounds.width(),
diff --git a/ui/android/view_android.h b/ui/android/view_android.h
index 7f013a9..764cb99 100644
--- a/ui/android/view_android.h
+++ b/ui/android/view_android.h
@@ -96,13 +96,10 @@
 
   // The content offset is in CSS pixels, and is used to translate
   // snapshots to the correct part of the view.
-  void set_content_offset(const gfx::Vector2dF& content_offset) {
+  void set_content_offset(float content_offset) {
     content_offset_ = content_offset;
   }
-
-  gfx::Vector2dF content_offset() const {
-    return content_offset_;
-  }
+  float content_offset() const { return content_offset_; }
 
   // Returns the window at the root of this hierarchy, or |null|
   // if disconnected.
@@ -143,6 +140,10 @@
   void OnBottomControlsChanged(float bottom_controls_offset,
                                float bottom_content_offset);
   int GetSystemWindowInsetBottom();
+  void set_viewport_size(const gfx::SizeF& viewport_size) {
+    viewport_size_ = viewport_size;
+  }
+  gfx::SizeF viewport_size() const { return viewport_size_; }
 
   ScopedAnchorView AcquireAnchorView();
   void SetAnchorRect(const base::android::JavaRef<jobject>& anchor,
@@ -215,9 +216,13 @@
   // the passed events should be processed by the view.
   LayoutParams layout_params_;
 
+  // In physical pixel.
   gfx::Size physical_size_;
 
-  gfx::Vector2dF content_offset_;  // in CSS pixel.
+  // In CSS pixel.
+  gfx::SizeF viewport_size_;  // viewport size from frame update.
+  float content_offset_;      // y content offset from the top.
+
   std::unique_ptr<EventForwarder> event_forwarder_;
 
   DISALLOW_COPY_AND_ASSIGN(ViewAndroid);
diff --git a/ui/aura/client/cursor_client.h b/ui/aura/client/cursor_client.h
index 8a78c1a..490cf57f 100644
--- a/ui/aura/client/cursor_client.h
+++ b/ui/aura/client/cursor_client.h
@@ -40,10 +40,10 @@
   virtual void HideCursor() = 0;
 
   // Sets the type of the mouse cursor icon.
-  virtual void SetCursorSet(ui::CursorSetType cursor_set) = 0;
+  virtual void SetCursorSize(ui::CursorSize cursor_size) = 0;
 
   // Gets the type of the mouse cursor icon.
-  virtual ui::CursorSetType GetCursorSet() const = 0;
+  virtual ui::CursorSize GetCursorSize() const = 0;
 
   // Gets whether the cursor is visible.
   virtual bool IsCursorVisible() const = 0;
diff --git a/ui/aura/client/cursor_client_observer.h b/ui/aura/client/cursor_client_observer.h
index 7dc2031..7766ed77 100644
--- a/ui/aura/client/cursor_client_observer.h
+++ b/ui/aura/client/cursor_client_observer.h
@@ -18,7 +18,7 @@
 class AURA_EXPORT CursorClientObserver {
  public:
   virtual void OnCursorVisibilityChanged(bool is_visible) {}
-  virtual void OnCursorSetChanged(ui::CursorSetType cursor_set) {}
+  virtual void OnCursorSizeChanged(ui::CursorSize cursor_size) {}
   virtual void OnCursorDisplayChanged(const display::Display& display) {}
 
  protected:
diff --git a/ui/aura/mus/window_manager_delegate.h b/ui/aura/mus/window_manager_delegate.h
index 8ba30ad..a8056cf 100644
--- a/ui/aura/mus/window_manager_delegate.h
+++ b/ui/aura/mus/window_manager_delegate.h
@@ -70,6 +70,9 @@
   // Globally shows or hides the cursor.
   virtual void SetCursorVisible(bool visible) = 0;
 
+  // Globally sets whether we use normal or large cursors.
+  virtual void SetCursorSize(ui::CursorSize cursor_size) = 0;
+
   // Sets a cursor which is used instead of the per window cursors. Pass a
   // nullopt in |cursor| to clear the override.
   virtual void SetGlobalOverrideCursor(
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index b69d69d..fb078bc 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -1884,6 +1884,11 @@
     window_manager_client_->WmSetCursorVisible(visible);
 }
 
+void WindowTreeClient::SetCursorSize(ui::CursorSize cursor_size) {
+  if (window_manager_client_)
+    window_manager_client_->WmSetCursorSize(cursor_size);
+}
+
 void WindowTreeClient::SetGlobalOverrideCursor(
     base::Optional<ui::CursorData> cursor) {
   if (window_manager_client_)
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index d3d6167..3bcc36d8a 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -484,6 +484,7 @@
   void LockCursor() override;
   void UnlockCursor() override;
   void SetCursorVisible(bool visible) override;
+  void SetCursorSize(ui::CursorSize cursor_size) override;
   void SetGlobalOverrideCursor(base::Optional<ui::CursorData> cursor) override;
   void RequestClose(Window* window) override;
   bool WaitForInitialDisplays() override;
diff --git a/ui/aura/test/mus/test_window_manager_client.cc b/ui/aura/test/mus/test_window_manager_client.cc
index 8ecb9dea..9e500d73 100644
--- a/ui/aura/test/mus/test_window_manager_client.cc
+++ b/ui/aura/test/mus/test_window_manager_client.cc
@@ -69,6 +69,8 @@
 
 void TestWindowManagerClient::WmSetCursorVisible(bool visible) {}
 
+void TestWindowManagerClient::WmSetCursorSize(ui::CursorSize cursor_size) {}
+
 void TestWindowManagerClient::WmSetGlobalOverrideCursor(
     base::Optional<ui::CursorData> cursor) {}
 
diff --git a/ui/aura/test/mus/test_window_manager_client.h b/ui/aura/test/mus/test_window_manager_client.h
index 0d56414..68d94332 100644
--- a/ui/aura/test/mus/test_window_manager_client.h
+++ b/ui/aura/test/mus/test_window_manager_client.h
@@ -56,6 +56,7 @@
   void WmLockCursor() override;
   void WmUnlockCursor() override;
   void WmSetCursorVisible(bool visible) override;
+  void WmSetCursorSize(ui::CursorSize cursor_size) override;
   void WmSetGlobalOverrideCursor(
       base::Optional<ui::CursorData> cursor) override;
   void WmMoveCursorToDisplayLocation(const gfx::Point& display_pixels,
diff --git a/ui/aura/test/test_cursor_client.cc b/ui/aura/test/test_cursor_client.cc
index 72f3a056..56f8fe02 100644
--- a/ui/aura/test/test_cursor_client.cc
+++ b/ui/aura/test/test_cursor_client.cc
@@ -44,11 +44,10 @@
     observer.OnCursorVisibilityChanged(false);
 }
 
-void TestCursorClient::SetCursorSet(ui::CursorSetType cursor_set) {
-}
+void TestCursorClient::SetCursorSize(ui::CursorSize cursor_size) {}
 
-ui::CursorSetType TestCursorClient::GetCursorSet() const {
-  return ui::CURSOR_SET_NORMAL;
+ui::CursorSize TestCursorClient::GetCursorSize() const {
+  return ui::CursorSize::kNormal;
 }
 
 bool TestCursorClient::IsCursorVisible() const {
diff --git a/ui/aura/test/test_cursor_client.h b/ui/aura/test/test_cursor_client.h
index 8b4e1d9..89aa953 100644
--- a/ui/aura/test/test_cursor_client.h
+++ b/ui/aura/test/test_cursor_client.h
@@ -36,8 +36,8 @@
   gfx::NativeCursor GetCursor() const override;
   void ShowCursor() override;
   void HideCursor() override;
-  void SetCursorSet(ui::CursorSetType cursor_set) override;
-  ui::CursorSetType GetCursorSet() const override;
+  void SetCursorSize(ui::CursorSize cursor_size) override;
+  ui::CursorSize GetCursorSize() const override;
   bool IsCursorVisible() const override;
   void EnableMouseEvents() override;
   void DisableMouseEvents() override;
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 00638b6..710731ee 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -160,6 +160,7 @@
     "cursor/cursor_data.cc",
     "cursor/cursor_data.h",
     "cursor/cursor_loader.h",
+    "cursor/cursor_type.h",
     "cursor/cursor_win.cc",
     "default_style.h",
     "default_theme_provider_mac.mm",
diff --git a/ui/base/cursor/cursor.h b/ui/base/cursor/cursor.h
index 05da7cd..716e7cf7 100644
--- a/ui/base/cursor/cursor.h
+++ b/ui/base/cursor/cursor.h
@@ -6,6 +6,7 @@
 #define UI_BASE_CURSOR_CURSOR_H_
 
 #include "build/build_config.h"
+#include "ui/base/cursor/cursor_type.h"
 #include "ui/base/ui_base_export.h"
 
 #if defined(OS_WIN)
@@ -24,69 +25,6 @@
 typedef void* PlatformCursor;
 #endif
 
-enum class CursorType {
-  // Equivalent to a NULL HCURSOR on Windows.
-  kNull = 0,
-
-  // These cursors mirror WebKit cursors from WebCursorInfo, but are replicated
-  // here so we don't introduce a WebKit dependency.
-  kPointer = 1,
-  kCross = 2,
-  kHand = 3,
-  kIBeam = 4,
-  kWait = 5,
-  kHelp = 6,
-  kEastResize = 7,
-  kNorthResize = 8,
-  kNorthEastResize = 9,
-  kNorthWestResize = 10,
-  kSouthResize = 11,
-  kSouthEastResize = 12,
-  kSouthWestResize = 13,
-  kWestResize = 14,
-  kNorthSouthResize = 15,
-  kEastWestResize = 16,
-  kNorthEastSouthWestResize = 17,
-  kNorthWestSouthEastResize = 18,
-  kColumnResize = 19,
-  kRowResize = 20,
-  kMiddlePanning = 21,
-  kEastPanning = 22,
-  kNorthPanning = 23,
-  kNorthEastPanning = 24,
-  kNorthWestPanning = 25,
-  kSouthPanning = 26,
-  kSouthEastPanning = 27,
-  kSouthWestPanning = 28,
-  kWestPanning = 29,
-  kMove = 30,
-  kVerticalText = 31,
-  kCell = 32,
-  kContextMenu = 33,
-  kAlias = 34,
-  kProgress = 35,
-  kNoDrop = 36,
-  kCopy = 37,
-  kNone = 38,
-  kNotAllowed = 39,
-  kZoomIn = 40,
-  kZoomOut = 41,
-  kGrab = 42,
-  kGrabbing = 43,
-  kCustom = 44,
-
-  // These additional drag and drop cursors are not listed in WebCursorInfo.
-  kDndNone = 45,
-  kDndMove = 46,
-  kDndCopy = 47,
-  kDndLink = 48,
-};
-
-enum CursorSetType {
-  CURSOR_SET_NORMAL,
-  CURSOR_SET_LARGE
-};
-
 // Ref-counted cursor that supports both default and custom cursors.
 class UI_BASE_EXPORT Cursor {
  public:
diff --git a/ui/base/cursor/cursor_loader_x11.cc b/ui/base/cursor/cursor_loader_x11.cc
index 5e12a17d..e464b78 100644
--- a/ui/base/cursor/cursor_loader_x11.cc
+++ b/ui/base/cursor/cursor_loader_x11.cc
@@ -346,7 +346,7 @@
   // fallback icon.
   int resource_id;
   gfx::Point point;
-  if (ui::GetCursorDataFor(ui::CURSOR_SET_NORMAL, id, scale(), &resource_id,
+  if (ui::GetCursorDataFor(ui::CursorSize::kNormal, id, scale(), &resource_id,
                            &point)) {
     LoadImageCursor(id, resource_id, point);
     return image_cursors_[id]->cursor;
diff --git a/ui/base/cursor/cursor_type.h b/ui/base/cursor/cursor_type.h
new file mode 100644
index 0000000..3fad02b8
--- /dev/null
+++ b/ui/base/cursor/cursor_type.h
@@ -0,0 +1,72 @@
+// 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 UI_BASE_CURSOR_CURSOR_TYPE_H_
+#define UI_BASE_CURSOR_CURSOR_TYPE_H_
+
+namespace ui {
+
+enum class CursorType {
+  // Equivalent to a NULL HCURSOR on Windows.
+  kNull = 0,
+
+  // These cursors mirror WebKit cursors from WebCursorInfo, but are replicated
+  // here so we don't introduce a WebKit dependency.
+  kPointer = 1,
+  kCross = 2,
+  kHand = 3,
+  kIBeam = 4,
+  kWait = 5,
+  kHelp = 6,
+  kEastResize = 7,
+  kNorthResize = 8,
+  kNorthEastResize = 9,
+  kNorthWestResize = 10,
+  kSouthResize = 11,
+  kSouthEastResize = 12,
+  kSouthWestResize = 13,
+  kWestResize = 14,
+  kNorthSouthResize = 15,
+  kEastWestResize = 16,
+  kNorthEastSouthWestResize = 17,
+  kNorthWestSouthEastResize = 18,
+  kColumnResize = 19,
+  kRowResize = 20,
+  kMiddlePanning = 21,
+  kEastPanning = 22,
+  kNorthPanning = 23,
+  kNorthEastPanning = 24,
+  kNorthWestPanning = 25,
+  kSouthPanning = 26,
+  kSouthEastPanning = 27,
+  kSouthWestPanning = 28,
+  kWestPanning = 29,
+  kMove = 30,
+  kVerticalText = 31,
+  kCell = 32,
+  kContextMenu = 33,
+  kAlias = 34,
+  kProgress = 35,
+  kNoDrop = 36,
+  kCopy = 37,
+  kNone = 38,
+  kNotAllowed = 39,
+  kZoomIn = 40,
+  kZoomOut = 41,
+  kGrab = 42,
+  kGrabbing = 43,
+  kCustom = 44,
+
+  // These additional drag and drop cursors are not listed in WebCursorInfo.
+  kDndNone = 45,
+  kDndMove = 46,
+  kDndCopy = 47,
+  kDndLink = 48,
+};
+
+enum class CursorSize { kNormal, kLarge };
+
+}  // namespace ui
+
+#endif  // UI_BASE_CURSOR_CURSOR_TYPE_H_
diff --git a/ui/base/cursor/cursors_aura.cc b/ui/base/cursor/cursors_aura.cc
index 0d8a73d..d7dadd8b 100644
--- a/ui/base/cursor/cursors_aura.cc
+++ b/ui/base/cursor/cursors_aura.cc
@@ -33,8 +33,8 @@
   HotPoint hot_2x;
 };
 
-struct CursorSet {
-  const CursorSetType id;
+struct CursorSizeData {
+  const CursorSize id;
   const CursorData* cursors;
   const int length;
   const CursorData* animated_cursors;
@@ -202,24 +202,19 @@
     {CursorType::kProgress, IDR_AURA_CURSOR_THROBBER, {7, 7}, {14, 14}},
 };
 
-const CursorSet kCursorSets[] = {
-  {
-    CURSOR_SET_NORMAL,
-    kNormalCursors, arraysize(kNormalCursors),
-    kAnimatedCursors, arraysize(kAnimatedCursors)
-  },
-  {
-    CURSOR_SET_LARGE,
-    kLargeCursors, arraysize(kLargeCursors),
-    // TODO(yoshiki): Replace animated cursors with big assets. crbug.com/247254
-    kAnimatedCursors, arraysize(kAnimatedCursors)
-  },
+const CursorSizeData kCursorSizes[] = {
+    {CursorSize::kNormal, kNormalCursors, arraysize(kNormalCursors),
+     kAnimatedCursors, arraysize(kAnimatedCursors)},
+    {CursorSize::kLarge, kLargeCursors, arraysize(kLargeCursors),
+     // TODO(yoshiki): Replace animated cursors with big assets.
+     // crbug.com/247254
+     kAnimatedCursors, arraysize(kAnimatedCursors)},
 };
 
-const CursorSet* GetCursorSetByType(CursorSetType cursor_set_id) {
-  for (size_t i = 0; i < arraysize(kCursorSets); ++i) {
-    if (kCursorSets[i].id == cursor_set_id)
-      return &kCursorSets[i];
+const CursorSizeData* GetCursorSizeByType(CursorSize cursor_size) {
+  for (size_t i = 0; i < arraysize(kCursorSizes); ++i) {
+    if (kCursorSizes[i].id == cursor_size)
+      return &kCursorSizes[i];
   }
 
   return NULL;
@@ -249,12 +244,12 @@
 
 }  // namespace
 
-bool GetCursorDataFor(CursorSetType cursor_set_id,
+bool GetCursorDataFor(CursorSize cursor_size,
                       CursorType id,
                       float scale_factor,
                       int* resource_id,
                       gfx::Point* point) {
-  const CursorSet* cursor_set = GetCursorSetByType(cursor_set_id);
+  const CursorSizeData* cursor_set = GetCursorSizeByType(cursor_size);
   if (cursor_set &&
       SearchTable(cursor_set->cursors,
                   cursor_set->length,
@@ -263,19 +258,19 @@
   }
 
   // Falls back to the default cursor set.
-  cursor_set = GetCursorSetByType(ui::CURSOR_SET_NORMAL);
+  cursor_set = GetCursorSizeByType(ui::CursorSize::kNormal);
   DCHECK(cursor_set);
   return SearchTable(cursor_set->cursors,
                      cursor_set->length,
                      id, scale_factor, resource_id, point);
 }
 
-bool GetAnimatedCursorDataFor(CursorSetType cursor_set_id,
+bool GetAnimatedCursorDataFor(CursorSize cursor_size,
                               CursorType id,
                               float scale_factor,
                               int* resource_id,
                               gfx::Point* point) {
-  const CursorSet* cursor_set = GetCursorSetByType(cursor_set_id);
+  const CursorSizeData* cursor_set = GetCursorSizeByType(cursor_size);
   if (cursor_set &&
       SearchTable(cursor_set->animated_cursors,
                   cursor_set->animated_length,
@@ -284,7 +279,7 @@
   }
 
   // Falls back to the default cursor set.
-  cursor_set = GetCursorSetByType(ui::CURSOR_SET_NORMAL);
+  cursor_set = GetCursorSizeByType(ui::CursorSize::kNormal);
   DCHECK(cursor_set);
   return SearchTable(cursor_set->animated_cursors,
                      cursor_set->animated_length,
@@ -304,11 +299,8 @@
   *point = IconUtil::GetHotSpotFromHICON(cursor_copy.platform());
 #else
   int resource_id;
-  if (!GetCursorDataFor(ui::CURSOR_SET_NORMAL,
-                        cursor.native_type(),
-                        cursor.device_scale_factor(),
-                        &resource_id,
-                        point)) {
+  if (!GetCursorDataFor(ui::CursorSize::kNormal, cursor.native_type(),
+                        cursor.device_scale_factor(), &resource_id, point)) {
     return false;
   }
 
diff --git a/ui/base/cursor/cursors_aura.h b/ui/base/cursor/cursors_aura.h
index 6ce2da6..ffa723a2 100644
--- a/ui/base/cursor/cursors_aura.h
+++ b/ui/base/cursor/cursors_aura.h
@@ -22,14 +22,14 @@
 // ui::CursorType::kHelp. The IDR will be placed in |resource_id| and the
 // hotspots for the different DPIs will be placed in |hot_1x| and |hot_2x|.
 // Returns false if |id| is invalid.
-bool UI_BASE_EXPORT GetCursorDataFor(CursorSetType cursor_set_id,
+bool UI_BASE_EXPORT GetCursorDataFor(CursorSize cursor_size,
                                      CursorType id,
                                      float scale_factor,
                                      int* resource_id,
                                      gfx::Point* point);
 
 // Like above, but for animated cursors.
-bool UI_BASE_EXPORT GetAnimatedCursorDataFor(CursorSetType cursor_set_id,
+bool UI_BASE_EXPORT GetAnimatedCursorDataFor(CursorSize cursor_size,
                                              CursorType id,
                                              float scale_factor,
                                              int* resource_id,
diff --git a/ui/base/cursor/image_cursors.cc b/ui/base/cursor/image_cursors.cc
index 6b6eea7..93c25a9a 100644
--- a/ui/base/cursor/image_cursors.cc
+++ b/ui/base/cursor/image_cursors.cc
@@ -60,8 +60,7 @@
 
 }  // namespace
 
-ImageCursors::ImageCursors() : cursor_set_(CURSOR_SET_NORMAL) {
-}
+ImageCursors::ImageCursors() : cursor_size_(CursorSize::kNormal) {}
 
 ImageCursors::~ImageCursors() {
 }
@@ -109,22 +108,18 @@
   for (size_t i = 0; i < arraysize(kImageCursorIds); ++i) {
     int resource_id = -1;
     gfx::Point hot_point;
-    bool success = GetCursorDataFor(cursor_set_,
-                                    kImageCursorIds[i],
-                                    device_scale_factor,
-                                    &resource_id,
-                                    &hot_point);
+    bool success =
+        GetCursorDataFor(cursor_size_, kImageCursorIds[i], device_scale_factor,
+                         &resource_id, &hot_point);
     DCHECK(success);
     cursor_loader_->LoadImageCursor(kImageCursorIds[i], resource_id, hot_point);
   }
   for (size_t i = 0; i < arraysize(kAnimatedCursorIds); ++i) {
     int resource_id = -1;
     gfx::Point hot_point;
-    bool success = GetAnimatedCursorDataFor(cursor_set_,
-                                            kAnimatedCursorIds[i],
-                                            device_scale_factor,
-                                            &resource_id,
-                                            &hot_point);
+    bool success =
+        GetAnimatedCursorDataFor(cursor_size_, kAnimatedCursorIds[i],
+                                 device_scale_factor, &resource_id, &hot_point);
     DCHECK(success);
     cursor_loader_->LoadAnimatedCursor(kAnimatedCursorIds[i],
                                        resource_id,
@@ -133,11 +128,11 @@
   }
 }
 
-void ImageCursors::SetCursorSet(CursorSetType cursor_set) {
-  if (cursor_set_ == cursor_set)
+void ImageCursors::SetCursorSize(CursorSize cursor_size) {
+  if (cursor_size_ == cursor_size)
     return;
 
-  cursor_set_ = cursor_set;
+  cursor_size_ = cursor_size;
 
   if (cursor_loader_.get())
     ReloadCursors();
diff --git a/ui/base/cursor/image_cursors.h b/ui/base/cursor/image_cursors.h
index 36e54656..43b40e0 100644
--- a/ui/base/cursor/image_cursors.h
+++ b/ui/base/cursor/image_cursors.h
@@ -33,8 +33,8 @@
   // size of the image to load. Returns true if the cursor image is reloaded.
   bool SetDisplay(const display::Display& display, float scale_factor);
 
-  // Sets the type of the mouse cursor icon.
-  void SetCursorSet(CursorSetType cursor_set);
+  // Sets the size of the mouse cursor icon.
+  void SetCursorSize(CursorSize cursor_size);
 
   // Sets the platform cursor based on the native type of |cursor|.
   void SetPlatformCursor(gfx::NativeCursor* cursor);
@@ -44,7 +44,7 @@
   void ReloadCursors();
 
   std::unique_ptr<CursorLoader> cursor_loader_;
-  CursorSetType cursor_set_;
+  CursorSize cursor_size_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageCursors);
 };
diff --git a/ui/gfx/image/image_unittest_util_ios.mm b/ui/gfx/image/image_unittest_util_ios.mm
index 5626617..ba55030 100644
--- a/ui/gfx/image/image_unittest_util_ios.mm
+++ b/ui/gfx/image/image_unittest_util_ios.mm
@@ -12,10 +12,11 @@
 namespace gfx {
 namespace test {
 
+// The |x| and |y| coordinates are interpreted as scale-independent in ios.
 SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
   // Start by extracting the target pixel into a 1x1 CGImage.
-  base::ScopedCFTypeRef<CGImageRef> pixel_image(
-      CGImageCreateWithImageInRect(image.CGImage, CGRectMake(x, y, 1, 1)));
+  base::ScopedCFTypeRef<CGImageRef> pixel_image(CGImageCreateWithImageInRect(
+      image.CGImage, CGRectMake(x * image.scale, y * image.scale, 1, 1)));
 
   // Draw that pixel into a 1x1 bitmap context.
   base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js
index fcca34c2..0ac5ea2 100644
--- a/ui/login/account_picker/md_user_pod_row.js
+++ b/ui/login/account_picker/md_user_pod_row.js
@@ -3169,7 +3169,7 @@
         this.smallPodsContainer.classList.remove('images-loading');
         this.topMask.classList.remove('images-loading');
         this.bottomMask.classList.remove('images-loading');
-      }, POD_ROW_IMAGES_LOAD_TIMEOUT_MS);
+      }.bind(this), POD_ROW_IMAGES_LOAD_TIMEOUT_MS);
 
       var isAccountPicker = $('login-header-bar').signinUIState ==
           SIGNIN_UI_STATE.ACCOUNT_PICKER;
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
index b4b827d..9d1749a 100644
--- a/ui/views/focus/focus_manager.cc
+++ b/ui/views/focus/focus_manager.cc
@@ -70,23 +70,24 @@
       return false;
 
     // Intercept arrow key messages to switch between grouped views.
+    bool is_left = key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP;
+    bool is_right = key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN;
     if (focused_view_ && focused_view_->GetGroup() != -1 &&
-        (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
-         key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
-      bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
+        (is_left || is_right)) {
+      bool next = is_right;
       View::Views views;
       focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
                                                &views);
       View::Views::const_iterator i(
           std::find(views.begin(), views.end(), focused_view_));
       DCHECK(i != views.end());
-      int index = static_cast<int>(i - views.begin());
-      index += next ? 1 : -1;
-      if (index < 0) {
-        index = static_cast<int>(views.size()) - 1;
-      } else if (index >= static_cast<int>(views.size())) {
+      size_t index = i - views.begin();
+      if (next && index == views.size() - 1)
         index = 0;
-      }
+      else if (!next && index == 0)
+        index = views.size() - 1;
+      else
+        index += next ? 1 : -1;
       SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
       return false;
     }
@@ -241,51 +242,50 @@
 
   // Traverse the FocusTraversable tree down to find the focusable view.
   View* v = FindFocusableView(focus_traversable, starting_view, reverse);
-  if (v) {
+  if (v)
     return v;
-  } else {
-    // Let's go up in the FocusTraversable tree.
-    FocusTraversable* parent_focus_traversable =
-        focus_traversable->GetFocusTraversableParent();
+
+  // Let's go up in the FocusTraversable tree.
+  FocusTraversable* parent_focus_traversable =
+      focus_traversable->GetFocusTraversableParent();
+  starting_view = focus_traversable->GetFocusTraversableParentView();
+  while (parent_focus_traversable) {
+    FocusTraversable* new_focus_traversable = nullptr;
+    View* new_starting_view = nullptr;
+    // When we are going backward, the parent view might gain the next focus.
+    bool check_starting_view = reverse;
+    v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
+        starting_view, reverse, FocusSearch::UP, check_starting_view,
+        &new_focus_traversable, &new_starting_view);
+
+    if (new_focus_traversable) {
+      DCHECK(!v);
+
+      // There is a FocusTraversable, traverse it down.
+      v = FindFocusableView(new_focus_traversable, nullptr, reverse);
+    }
+
+    if (v)
+      return v;
+
     starting_view = focus_traversable->GetFocusTraversableParentView();
-    while (parent_focus_traversable) {
-      FocusTraversable* new_focus_traversable = NULL;
-      View* new_starting_view = NULL;
-      // When we are going backward, the parent view might gain the next focus.
-      bool check_starting_view = reverse;
-      v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
-          starting_view, reverse, FocusSearch::UP,
-          check_starting_view, &new_focus_traversable, &new_starting_view);
-
-      if (new_focus_traversable) {
-        DCHECK(!v);
-
-        // There is a FocusTraversable, traverse it down.
-        v = FindFocusableView(new_focus_traversable, NULL, reverse);
-      }
-
-      if (v)
-        return v;
-
-      starting_view = focus_traversable->GetFocusTraversableParentView();
-      parent_focus_traversable =
-          parent_focus_traversable->GetFocusTraversableParent();
-    }
-
-    // If we get here, we have reached the end of the focus hierarchy, let's
-    // loop. Make sure there was at least a view to start with, to prevent
-    // infinitely looping in empty windows.
-    if (!dont_loop && original_starting_view) {
-      // Easy, just clear the selection and press tab again.
-      // By calling with NULL as the starting view, we'll start from either
-      // the starting views widget or |widget_|.
-      Widget* widget = original_starting_view->GetWidget();
-      if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
-        widget = widget_;
-      return GetNextFocusableView(NULL, widget, reverse, true);
-    }
+    parent_focus_traversable =
+        parent_focus_traversable->GetFocusTraversableParent();
   }
-  return NULL;
+
+  // If we get here, we have reached the end of the focus hierarchy, let's
+  // loop. Make sure there was at least a view to start with, to prevent
+  // infinitely looping in empty windows.
+  if (dont_loop || !original_starting_view)
+    return nullptr;
+
+  // Easy, just clear the selection and press tab again.
+  // By calling with NULL as the starting view, we'll start from either
+  // the starting views widget or |widget_|.
+  Widget* widget = original_starting_view->GetWidget();
+  if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
+    widget = widget_;
+  return GetNextFocusableView(nullptr, widget, reverse, true);
 }
 
 void FocusManager::SetKeyboardAccessible(bool keyboard_accessible) {
@@ -482,9 +482,7 @@
 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
   if (accelerator_manager_.Process(accelerator))
     return true;
-  if (delegate_.get())
-    return delegate_->ProcessAccelerator(accelerator);
-  return false;
+  return delegate_ && delegate_->ProcessAccelerator(accelerator);
 }
 
 bool FocusManager::HasPriorityHandler(
diff --git a/ui/views/focus/focus_manager_factory.cc b/ui/views/focus/focus_manager_factory.cc
index a5393cf..99ca7c5 100644
--- a/ui/views/focus/focus_manager_factory.cc
+++ b/ui/views/focus/focus_manager_factory.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/focus/focus_manager_factory.h"
 
+#include "base/memory/ptr_util.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/focus/focus_manager_delegate.h"
 
@@ -17,16 +18,17 @@
   ~DefaultFocusManagerFactory() override {}
 
  protected:
-  FocusManager* CreateFocusManager(Widget* widget,
-                                   bool desktop_widget) override {
-    return new FocusManager(widget, nullptr /* delegate */);
+  std::unique_ptr<FocusManager> CreateFocusManager(
+      Widget* widget,
+      bool desktop_widget) override {
+    return base::MakeUnique<FocusManager>(widget, nullptr /* delegate */);
   }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DefaultFocusManagerFactory);
 };
 
-FocusManagerFactory* focus_manager_factory = nullptr;
+FocusManagerFactory* g_focus_manager_factory = nullptr;
 
 }  // namespace
 
@@ -37,19 +39,19 @@
 }
 
 // static
-FocusManager* FocusManagerFactory::Create(Widget* widget,
-                                          bool desktop_widget) {
-  if (!focus_manager_factory)
-    focus_manager_factory = new DefaultFocusManagerFactory();
-  return focus_manager_factory->CreateFocusManager(widget, desktop_widget);
+std::unique_ptr<FocusManager> FocusManagerFactory::Create(Widget* widget,
+                                                          bool desktop_widget) {
+  if (!g_focus_manager_factory)
+    g_focus_manager_factory = new DefaultFocusManagerFactory();
+  return g_focus_manager_factory->CreateFocusManager(widget, desktop_widget);
 }
 
 // static
 void FocusManagerFactory::Install(FocusManagerFactory* f) {
-  if (f == focus_manager_factory)
+  if (f == g_focus_manager_factory)
     return;
-  delete focus_manager_factory;
-  focus_manager_factory = f ? f : new DefaultFocusManagerFactory();
+  delete g_focus_manager_factory;
+  g_focus_manager_factory = f ? f : new DefaultFocusManagerFactory();
 }
 
 }  // namespace views
diff --git a/ui/views/focus/focus_manager_factory.h b/ui/views/focus/focus_manager_factory.h
index ac90a7b8..9b17a8cb 100644
--- a/ui/views/focus/focus_manager_factory.h
+++ b/ui/views/focus/focus_manager_factory.h
@@ -5,6 +5,8 @@
 #ifndef UI_VIEWS_FOCUS_FOCUS_MANAGER_FACTORY_H_
 #define UI_VIEWS_FOCUS_FOCUS_MANAGER_FACTORY_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "ui/views/views_export.h"
 
@@ -17,8 +19,9 @@
 // to inject a custom factory.
 class VIEWS_EXPORT FocusManagerFactory {
  public:
-  // Create a FocusManager for the given |widget| using installe Factory.
-  static FocusManager* Create(Widget* widget, bool desktop_widget);
+  // Create a FocusManager for the given |widget| using the installed Factory.
+  static std::unique_ptr<FocusManager> Create(Widget* widget,
+                                              bool desktop_widget);
 
   // Installs FocusManagerFactory. If |factory| is NULL, it resets
   // to the default factory which creates plain FocusManager.
@@ -31,8 +34,9 @@
   // Create a FocusManager for the given |widget|.
   // The |desktop_widget| bool is true for widgets created in the desktop and
   // false for widgets created in the shell.
-  virtual FocusManager* CreateFocusManager(Widget* widget,
-                                           bool desktop_widget) = 0;
+  virtual std::unique_ptr<FocusManager> CreateFocusManager(
+      Widget* widget,
+      bool desktop_widget) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FocusManagerFactory);
diff --git a/ui/views/focus/focus_manager_unittest.cc b/ui/views/focus/focus_manager_unittest.cc
index bafea1e..7137786 100644
--- a/ui/views/focus/focus_manager_unittest.cc
+++ b/ui/views/focus/focus_manager_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -477,14 +478,17 @@
     explicit TestFocusManagerFactory(DtorTrackVector* dtor_tracker)
         : dtor_tracker_(dtor_tracker) {
     }
+    ~TestFocusManagerFactory() override {}
 
-    FocusManager* CreateFocusManager(Widget* widget,
-                                     bool desktop_widget) override {
-      return new FocusManagerDtorTracked(widget, dtor_tracker_);
+    std::unique_ptr<FocusManager> CreateFocusManager(
+        Widget* widget,
+        bool desktop_widget) override {
+      return base::MakeUnique<FocusManagerDtorTracked>(widget, dtor_tracker_);
     }
 
    private:
     DtorTrackVector* dtor_tracker_;
+
     DISALLOW_COPY_AND_ASSIGN(TestFocusManagerFactory);
   };
 
diff --git a/ui/views/mus/aura_init.cc b/ui/views/mus/aura_init.cc
index cb5ebff..f53872d 100644
--- a/ui/views/mus/aura_init.cc
+++ b/ui/views/mus/aura_init.cc
@@ -63,8 +63,9 @@
       env_(aura::Env::CreateInstance(
           (mode == Mode::AURA_MUS || mode == Mode::AURA_MUS_WINDOW_MANAGER)
               ? aura::Env::Mode::MUS
-              : aura::Env::Mode::LOCAL)),
-      views_delegate_(new MusViewsDelegate) {
+              : aura::Env::Mode::LOCAL)) {
+  if (!ViewsDelegate::GetInstance())
+    views_delegate_ = base::MakeUnique<MusViewsDelegate>();
   if (mode == Mode::AURA_MUS) {
     mus_client_ =
         base::WrapUnique(new MusClient(connector, identity, io_task_runner));
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index bd880bf9..e7d6712 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -165,8 +165,8 @@
     }
   }
 
-  void SetCursorSet(ui::CursorSetType cursor_set,
-                    wm::NativeCursorManagerDelegate* delegate) override {
+  void SetCursorSize(ui::CursorSize cursor_size,
+                     wm::NativeCursorManagerDelegate* delegate) override {
     // TODO(erg): For now, ignore the difference between SET_NORMAL and
     // SET_LARGE here. This feels like a thing that mus should decide instead.
     //
diff --git a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index 38242a73..5d4ae7a 100644
--- a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -74,8 +74,8 @@
     (*i)->OnCursorVisibilityChanged(visible);
 }
 
-void DesktopNativeCursorManager::SetCursorSet(
-    ui::CursorSetType cursor_set,
+void DesktopNativeCursorManager::SetCursorSize(
+    ui::CursorSize cursor_size,
     wm::NativeCursorManagerDelegate* delegate) {
   NOTIMPLEMENTED();
 }
diff --git a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
index d7ba6daa..6f0342d 100644
--- a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
+++ b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
@@ -54,8 +54,8 @@
                  wm::NativeCursorManagerDelegate* delegate) override;
   void SetVisibility(bool visible,
                      wm::NativeCursorManagerDelegate* delegate) override;
-  void SetCursorSet(ui::CursorSetType cursor_set,
-                    wm::NativeCursorManagerDelegate* delegate) override;
+  void SetCursorSize(ui::CursorSize cursor_size,
+                     wm::NativeCursorManagerDelegate* delegate) override;
   void SetMouseEventsEnabled(
       bool enabled,
       wm::NativeCursorManagerDelegate* delegate) override;
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index a0394435..32a50e88 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -1069,7 +1069,7 @@
 
 void Widget::OnNativeWidgetCreated(bool desktop_widget) {
   if (is_top_level())
-    focus_manager_.reset(FocusManagerFactory::Create(this, desktop_widget));
+    focus_manager_ = FocusManagerFactory::Create(this, desktop_widget);
 
   native_widget_->InitModalType(widget_delegate_->GetModalType());
 
diff --git a/ui/wm/core/cursor_manager.cc b/ui/wm/core/cursor_manager.cc
index 839a22e..25d4854 100644
--- a/ui/wm/core/cursor_manager.cc
+++ b/ui/wm/core/cursor_manager.cc
@@ -24,7 +24,7 @@
   CursorState()
       : cursor_(ui::CursorType::kNone),
         visible_(true),
-        cursor_set_(ui::CURSOR_SET_NORMAL),
+        cursor_size_(ui::CursorSize::kNormal),
         mouse_events_enabled_(true),
         visible_on_mouse_events_enabled_(true) {}
 
@@ -38,9 +38,9 @@
     // Ignores the call when mouse events disabled.
   }
 
-  ui::CursorSetType cursor_set() const { return cursor_set_; }
-  void set_cursor_set(ui::CursorSetType cursor_set) {
-    cursor_set_ = cursor_set;
+  ui::CursorSize cursor_size() const { return cursor_size_; }
+  void set_cursor_size(ui::CursorSize cursor_size) {
+    cursor_size_ = cursor_size;
   }
 
   bool mouse_events_enabled() const { return mouse_events_enabled_; }
@@ -61,7 +61,7 @@
  private:
   gfx::NativeCursor cursor_;
   bool visible_;
-  ui::CursorSetType cursor_set_;
+  ui::CursorSize cursor_size_;
   bool mouse_events_enabled_;
 
   // The visibility to set when mouse events are enabled.
@@ -129,17 +129,17 @@
   return current_state_->visible();
 }
 
-void CursorManager::SetCursorSet(ui::CursorSetType cursor_set) {
-  state_on_unlock_->set_cursor_set(cursor_set);
-  if (GetCursorSet() != state_on_unlock_->cursor_set()) {
-    delegate_->SetCursorSet(state_on_unlock_->cursor_set(), this);
+void CursorManager::SetCursorSize(ui::CursorSize cursor_size) {
+  state_on_unlock_->set_cursor_size(cursor_size);
+  if (GetCursorSize() != state_on_unlock_->cursor_size()) {
+    delegate_->SetCursorSize(state_on_unlock_->cursor_size(), this);
     for (auto& observer : observers_)
-      observer.OnCursorSetChanged(cursor_set);
+      observer.OnCursorSizeChanged(cursor_size);
   }
 }
 
-ui::CursorSetType CursorManager::GetCursorSet() const {
-  return current_state_->cursor_set();
+ui::CursorSize CursorManager::GetCursorSize() const {
+  return current_state_->cursor_size();
 }
 
 void CursorManager::EnableMouseEvents() {
@@ -230,8 +230,8 @@
   current_state_->SetVisible(visible);
 }
 
-void CursorManager::CommitCursorSet(ui::CursorSetType cursor_set) {
-  current_state_->set_cursor_set(cursor_set);
+void CursorManager::CommitCursorSize(ui::CursorSize cursor_size) {
+  current_state_->set_cursor_size(cursor_size);
 }
 
 void CursorManager::CommitMouseEventsEnabled(bool enabled) {
diff --git a/ui/wm/core/cursor_manager.h b/ui/wm/core/cursor_manager.h
index 003d8740..929e1cf 100644
--- a/ui/wm/core/cursor_manager.h
+++ b/ui/wm/core/cursor_manager.h
@@ -49,8 +49,8 @@
   void ShowCursor() override;
   void HideCursor() override;
   bool IsCursorVisible() const override;
-  void SetCursorSet(ui::CursorSetType cursor_set) override;
-  ui::CursorSetType GetCursorSet() const override;
+  void SetCursorSize(ui::CursorSize cursor_size) override;
+  ui::CursorSize GetCursorSize() const override;
   void EnableMouseEvents() override;
   void DisableMouseEvents() override;
   bool IsMouseEventsEnabled() const override;
@@ -67,7 +67,7 @@
   // Overridden from NativeCursorManagerDelegate:
   void CommitCursor(gfx::NativeCursor cursor) override;
   void CommitVisibility(bool visible) override;
-  void CommitCursorSet(ui::CursorSetType cursor_set) override;
+  void CommitCursorSize(ui::CursorSize cursor_size) override;
   void CommitMouseEventsEnabled(bool enabled) override;
 
   std::unique_ptr<NativeCursorManager> delegate_;
diff --git a/ui/wm/core/cursor_manager_unittest.cc b/ui/wm/core/cursor_manager_unittest.cc
index 91e3367009..17e0603 100644
--- a/ui/wm/core/cursor_manager_unittest.cc
+++ b/ui/wm/core/cursor_manager_unittest.cc
@@ -35,9 +35,9 @@
     delegate->CommitMouseEventsEnabled(enabled);
   }
 
-  void SetCursorSet(ui::CursorSetType cursor_set,
-                    wm::NativeCursorManagerDelegate* delegate) override {
-    delegate->CommitCursorSet(cursor_set);
+  void SetCursorSize(ui::CursorSize cursor_size,
+                     wm::NativeCursorManagerDelegate* delegate) override {
+    delegate->CommitCursorSize(cursor_size);
   }
 };
 
@@ -153,24 +153,24 @@
   EXPECT_FALSE(cursor_manager_.IsMouseEventsEnabled());
 }
 
-TEST_F(CursorManagerTest, SetCursorSet) {
+TEST_F(CursorManagerTest, SetCursorSize) {
   wm::TestingCursorClientObserver observer;
   cursor_manager_.AddObserver(&observer);
 
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, observer.cursor_set());
+  EXPECT_EQ(ui::CursorSize::kNormal, cursor_manager_.GetCursorSize());
+  EXPECT_EQ(ui::CursorSize::kNormal, observer.cursor_size());
 
-  cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, observer.cursor_set());
+  cursor_manager_.SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_EQ(ui::CursorSize::kNormal, cursor_manager_.GetCursorSize());
+  EXPECT_EQ(ui::CursorSize::kNormal, observer.cursor_size());
 
-  cursor_manager_.SetCursorSet(ui::CURSOR_SET_LARGE);
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, cursor_manager_.GetCursorSet());
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, observer.cursor_set());
+  cursor_manager_.SetCursorSize(ui::CursorSize::kLarge);
+  EXPECT_EQ(ui::CursorSize::kLarge, cursor_manager_.GetCursorSize());
+  EXPECT_EQ(ui::CursorSize::kLarge, observer.cursor_size());
 
-  cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, cursor_manager_.GetCursorSet());
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, observer.cursor_set());
+  cursor_manager_.SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_EQ(ui::CursorSize::kNormal, cursor_manager_.GetCursorSize());
+  EXPECT_EQ(ui::CursorSize::kNormal, observer.cursor_size());
 }
 
 TEST_F(CursorManagerTest, IsMouseEventsEnabled) {
@@ -273,8 +273,8 @@
   EXPECT_FALSE(observer_b.did_visibility_change());
   EXPECT_FALSE(observer_a.is_cursor_visible());
   EXPECT_FALSE(observer_b.is_cursor_visible());
-  EXPECT_FALSE(observer_a.did_cursor_set_change());
-  EXPECT_FALSE(observer_b.did_cursor_set_change());
+  EXPECT_FALSE(observer_a.did_cursor_size_change());
+  EXPECT_FALSE(observer_b.did_cursor_size_change());
 
   // Hide the cursor using HideCursor().
   cursor_manager_.HideCursor();
@@ -284,11 +284,11 @@
   EXPECT_FALSE(observer_b.is_cursor_visible());
 
   // Set the cursor set.
-  cursor_manager_.SetCursorSet(ui::CURSOR_SET_LARGE);
-  EXPECT_TRUE(observer_a.did_cursor_set_change());
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, observer_a.cursor_set());
-  EXPECT_TRUE(observer_b.did_cursor_set_change());
-  EXPECT_EQ(ui::CURSOR_SET_LARGE, observer_b.cursor_set());
+  cursor_manager_.SetCursorSize(ui::CursorSize::kLarge);
+  EXPECT_TRUE(observer_a.did_cursor_size_change());
+  EXPECT_EQ(ui::CursorSize::kLarge, observer_a.cursor_size());
+  EXPECT_TRUE(observer_b.did_cursor_size_change());
+  EXPECT_EQ(ui::CursorSize::kLarge, observer_b.cursor_size());
 
   // Show the cursor using ShowCursor().
   observer_a.reset();
@@ -312,10 +312,10 @@
   EXPECT_FALSE(observer_a.is_cursor_visible());
 
   // Set back the cursor set to normal.
-  cursor_manager_.SetCursorSet(ui::CURSOR_SET_NORMAL);
-  EXPECT_TRUE(observer_a.did_cursor_set_change());
-  EXPECT_EQ(ui::CURSOR_SET_NORMAL, observer_a.cursor_set());
-  EXPECT_FALSE(observer_b.did_cursor_set_change());
+  cursor_manager_.SetCursorSize(ui::CursorSize::kNormal);
+  EXPECT_TRUE(observer_a.did_cursor_size_change());
+  EXPECT_EQ(ui::CursorSize::kNormal, observer_a.cursor_size());
+  EXPECT_FALSE(observer_b.did_cursor_size_change());
 
   // Show the cursor using ShowCursor().
   observer_a.reset();
diff --git a/ui/wm/core/native_cursor_manager.h b/ui/wm/core/native_cursor_manager.h
index c3be2475..170cbb1 100644
--- a/ui/wm/core/native_cursor_manager.h
+++ b/ui/wm/core/native_cursor_manager.h
@@ -43,9 +43,8 @@
     NativeCursorManagerDelegate* delegate) = 0;
 
   // A request to set the cursor set.
-  virtual void SetCursorSet(
-      ui::CursorSetType cursor_set,
-      NativeCursorManagerDelegate* delegate) = 0;
+  virtual void SetCursorSize(ui::CursorSize cursor_size,
+                             NativeCursorManagerDelegate* delegate) = 0;
 
   // A request to set whether mouse events are disabled. At minimum,
   // implementer should call NativeCursorManagerDelegate::
diff --git a/ui/wm/core/native_cursor_manager_delegate.h b/ui/wm/core/native_cursor_manager_delegate.h
index aad9825..c84ba5b 100644
--- a/ui/wm/core/native_cursor_manager_delegate.h
+++ b/ui/wm/core/native_cursor_manager_delegate.h
@@ -24,7 +24,7 @@
 
   virtual void CommitCursor(gfx::NativeCursor cursor) = 0;
   virtual void CommitVisibility(bool visible) = 0;
-  virtual void CommitCursorSet(ui::CursorSetType cursor_set) = 0;
+  virtual void CommitCursorSize(ui::CursorSize cursor_size) = 0;
   virtual void CommitMouseEventsEnabled(bool enabled) = 0;
 };
 
diff --git a/ui/wm/test/testing_cursor_client_observer.cc b/ui/wm/test/testing_cursor_client_observer.cc
index 00d4e1b..c8a286f 100644
--- a/ui/wm/test/testing_cursor_client_observer.cc
+++ b/ui/wm/test/testing_cursor_client_observer.cc
@@ -9,13 +9,13 @@
 TestingCursorClientObserver::TestingCursorClientObserver()
     : cursor_visibility_(false),
       did_visibility_change_(false),
-      cursor_set_(ui::CURSOR_SET_NORMAL),
-      did_cursor_set_change_(false) {}
+      cursor_size_(ui::CursorSize::kNormal),
+      did_cursor_size_change_(false) {}
 
 void TestingCursorClientObserver::reset() {
   cursor_visibility_ = did_visibility_change_ = false;
-  cursor_set_ = ui::CURSOR_SET_NORMAL;
-  did_cursor_set_change_ = false;
+  cursor_size_ = ui::CursorSize::kNormal;
+  did_cursor_size_change_ = false;
 }
 
 void TestingCursorClientObserver::OnCursorVisibilityChanged(bool is_visible) {
@@ -23,10 +23,10 @@
   did_visibility_change_ = true;
 }
 
-void TestingCursorClientObserver::OnCursorSetChanged(
-    ui::CursorSetType cursor_set) {
-  cursor_set_ = cursor_set;
-  did_cursor_set_change_ = true;
+void TestingCursorClientObserver::OnCursorSizeChanged(
+    ui::CursorSize cursor_size) {
+  cursor_size_ = cursor_size;
+  did_cursor_size_change_ = true;
 }
 
 }  // namespace wm
diff --git a/ui/wm/test/testing_cursor_client_observer.h b/ui/wm/test/testing_cursor_client_observer.h
index 1b0bb203..2698935 100644
--- a/ui/wm/test/testing_cursor_client_observer.h
+++ b/ui/wm/test/testing_cursor_client_observer.h
@@ -15,18 +15,18 @@
 
   bool is_cursor_visible() const { return cursor_visibility_; }
   bool did_visibility_change() const { return did_visibility_change_; }
-  ui::CursorSetType cursor_set() const { return cursor_set_; }
-  bool did_cursor_set_change() const { return did_cursor_set_change_; }
+  ui::CursorSize cursor_size() const { return cursor_size_; }
+  bool did_cursor_size_change() const { return did_cursor_size_change_; }
 
   // Overridden from aura::client::CursorClientObserver:
   void OnCursorVisibilityChanged(bool is_visible) override;
-  void OnCursorSetChanged(ui::CursorSetType cursor_set) override;
+  void OnCursorSizeChanged(ui::CursorSize cursor_size) override;
 
  private:
   bool cursor_visibility_;
   bool did_visibility_change_;
-  ui::CursorSetType cursor_set_;
-  bool did_cursor_set_change_;
+  ui::CursorSize cursor_size_;
+  bool did_cursor_size_change_;
 
   DISALLOW_COPY_AND_ASSIGN(TestingCursorClientObserver);
 };