diff --git a/DEPS b/DEPS
index 3dc57fe..a7300f2d4 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': '5c85b29ca3c3d887e9fbf660311f9e94a0e0d3fa',
+  'v8_revision': '1dc40944fe81cbabc94f96e3a06595da2d093657',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '33dd830890d38f9083b732cd908ef082f1d89d65',
+  'pdfium_revision': 'aea80dcc0abc0c310316fa502f91a359bc684758',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '0327c967ed7f2960c26f33ef34ba3f95b6d69da7',
+  'catapult_revision': '65e2bf234545de3acd7f8f1bbda4f0e9094e46f4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/fast_ink/fast_ink_view.cc b/ash/fast_ink/fast_ink_view.cc
index 236aee2..8f1a1c9 100644
--- a/ash/fast_ink/fast_ink_view.cc
+++ b/ash/fast_ink/fast_ink_view.cc
@@ -340,9 +340,13 @@
 
   cc::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  quad_state->quad_layer_rect = quad_rect;
-  quad_state->visible_quad_layer_rect = quad_rect;
-  quad_state->opacity = 1.0f;
+  quad_state->SetAll(
+      /*quad_to_target_transform=*/gfx::Transform(),
+      /*quad_layer_rect=*/quad_rect,
+      /*visible_quad_layer_rect=*/quad_rect,
+      /*clip_rect=*/gfx::Rect(),
+      /*is_clipped=*/false, /*opacity=*/1.f,
+      /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
 
   cc::CompositorFrame frame;
   // TODO(eseckler): FastInkView should use BeginFrames and set the ack
diff --git a/ash/host/ash_window_tree_host.h b/ash/host/ash_window_tree_host.h
index 207045a..df9bf9d3 100644
--- a/ash/host/ash_window_tree_host.h
+++ b/ash/host/ash_window_tree_host.h
@@ -34,13 +34,8 @@
   static std::unique_ptr<AshWindowTreeHost> Create(
       const AshWindowTreeHostInitParams& init_params);
 
-  // Clips the cursor to the bounds of the root window until UnConfineCursor().
-  // We would like to be able to confine the cursor to that window. However,
-  // currently, we do not have such functionality in X. So we just confine
-  // to the root window. This is ok because this option is currently only
-  // being used in fullscreen mode, so root_window bounds = window bounds.
+  // Clips the cursor to the bounds of the root window.
   virtual bool ConfineCursorToRootWindow() = 0;
-  virtual void UnConfineCursor() = 0;
 
   virtual void SetRootWindowTransformer(
       std::unique_ptr<RootWindowTransformer> transformer) = 0;
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc
index 438f7560..6878cee4 100644
--- a/ash/host/ash_window_tree_host_platform.cc
+++ b/ash/host/ash_window_tree_host_platform.cc
@@ -48,10 +48,6 @@
   return true;
 }
 
-void AshWindowTreeHostPlatform::UnConfineCursor() {
-  NOTIMPLEMENTED();
-}
-
 #if defined(USE_OZONE)
 void AshWindowTreeHostPlatform::SetCursorConfig(
     const display::Display& display,
diff --git a/ash/host/ash_window_tree_host_platform.h b/ash/host/ash_window_tree_host_platform.h
index 27578576..63c89390 100644
--- a/ash/host/ash_window_tree_host_platform.h
+++ b/ash/host/ash_window_tree_host_platform.h
@@ -26,7 +26,6 @@
 
   // AshWindowTreeHost:
   bool ConfineCursorToRootWindow() override;
-  void UnConfineCursor() override;
   void SetRootWindowTransformer(
       std::unique_ptr<RootWindowTransformer> transformer) override;
   gfx::Insets GetHostInsets() const override;
diff --git a/ash/mus/ash_window_tree_host_mus.cc b/ash/mus/ash_window_tree_host_mus.cc
index 90f2c32..066f8c6 100644
--- a/ash/mus/ash_window_tree_host_mus.cc
+++ b/ash/mus/ash_window_tree_host_mus.cc
@@ -36,10 +36,6 @@
   return true;
 }
 
-void AshWindowTreeHostMus::UnConfineCursor() {
-  NOTIMPLEMENTED();
-}
-
 void AshWindowTreeHostMus::SetRootWindowTransformer(
     std::unique_ptr<RootWindowTransformer> transformer) {
   transformer_helper_->SetRootWindowTransformer(std::move(transformer));
diff --git a/ash/mus/ash_window_tree_host_mus.h b/ash/mus/ash_window_tree_host_mus.h
index 75b86ea9..f441899 100644
--- a/ash/mus/ash_window_tree_host_mus.h
+++ b/ash/mus/ash_window_tree_host_mus.h
@@ -21,7 +21,6 @@
 
   // AshWindowTreeHost:
   bool ConfineCursorToRootWindow() override;
-  void UnConfineCursor() override;
   void SetRootWindowTransformer(
       std::unique_ptr<RootWindowTransformer> transformer) override;
   gfx::Insets GetHostInsets() const override;
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc
index 612d1cf..15bfcb3 100644
--- a/ash/shelf/shelf.cc
+++ b/ash/shelf/shelf.cc
@@ -120,6 +120,8 @@
   aura::Window* status_container =
       root->GetChildById(kShellWindowId_StatusContainer);
   shelf_widget_->CreateStatusAreaWidget(status_container);
+
+  Shell::Get()->window_tree_host_manager()->AddObserver(this);
 }
 
 void Shelf::ShutdownShelfWidget() {
@@ -128,7 +130,11 @@
 }
 
 void Shelf::DestroyShelfWidget() {
-  shelf_widget_.reset();
+  // May be called multiple times during shutdown.
+  if (shelf_widget_) {
+    shelf_widget_.reset();
+    Shell::Get()->window_tree_host_manager()->RemoveObserver(this);
+  }
 }
 
 void Shelf::NotifyShelfInitialized() {
@@ -365,4 +371,19 @@
     observer.OnBackgroundTypeChanged(background_type, change_type);
 }
 
+void Shelf::OnWindowTreeHostReusedForDisplay(
+    AshWindowTreeHost* window_tree_host,
+    const display::Display& display) {
+  // See comment in OnWindowTreeHostsSwappedDisplays().
+  NotifyShelfInitialized();
+}
+
+void Shelf::OnWindowTreeHostsSwappedDisplays(AshWindowTreeHost* host1,
+                                             AshWindowTreeHost* host2) {
+  // The display id for this shelf instance may have changed, so request
+  // re-initialization to fetch the alignment and auto-hide state from prefs.
+  // See http://crbug.com/748291
+  NotifyShelfInitialized();
+}
+
 }  // namespace ash
diff --git a/ash/shelf/shelf.h b/ash/shelf/shelf.h
index e9bfc15..0308cc1 100644
--- a/ash/shelf/shelf.h
+++ b/ash/shelf/shelf.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "ash/display/window_tree_host_manager.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/shelf/shelf_layout_manager_observer.h"
 #include "ash/shelf/shelf_locking_manager.h"
@@ -40,7 +41,8 @@
 // Controller for the shelf state. One per display, because each display might
 // have different shelf alignment, autohide, etc. Exists for the lifetime of the
 // root window controller.
-class ASH_EXPORT Shelf : public ShelfLayoutManagerObserver {
+class ASH_EXPORT Shelf : public ShelfLayoutManagerObserver,
+                         public WindowTreeHostManager::Observer {
  public:
   Shelf();
   ~Shelf() override;
@@ -146,6 +148,13 @@
   void OnBackgroundUpdated(ShelfBackgroundType background_type,
                            AnimationChangeType change_type) override;
 
+  // WindowTreeHostManager::Observer:
+  void OnWindowTreeHostReusedForDisplay(
+      AshWindowTreeHost* window_tree_host,
+      const display::Display& display) override;
+  void OnWindowTreeHostsSwappedDisplays(AshWindowTreeHost* host1,
+                                        AshWindowTreeHost* host2) override;
+
  private:
   class AutoHideEventHandler;
   friend class ShelfLayoutManagerTest;
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc
index 53cbaa760..8963ead 100644
--- a/ash/shelf/shelf_unittest.cc
+++ b/ash/shelf/shelf_unittest.cc
@@ -5,15 +5,55 @@
 #include <utility>
 
 #include "ash/public/cpp/shelf_model.h"
+#include "ash/root_window_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_button.h"
+#include "ash/shelf/shelf_controller.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
+#include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 
 namespace ash {
+namespace {
+
+Shelf* GetShelfForDisplay(int64_t display_id) {
+  return Shell::GetRootWindowControllerWithDisplayId(display_id)->shelf();
+}
+
+// Tracks shelf initialization display ids.
+class ShelfInitializationObserver : public mojom::ShelfObserver {
+ public:
+  ShelfInitializationObserver() = default;
+  ~ShelfInitializationObserver() override = default;
+
+  // mojom::ShelfObserver:
+  void OnShelfInitialized(int64_t display_id) override {
+    shelf_initialized_display_ids_.push_back(display_id);
+  }
+  void OnAlignmentChanged(ShelfAlignment alignment,
+                          int64_t display_id) override {}
+  void OnAutoHideBehaviorChanged(ShelfAutoHideBehavior auto_hide,
+                                 int64_t display_id) override {}
+  void OnShelfItemAdded(int32_t, const ShelfItem&) override {}
+  void OnShelfItemRemoved(const ShelfID&) override {}
+  void OnShelfItemMoved(const ShelfID&, int32_t) override {}
+  void OnShelfItemUpdated(const ShelfItem&) override {}
+  void OnShelfItemDelegateChanged(const ShelfID&,
+                                  mojom::ShelfItemDelegatePtr) override {}
+
+  std::vector<int64_t> shelf_initialized_display_ids_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShelfInitializationObserver);
+};
+
+}  // namespace
 
 class ShelfTest : public AshTestBase {
  public:
@@ -110,4 +150,65 @@
   EXPECT_FALSE(shelf_widget->IsShowingOverflowBubble());
 }
 
+// Verifies that shelves are re-initialized after display swap, which will
+// reload their alignment prefs. http://crbug.com/748291
+TEST_F(ShelfTest, ShelfInitializedOnDisplaySwap) {
+  ShelfController* controller = Shell::Get()->shelf_controller();
+  ShelfInitializationObserver observer;
+  mojom::ShelfObserverAssociatedPtr observer_ptr;
+  mojo::AssociatedBinding<mojom::ShelfObserver> binding(
+      &observer, mojo::MakeIsolatedRequest(&observer_ptr));
+  controller->AddObserver(observer_ptr.PassInterface());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(0u, observer.shelf_initialized_display_ids_.size());
+
+  // Simulate adding an external display at the lock screen. The shelf on the
+  // new display is initialized.
+  GetSessionControllerClient()->RequestLockScreen();
+  UpdateDisplay("1024x768,800x600");
+  base::RunLoop().RunUntilIdle();
+  const int64_t internal_display_id = GetPrimaryDisplay().id();
+  const int64_t external_display_id = GetSecondaryDisplay().id();
+  ASSERT_EQ(1u, observer.shelf_initialized_display_ids_.size());
+  EXPECT_EQ(external_display_id, observer.shelf_initialized_display_ids_[0]);
+  observer.shelf_initialized_display_ids_.clear();
+
+  // Simulate the external display becoming the primary display. Each shelf is
+  // re-initialized.
+  SwapPrimaryDisplay();
+  base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(2u, observer.shelf_initialized_display_ids_.size());
+  EXPECT_TRUE(base::ContainsValue(observer.shelf_initialized_display_ids_,
+                                  internal_display_id));
+  EXPECT_TRUE(base::ContainsValue(observer.shelf_initialized_display_ids_,
+                                  external_display_id));
+
+  // Simulate shelf state being set from prefs, which is how Chrome responds to
+  // the initialization request.
+  controller->SetAlignment(SHELF_ALIGNMENT_LEFT, internal_display_id);
+  controller->SetAlignment(SHELF_ALIGNMENT_RIGHT, external_display_id);
+  controller->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
+                                  internal_display_id);
+  controller->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
+                                  external_display_id);
+
+  // Shelf is still locked to bottom because screen is locked.
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED,
+            GetShelfForDisplay(internal_display_id)->alignment());
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED,
+            GetShelfForDisplay(external_display_id)->alignment());
+
+  // After screen unlock all shelves should have an alignment.
+  GetSessionControllerClient()->UnlockScreen();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(SHELF_ALIGNMENT_LEFT,
+            GetShelfForDisplay(internal_display_id)->alignment());
+  EXPECT_EQ(SHELF_ALIGNMENT_RIGHT,
+            GetShelfForDisplay(external_display_id)->alignment());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
+            GetShelfForDisplay(internal_display_id)->auto_hide_behavior());
+  EXPECT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS,
+            GetShelfForDisplay(external_display_id)->auto_hide_behavior());
+}
+
 }  // namespace ash
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 362db328..9896cb5 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -79,11 +79,6 @@
   return display::Screen::GetScreen()->GetPrimaryDisplay().id();
 }
 
-}  // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// ShelfObserver::OnShelfIconPositionsChanged tests.
-
 class TestShelfObserver : public ShelfObserver {
  public:
   explicit TestShelfObserver(Shelf* shelf) : shelf_(shelf) {
@@ -118,6 +113,11 @@
   DISALLOW_COPY_AND_ASSIGN(TestShelfObserver);
 };
 
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ShelfObserver::OnShelfIconPositionsChanged tests.
+
 class ShelfObserverIconTest : public AshTestBase {
  public:
   ShelfObserverIconTest() {}
diff --git a/ash/system/system_notifier.cc b/ash/system/system_notifier.cc
index 09bb4747..b094f7a 100644
--- a/ash/system/system_notifier.cc
+++ b/ash/system/system_notifier.cc
@@ -32,7 +32,8 @@
     kNotifierDisk, kNotifierLocale, kNotifierMultiProfileFirstRun,
     kNotifierNetwork, kNotifierNetworkPortalDetector, kNotifierScreenshot,
     kNotifierScreenCapture, kNotifierScreenShare, kNotifierSessionLengthTimeout,
-    kNotifierSms, kNotifierSupervisedUser, kNotifierWebUsb, kNotifierWifiToggle,
+    kNotifierSms, kNotifierSupervisedUser, kNotifierTether, kNotifierWebUsb,
+    kNotifierWifiToggle,
     // Note: Order doesn't matter here, so keep this in alphabetic order, don't
     // just add your stuff at the end!
     NULL};
@@ -76,6 +77,7 @@
 const char kNotifierSessionLengthTimeout[] = "ash.session-length-timeout";
 const char kNotifierSms[] = "ash.sms";
 const char kNotifierSupervisedUser[] = "ash.locally-managed-user";
+const char kNotifierTether[] = "ash.tether";
 const char kNotifierWebUsb[] = "ash.webusb";
 const char kNotifierWifiToggle[] = "ash.wifi-toggle";
 
diff --git a/ash/system/system_notifier.h b/ash/system/system_notifier.h
index 1fa4832a..ba5a5fa9 100644
--- a/ash/system/system_notifier.h
+++ b/ash/system/system_notifier.h
@@ -39,6 +39,7 @@
 ASH_EXPORT extern const char kNotifierSessionLengthTimeout[];
 ASH_EXPORT extern const char kNotifierSms[];
 ASH_EXPORT extern const char kNotifierSupervisedUser[];
+ASH_EXPORT extern const char kNotifierTether[];
 ASH_EXPORT extern const char kNotifierWebUsb[];
 ASH_EXPORT extern const char kNotifierWifiToggle[];
 
diff --git a/base/logging.cc b/base/logging.cc
index 1c204014..92aa256 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -872,9 +872,9 @@
   if (len) {
     // Messages returned by system end with line breaks.
     return base::CollapseWhitespaceASCII(msgbuf, true) +
-        base::StringPrintf(" (0x%X)", error_code);
+           base::StringPrintf(" (0x%lX)", error_code);
   }
-  return base::StringPrintf("Error (0x%X) while retrieving error. (0x%X)",
+  return base::StringPrintf("Error (0x%lX) while retrieving error. (0x%lX)",
                             GetLastError(), error_code);
 }
 #elif defined(OS_POSIX)
diff --git a/base/memory/shared_memory_fuchsia.cc b/base/memory/shared_memory_fuchsia.cc
index 9ad212f..c622308c 100644
--- a/base/memory/shared_memory_fuchsia.cc
+++ b/base/memory/shared_memory_fuchsia.cc
@@ -4,6 +4,8 @@
 
 #include "base/memory/shared_memory.h"
 
+#include <limits>
+
 #include <magenta/process.h>
 #include <magenta/rights.h>
 #include <magenta/syscalls.h>
@@ -36,6 +38,12 @@
   handle.Close();
 }
 
+// static
+size_t SharedMemory::GetHandleLimit() {
+  // No documented limit, currently.
+  return std::numeric_limits<size_t>::max();
+}
+
 bool SharedMemory::CreateAndMapAnonymous(size_t size) {
   return CreateAnonymous(size) && Map(size);
 }
diff --git a/base/native_library_win.cc b/base/native_library_win.cc
index 68ff3d1f..c281fbf 100644
--- a/base/native_library_win.cc
+++ b/base/native_library_win.cc
@@ -147,7 +147,7 @@
 }  // namespace
 
 std::string NativeLibraryLoadError::ToString() const {
-  return StringPrintf("%u", code);
+  return StringPrintf("%lu", code);
 }
 
 // static
diff --git a/build/config/mac/mac_sdk_overrides.gni b/build/config/mac/mac_sdk_overrides.gni
index 3632678..2c89492 100644
--- a/build/config/mac/mac_sdk_overrides.gni
+++ b/build/config/mac/mac_sdk_overrides.gni
@@ -9,7 +9,7 @@
 declare_args() {
   # Minimum supported version of the Mac SDK.
   if (_sdk_min_from_env == "") {
-    mac_sdk_min = "10.12"
+    mac_sdk_min = "10.10"
   } else {
     mac_sdk_min = _sdk_min_from_env
   }
@@ -18,5 +18,5 @@
 # Always assert that mac_sdk_min is used on non-macOS platforms to prevent
 # unused args warnings.
 if (!is_mac) {
-  assert(mac_sdk_min == "10.12" || true)
+  assert(mac_sdk_min == "10.10" || true)
 }
diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc
index b93b9ec5..e67a1ce 100644
--- a/cc/animation/animation.cc
+++ b/cc/animation/animation.cc
@@ -8,6 +8,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/animation/animation_curve.h"
 
@@ -267,4 +268,12 @@
   }
 }
 
+std::string Animation::ToString() const {
+  return base::StringPrintf(
+      "Animation{id=%d, group=%d, target_property_id=%d, "
+      "run_state=%s}",
+      id_, group_, target_property_id_,
+      s_runStateNames[static_cast<int>(run_state_)]);
+}
+
 }  // namespace cc
diff --git a/cc/animation/animation.h b/cc/animation/animation.h
index 4057c377..321286a 100644
--- a/cc/animation/animation.h
+++ b/cc/animation/animation.h
@@ -145,6 +145,8 @@
 
   void PushPropertiesTo(Animation* other) const;
 
+  std::string ToString() const;
+
   void set_is_impl_only(bool is_impl_only) { is_impl_only_ = is_impl_only; }
   bool is_impl_only() const { return is_impl_only_; }
 
diff --git a/cc/animation/animation_player.cc b/cc/animation/animation_player.cc
index def3e626..755da69 100644
--- a/cc/animation/animation_player.cc
+++ b/cc/animation/animation_player.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
 #include "cc/animation/animation_delegate.h"
 #include "cc/animation/animation_events.h"
 #include "cc/animation/animation_host.h"
@@ -1202,4 +1203,21 @@
   scroll_offset_animation_was_interrupted_ = false;
 }
 
+std::string AnimationPlayer::ToString() const {
+  return base::StringPrintf(
+      "AnimationPlayer{id=%d, element_id=(%lu), animations=[%s]}", id_,
+      static_cast<unsigned long>(element_id_.id_),
+      AnimationsToString().c_str());
+}
+
+std::string AnimationPlayer::AnimationsToString() const {
+  std::string str;
+  for (size_t i = 0; i < animations_.size(); i++) {
+    if (i > 0)
+      str.append(", ");
+    str.append(animations_[i]->ToString());
+  }
+  return str;
+}
+
 }  // namespace cc
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h
index c2df51f..b2a52ac 100644
--- a/cc/animation/animation_player.h
+++ b/cc/animation/animation_player.h
@@ -175,6 +175,8 @@
     return scroll_offset_animation_was_interrupted_;
   }
 
+  std::string ToString() const;
+
  private:
   friend class base::RefCounted<AnimationPlayer>;
 
@@ -200,6 +202,8 @@
       AnimationPlayer* animation_player_impl) const;
   void PushPropertiesToImplThread(AnimationPlayer* animation_player_impl);
 
+  std::string AnimationsToString() const;
+
   using Animations = std::vector<std::unique_ptr<Animation>>;
   Animations animations_;
 
diff --git a/cc/animation/animation_player_unittest.cc b/cc/animation/animation_player_unittest.cc
index 7b4b82d8..7f5f016 100644
--- a/cc/animation/animation_player_unittest.cc
+++ b/cc/animation/animation_player_unittest.cc
@@ -410,5 +410,30 @@
   EXPECT_EQ(player_impl_->element_id(), new_element_id);
 }
 
+TEST_F(AnimationPlayerTest, ToString) {
+  player_->AttachElement(element_id_);
+  EXPECT_EQ("AnimationPlayer{id=2, element_id=(1), animations=[]}",
+            player_->ToString());
+
+  player_->AddAnimation(
+      Animation::Create(base::MakeUnique<FakeFloatAnimationCurve>(15), 42, 73,
+                        TargetProperty::OPACITY));
+  EXPECT_EQ(
+      "AnimationPlayer{id=2, element_id=(1), animations=[Animation{id=42, "
+      "group=73, target_property_id=1, "
+      "run_state=WAITING_FOR_TARGET_AVAILABILITY}]}",
+      player_->ToString());
+
+  player_->AddAnimation(
+      Animation::Create(base::MakeUnique<FakeFloatAnimationCurve>(18), 45, 76,
+                        TargetProperty::BOUNDS));
+  EXPECT_EQ(
+      "AnimationPlayer{id=2, element_id=(1), animations=[Animation{id=42, "
+      "group=73, target_property_id=1, "
+      "run_state=WAITING_FOR_TARGET_AVAILABILITY}, Animation{id=45, group=76, "
+      "target_property_id=5, run_state=WAITING_FOR_TARGET_AVAILABILITY}]}",
+      player_->ToString());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/animation/animation_unittest.cc b/cc/animation/animation_unittest.cc
index eaeb6fb..8f4d22a 100644
--- a/cc/animation/animation_unittest.cc
+++ b/cc/animation/animation_unittest.cc
@@ -1002,5 +1002,14 @@
   EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
 }
 
+TEST(AnimationTest, ToString) {
+  EXPECT_EQ(
+      "Animation{id=42, group=73, target_property_id=1, "
+      "run_state=WAITING_FOR_TARGET_AVAILABILITY}",
+      Animation::Create(base::MakeUnique<FakeFloatAnimationCurve>(15), 42, 73,
+                        TargetProperty::OPACITY)
+          ->ToString());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/paint/paint_flags.cc b/cc/paint/paint_flags.cc
index cd3be36..3f1027c 100644
--- a/cc/paint/paint_flags.cc
+++ b/cc/paint/paint_flags.cc
@@ -4,6 +4,8 @@
 
 #include "cc/paint/paint_flags.h"
 
+#include "cc/paint/paint_op_buffer.h"
+
 namespace {
 
 static bool affects_alpha(const SkColorFilter* cf) {
@@ -122,4 +124,8 @@
   return paint;
 }
 
+bool PaintFlags::IsValid() const {
+  return PaintOp::IsValidPaintFlagsSkBlendMode(getBlendMode());
+}
+
 }  // namespace cc
diff --git a/cc/paint/paint_flags.h b/cc/paint/paint_flags.h
index 49b66a96..f652f90 100644
--- a/cc/paint/paint_flags.h
+++ b/cc/paint/paint_flags.h
@@ -217,6 +217,8 @@
 
   SkPaint ToSkPaint() const;
 
+  bool IsValid() const;
+
  private:
   friend class PaintOpReader;
   friend class PaintOpWriter;
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index 38ef159..a53e24e7 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -223,6 +223,7 @@
     static_assert(
         !T::kHasPaintFlags,
         "This function should not be used for a PaintOp that has PaintFlags");
+    DCHECK(op->IsValid());
     NOTREACHED();
   }
   static void Raster(const T* op,
@@ -231,6 +232,7 @@
     static_assert(
         !T::kHasPaintFlags,
         "This function should not be used for a PaintOp that has PaintFlags");
+    DCHECK(op->IsValid());
     T::Raster(op, canvas, params);
   }
 };
@@ -243,6 +245,7 @@
                               const PlaybackParams& params) {
     static_assert(T::kHasPaintFlags,
                   "This function expects the PaintOp to have PaintFlags");
+    DCHECK(op->IsValid());
     T::RasterWithFlags(op, flags, canvas, params);
   }
 
@@ -251,6 +254,7 @@
                      const PlaybackParams& params) {
     static_assert(T::kHasPaintFlags,
                   "This function expects the PaintOp to have PaintFlags");
+    DCHECK(op->IsValid());
     T::RasterWithFlags(op, &op->flags, canvas, params);
   }
 };
@@ -742,6 +746,8 @@
   memcpy(output, input, sizeof(T));
 
   T* op = reinterpret_cast<T*>(output);
+  if (!op->IsValid())
+    return nullptr;
   // Type and skip were already read once, so could have been changed.
   // Don't trust them and clobber them with something valid.
   UpdateTypeAndSkip(op);
@@ -759,7 +765,7 @@
   helper.Read(&op->annotation_type);
   helper.Read(&op->rect);
   helper.Read(&op->data);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~AnnotateOp();
     return nullptr;
   }
@@ -787,7 +793,7 @@
   helper.Read(&op->path);
   helper.Read(&op->op);
   helper.Read(&op->antialias);
-  if (!helper.valid() || !IsValidSkClipOp(op->op)) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~ClipPathOp();
     return nullptr;
   }
@@ -800,18 +806,14 @@
                                  size_t input_size,
                                  void* output,
                                  size_t output_size) {
-  ClipRectOp* op =
-      SimpleDeserialize<ClipRectOp>(input, input_size, output, output_size);
-  return op && IsValidSkClipOp(op->op) ? op : nullptr;
+  return SimpleDeserialize<ClipRectOp>(input, input_size, output, output_size);
 }
 
 PaintOp* ClipRRectOp::Deserialize(const void* input,
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
-  ClipRRectOp* op =
-      SimpleDeserialize<ClipRRectOp>(input, input_size, output, output_size);
-  return op && IsValidSkClipOp(op->op) ? op : nullptr;
+  return SimpleDeserialize<ClipRRectOp>(input, input_size, output, output_size);
 }
 
 PaintOp* ConcatOp::Deserialize(const void* input,
@@ -834,7 +836,7 @@
   helper.Read(&op->start_angle);
   helper.Read(&op->sweep_angle);
   helper.Read(&op->use_center);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawArcOp();
     return nullptr;
   }
@@ -854,7 +856,7 @@
   helper.Read(&op->cx);
   helper.Read(&op->cy);
   helper.Read(&op->radius);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawCircleOp();
     return nullptr;
   }
@@ -866,9 +868,7 @@
                                   size_t input_size,
                                   void* output,
                                   size_t output_size) {
-  DrawColorOp* op =
-      SimpleDeserialize<DrawColorOp>(input, input_size, output, output_size);
-  return op && IsValidDrawColorSkBlendMode(op->mode) ? op : nullptr;
+  return SimpleDeserialize<DrawColorOp>(input, input_size, output, output_size);
 }
 
 PaintOp* DrawDRRectOp::Deserialize(const void* input,
@@ -882,7 +882,7 @@
   helper.Read(&op->flags);
   helper.Read(&op->outer);
   helper.Read(&op->inner);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawDRRectOp();
     return nullptr;
   }
@@ -902,7 +902,7 @@
   helper.Read(&op->image);
   helper.Read(&op->left);
   helper.Read(&op->top);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawImageOp();
     return nullptr;
   }
@@ -923,7 +923,7 @@
   helper.Read(&op->src);
   helper.Read(&op->dst);
   helper.Read(&op->constraint);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawImageRectOp();
     return nullptr;
   }
@@ -941,7 +941,7 @@
   PaintOpReader helper(input, input_size);
   helper.Read(&op->flags);
   helper.Read(&op->rect);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawIRectOp();
     return nullptr;
   }
@@ -962,7 +962,7 @@
   helper.Read(&op->y0);
   helper.Read(&op->x1);
   helper.Read(&op->y1);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawLineOp();
     return nullptr;
   }
@@ -980,7 +980,7 @@
   PaintOpReader helper(input, input_size);
   helper.Read(&op->flags);
   helper.Read(&op->oval);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawOvalOp();
     return nullptr;
   }
@@ -998,7 +998,7 @@
   PaintOpReader helper(input, input_size);
   helper.Read(&op->flags);
   helper.Read(&op->path);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawPathOp();
     return nullptr;
   }
@@ -1027,7 +1027,7 @@
     helper.ReadArray(op->count, op->GetArray());
     helper.ReadData(op->bytes, op->GetData());
   }
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawPosTextOp();
     return nullptr;
   }
@@ -1059,7 +1059,7 @@
   PaintOpReader helper(input, input_size);
   helper.Read(&op->flags);
   helper.Read(&op->rect);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawRectOp();
     return nullptr;
   }
@@ -1077,7 +1077,7 @@
   PaintOpReader helper(input, input_size);
   helper.Read(&op->flags);
   helper.Read(&op->rrect);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawRRectOp();
     return nullptr;
   }
@@ -1099,7 +1099,7 @@
   helper.Read(&op->bytes);
   if (helper.valid())
     helper.ReadData(op->bytes, op->GetData());
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawTextOp();
     return nullptr;
   }
@@ -1122,7 +1122,7 @@
   helper.Read(&op->x);
   helper.Read(&op->y);
   helper.Read(&op->blob);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~DrawTextBlobOp();
     return nullptr;
   }
@@ -1168,7 +1168,7 @@
   PaintOpReader helper(input, input_size);
   helper.Read(&op->flags);
   helper.Read(&op->bounds);
-  if (!helper.valid()) {
+  if (!helper.valid() || !op->IsValid()) {
     op->~SaveLayerOp();
     return nullptr;
   }
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index 3a8035f5..3d600a9 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -333,6 +333,7 @@
   static void Raster(const AnnotateOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   PaintCanvas::AnnotationType annotation_type;
@@ -353,6 +354,7 @@
   static void Raster(const ClipDeviceRectOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return IsValidSkClipOp(op); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkIRect device_rect;
@@ -368,6 +370,7 @@
   static void Raster(const ClipPathOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return IsValidSkClipOp(op); }
   int CountSlowPaths() const;
   bool HasNonAAPaint() const { return !antialias; }
   HAS_SERIALIZATION_FUNCTIONS();
@@ -388,6 +391,7 @@
   static void Raster(const ClipRectOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return IsValidSkClipOp(op); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRect rect;
@@ -406,6 +410,7 @@
   static void Raster(const ClipRRectOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return IsValidSkClipOp(op); }
   bool HasNonAAPaint() const { return !antialias; }
   HAS_SERIALIZATION_FUNCTIONS();
 
@@ -424,6 +429,7 @@
   static void Raster(const ConcatOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   ThreadsafeMatrix matrix;
@@ -450,6 +456,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRect oval;
@@ -474,6 +481,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkScalar cx;
@@ -492,6 +500,7 @@
   static void Raster(const DrawColorOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return IsValidDrawColorSkBlendMode(mode); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkColor color;
@@ -513,6 +522,9 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const {
+    return flags.IsValid() && outer.isValid() && inner.isValid();
+  }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRRect outer;
@@ -535,6 +547,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   bool HasDiscardableImages() const;
   bool HasNonAAPaint() const { return false; }
   HAS_SERIALIZATION_FUNCTIONS();
@@ -561,6 +574,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   bool HasDiscardableImages() const;
   HAS_SERIALIZATION_FUNCTIONS();
 
@@ -583,6 +597,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   bool HasNonAAPaint() const { return false; }
   HAS_SERIALIZATION_FUNCTIONS();
 
@@ -606,6 +621,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   int CountSlowPaths() const;
@@ -629,6 +645,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRect oval;
@@ -647,6 +664,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   int CountSlowPaths() const;
   HAS_SERIALIZATION_FUNCTIONS();
 
@@ -666,6 +684,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   const void* GetData() const { return GetDataForThis(this); }
@@ -686,6 +705,7 @@
   static void Raster(const DrawRecordOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   size_t AdditionalBytesUsed() const;
   bool HasDiscardableImages() const;
   int CountSlowPaths() const;
@@ -708,6 +728,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRect rect;
@@ -726,6 +747,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid() && rrect.isValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRRect rrect;
@@ -744,6 +766,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   void* GetData() { return GetDataForThis(this); }
@@ -769,6 +792,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   HAS_SERIALIZATION_FUNCTIONS();
 
   sk_sp<SkTextBlob> blob;
@@ -785,6 +809,7 @@
   static void Raster(const NoopOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params) {}
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 };
 
@@ -794,6 +819,7 @@
   static void Raster(const RestoreOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 };
 
@@ -804,6 +830,7 @@
   static void Raster(const RotateOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkScalar degrees;
@@ -818,6 +845,7 @@
   static void Raster(const SaveOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 };
 
@@ -831,6 +859,7 @@
                               const PaintFlags* flags,
                               SkCanvas* canvas,
                               const PlaybackParams& params);
+  bool IsValid() const { return flags.IsValid(); }
   bool HasNonAAPaint() const { return false; }
   HAS_SERIALIZATION_FUNCTIONS();
 
@@ -852,6 +881,7 @@
   static void Raster(const SaveLayerAlphaOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkRect bounds;
@@ -869,6 +899,7 @@
   static void Raster(const ScaleOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkScalar sx;
@@ -891,6 +922,7 @@
   static void Raster(const SetMatrixOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   ThreadsafeMatrix matrix;
@@ -906,6 +938,7 @@
   static void Raster(const TranslateOp* op,
                      SkCanvas* canvas,
                      const PlaybackParams& params);
+  bool IsValid() const { return true; }
   HAS_SERIALIZATION_FUNCTIONS();
 
   SkScalar dx;
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 1e01b3f..3877ae02 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -1602,6 +1602,8 @@
 void CompareImages(const PaintImage& original, const PaintImage& written) {}
 
 void CompareAnnotateOp(const AnnotateOp* original, const AnnotateOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->annotation_type, written->annotation_type);
   EXPECT_EQ(original->rect, written->rect);
   EXPECT_EQ(!!original->data, !!written->data);
@@ -1614,18 +1616,24 @@
 
 void CompareClipDeviceRectOp(const ClipDeviceRectOp* original,
                              const ClipDeviceRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->device_rect, written->device_rect);
   EXPECT_EQ(original->subtract_rect, written->subtract_rect);
   EXPECT_EQ(original->op, written->op);
 }
 
 void CompareClipPathOp(const ClipPathOp* original, const ClipPathOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_TRUE(original->path == written->path);
   EXPECT_EQ(original->op, written->op);
   EXPECT_EQ(original->antialias, written->antialias);
 }
 
 void CompareClipRectOp(const ClipRectOp* original, const ClipRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->rect, written->rect);
   EXPECT_EQ(original->op, written->op);
   EXPECT_EQ(original->antialias, written->antialias);
@@ -1633,17 +1641,23 @@
 
 void CompareClipRRectOp(const ClipRRectOp* original,
                         const ClipRRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->rrect, written->rrect);
   EXPECT_EQ(original->op, written->op);
   EXPECT_EQ(original->antialias, written->antialias);
 }
 
 void CompareConcatOp(const ConcatOp* original, const ConcatOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->matrix, written->matrix);
   EXPECT_EQ(original->matrix.getType(), written->matrix.getType());
 }
 
 void CompareDrawArcOp(const DrawArcOp* original, const DrawArcOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->oval, written->oval);
   EXPECT_EQ(original->start_angle, written->start_angle);
@@ -1653,6 +1667,8 @@
 
 void CompareDrawCircleOp(const DrawCircleOp* original,
                          const DrawCircleOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->cx, written->cx);
   EXPECT_EQ(original->cy, written->cy);
@@ -1661,11 +1677,15 @@
 
 void CompareDrawColorOp(const DrawColorOp* original,
                         const DrawColorOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->color, written->color);
 }
 
 void CompareDrawDRRectOp(const DrawDRRectOp* original,
                          const DrawDRRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->outer, written->outer);
   EXPECT_EQ(original->inner, written->inner);
@@ -1673,6 +1693,8 @@
 
 void CompareDrawImageOp(const DrawImageOp* original,
                         const DrawImageOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   CompareImages(original->image, written->image);
   EXPECT_EQ(original->left, written->left);
@@ -1681,6 +1703,8 @@
 
 void CompareDrawImageRectOp(const DrawImageRectOp* original,
                             const DrawImageRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   CompareImages(original->image, written->image);
   EXPECT_EQ(original->src, written->src);
@@ -1689,11 +1713,15 @@
 
 void CompareDrawIRectOp(const DrawIRectOp* original,
                         const DrawIRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->rect, written->rect);
 }
 
 void CompareDrawLineOp(const DrawLineOp* original, const DrawLineOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->x0, written->x0);
   EXPECT_EQ(original->y0, written->y0);
@@ -1702,17 +1730,23 @@
 }
 
 void CompareDrawOvalOp(const DrawOvalOp* original, const DrawOvalOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->oval, written->oval);
 }
 
 void CompareDrawPathOp(const DrawPathOp* original, const DrawPathOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_TRUE(original->path == written->path);
 }
 
 void CompareDrawPosTextOp(const DrawPosTextOp* original,
                           const DrawPosTextOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   ASSERT_EQ(original->bytes, written->bytes);
   EXPECT_EQ(std::string(static_cast<const char*>(original->GetData())),
@@ -1723,17 +1757,23 @@
 }
 
 void CompareDrawRectOp(const DrawRectOp* original, const DrawRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->rect, written->rect);
 }
 
 void CompareDrawRRectOp(const DrawRRectOp* original,
                         const DrawRRectOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->rrect, written->rrect);
 }
 
 void CompareDrawTextOp(const DrawTextOp* original, const DrawTextOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->x, written->x);
   EXPECT_EQ(original->y, written->y);
@@ -1744,6 +1784,8 @@
 
 void CompareDrawTextBlobOp(const DrawTextBlobOp* original,
                            const DrawTextBlobOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->x, written->x);
   EXPECT_EQ(original->y, written->y);
@@ -1776,28 +1818,40 @@
 
 void CompareNoopOp(const NoopOp* original, const NoopOp* written) {
   // Nothing to compare.
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
 }
 
 void CompareRestoreOp(const RestoreOp* original, const RestoreOp* written) {
   // Nothing to compare.
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
 }
 
 void CompareRotateOp(const RotateOp* original, const RotateOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->degrees, written->degrees);
 }
 
 void CompareSaveOp(const SaveOp* original, const SaveOp* written) {
   // Nothing to compare.
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
 }
 
 void CompareSaveLayerOp(const SaveLayerOp* original,
                         const SaveLayerOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   CompareFlags(original->flags, written->flags);
   EXPECT_EQ(original->bounds, written->bounds);
 }
 
 void CompareSaveLayerAlphaOp(const SaveLayerAlphaOp* original,
                              const SaveLayerAlphaOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->bounds, written->bounds);
   EXPECT_EQ(original->alpha, written->alpha);
   EXPECT_EQ(original->preserve_lcd_text_requests,
@@ -1805,23 +1859,35 @@
 }
 
 void CompareScaleOp(const ScaleOp* original, const ScaleOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->sx, written->sx);
   EXPECT_EQ(original->sy, written->sy);
 }
 
 void CompareSetMatrixOp(const SetMatrixOp* original,
                         const SetMatrixOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->matrix, written->matrix);
 }
 
 void CompareTranslateOp(const TranslateOp* original,
                         const TranslateOp* written) {
+  EXPECT_TRUE(original->IsValid());
+  EXPECT_TRUE(written->IsValid());
   EXPECT_EQ(original->dx, written->dx);
   EXPECT_EQ(original->dy, written->dy);
 }
 
 class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
  public:
+  PaintOpSerializationTest() {
+    // Verify test data.
+    for (size_t i = 0; i < test_rrects.size(); ++i)
+      EXPECT_TRUE(test_rrects[i].isValid());
+  }
+
   PaintOpType GetParamType() const {
     return static_cast<PaintOpType>(GetParam());
   }
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 5379651c..d3932f7 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -7,7 +7,6 @@
 #include <stddef.h>
 
 #include "cc/paint/paint_flags.h"
-#include "cc/paint/paint_op_buffer.h"
 #include "third_party/skia/include/core/SkFlattenableSerialization.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/core/SkRRect.h"
@@ -121,8 +120,6 @@
   Read(&flags->width_);
   Read(&flags->miter_limit_);
   ReadSimple(&flags->blend_mode_);
-  if (!PaintOp::IsValidPaintFlagsSkBlendMode(flags->getBlendMode()))
-    valid_ = false;
   ReadSimple(&flags->bitfields_uint_);
 
   // TODO(enne): ReadTypeface, http://crbug.com/737629
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index 02c6bffa..c50893f90 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -350,6 +350,9 @@
   void set_gpu_rasterization(bool gpu_rasterization) {
     test_capabilities_.gpu_rasterization = gpu_rasterization;
   }
+  void set_avoid_stencil_buffers(bool avoid_stencil_buffers) {
+    test_capabilities_.avoid_stencil_buffers = avoid_stencil_buffers;
+  }
   void set_enable_dc_layers(bool support) {
     test_capabilities_.dc_layers = support;
   }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index b411b89..49c95175 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1894,7 +1894,7 @@
     const auto& caps = compositor_context_provider->ContextCapabilities();
     gpu_rasterization_enabled = caps.gpu_rasterization;
     supports_disable_msaa = caps.multisample_compatibility;
-    if (!caps.msaa_is_slow)
+    if (!caps.msaa_is_slow && !caps.avoid_stencil_buffers)
       max_msaa_samples = caps.max_samples;
   }
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index cf603ce..a5f668cd 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -12105,13 +12105,15 @@
 
 class MsaaIsSlowLayerTreeHostImplTest : public LayerTreeHostImplTest {
  public:
-  void CreateHostImplWithMsaaIsSlow(bool msaa_is_slow) {
+  void CreateHostImplWithCaps(bool msaa_is_slow, bool avoid_stencil_buffers) {
     LayerTreeSettings settings = DefaultSettings();
     settings.gpu_rasterization_msaa_sample_count = 4;
     auto context_provider = TestContextProvider::Create();
     context_provider->UnboundTestContext3d()->SetMaxSamples(4);
     context_provider->UnboundTestContext3d()->set_msaa_is_slow(msaa_is_slow);
     context_provider->UnboundTestContext3d()->set_gpu_rasterization(true);
+    context_provider->UnboundTestContext3d()->set_avoid_stencil_buffers(
+        avoid_stencil_buffers);
     auto msaa_is_normal_layer_tree_frame_sink =
         FakeLayerTreeFrameSink::Create3d(context_provider);
     EXPECT_TRUE(CreateHostImpl(
@@ -12120,9 +12122,9 @@
 };
 
 TEST_F(MsaaIsSlowLayerTreeHostImplTest, GpuRasterizationStatusMsaaIsSlow) {
-  // Ensure that without the msaa_is_slow cap we raster slow paths with
-  // msaa.
-  CreateHostImplWithMsaaIsSlow(false);
+  // Ensure that without the msaa_is_slow or avoid_stencil_buffers caps
+  // we raster slow paths with msaa.
+  CreateHostImplWithCaps(false, false);
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentHasSlowPaths(true);
   host_impl_->CommitComplete();
@@ -12130,9 +12132,28 @@
             host_impl_->gpu_rasterization_status());
   EXPECT_TRUE(host_impl_->use_gpu_rasterization());
 
-  // Ensure that with the msaa_is_slow cap we don't raster slow paths
-  // with msaa (we'll still use GPU raster, though).
-  CreateHostImplWithMsaaIsSlow(true);
+  // Ensure that with either msaa_is_slow or avoid_stencil_buffers caps
+  // we don't raster slow paths with msaa (we'll still use GPU raster, though).
+  // msaa_is_slow = true, avoid_stencil_buffers = false
+  CreateHostImplWithCaps(true, false);
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentHasSlowPaths(true);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+  EXPECT_FALSE(host_impl_->use_msaa());
+
+  // msaa_is_slow = false, avoid_stencil_buffers = true
+  CreateHostImplWithCaps(false, true);
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentHasSlowPaths(true);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+  EXPECT_FALSE(host_impl_->use_msaa());
+
+  // msaa_is_slow = true, avoid_stencil_buffers = true
+  CreateHostImplWithCaps(true, true);
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentHasSlowPaths(true);
   host_impl_->CommitComplete();
diff --git a/chrome/app/md_extensions_strings.grdp b/chrome/app/md_extensions_strings.grdp
index 3212ab57..ecfbe0a 100644
--- a/chrome/app/md_extensions_strings.grdp
+++ b/chrome/app/md_extensions_strings.grdp
@@ -103,6 +103,15 @@
   <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_TITLE" desc="The title of the dialog to pack an extension.">
     Pack extension
   </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_WARNING_TITLE" desc="Warning title message for pack extension">
+    Pack extension warning
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_ERROR_TITLE" desc="Error title message for pack extension">
+    Pack extension error
+  </message>
+  <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_PROCEED_ANYWAY" desc="Button to continue with operation in extension packing">
+    Proceed anyway
+  </message>
   <message name="IDS_MD_EXTENSIONS_PACK_DIALOG_BROWSE_BUTTON" desc="The label of the button to browse the file system to select an extension directory or file.">
     Browse
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 9661ebe94..9128ae9 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3446,6 +3446,8 @@
       "task_manager/providers/child_process_task.h",
       "task_manager/providers/child_process_task_provider.cc",
       "task_manager/providers/child_process_task_provider.h",
+      "task_manager/providers/render_process_host_task_provider.cc",
+      "task_manager/providers/render_process_host_task_provider.h",
       "task_manager/providers/task.cc",
       "task_manager/providers/task.h",
       "task_manager/providers/task_provider.cc",
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 2154935..5fa138a 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -210,6 +210,8 @@
         <include name="IDR_MD_EXTENSIONS_OPTIONS_DIALOG_JS" file="resources\md_extensions\options_dialog.js" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_PACK_DIALOG_HTML" file="resources\md_extensions\pack_dialog.html" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_PACK_DIALOG_JS" file="resources\md_extensions\pack_dialog.js" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_PACK_DIALOG_ALERT_HTML" file="resources\md_extensions\pack_dialog_alert.html" type="BINDATA" />
+        <include name="IDR_MD_EXTENSIONS_PACK_DIALOG_ALERT_JS" file="resources\md_extensions\pack_dialog_alert.js" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_SERVICE_HTML" file="resources\md_extensions\service.html" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_SERVICE_JS" file="resources\md_extensions\service.js" type="BINDATA" />
         <include name="IDR_MD_EXTENSIONS_SHORTCUT_INPUT_HTML" file="resources\md_extensions\shortcut_input.html" type="BINDATA" />
diff --git a/chrome/browser/chromeos/net/DEPS b/chrome/browser/chromeos/net/DEPS
index 777e45bf..1ee1408 100644
--- a/chrome/browser/chromeos/net/DEPS
+++ b/chrome/browser/chromeos/net/DEPS
@@ -17,4 +17,7 @@
     "+ash/system/system_notifier.h",
     "+ash/resources/grit/ash_resources.h",
   ],
+  "tether_notification_presenter\.cc": [
+    "+ash/system/system_notifier.h",
+  ],
 }
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter.cc b/chrome/browser/chromeos/net/tether_notification_presenter.cc
index cfa02db..deaa8842 100644
--- a/chrome/browser/chromeos/net/tether_notification_presenter.cc
+++ b/chrome/browser/chromeos/net/tether_notification_presenter.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/net/tether_notification_presenter.h"
 
+#include "ash/system/system_notifier.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
@@ -54,11 +55,39 @@
   return std::min(std::max(normalized_signal_strength, 0), 4);
 }
 
-}  // namespace
+std::unique_ptr<message_center::Notification> CreateNotification(
+    const std::string& id,
+    const base::string16& title,
+    const base::string16& message,
+    const message_center::RichNotificationData rich_notification_data,
+    int signal_strength) {
+  auto source = base::MakeUnique<ash::network_icon::SignalStrengthImageSource>(
+      ash::network_icon::BARS, gfx::kGoogleBlue500, kTetherSignalIconSize,
+      GetNormalizedSignalStrength(signal_strength));
+  std::unique_ptr<message_center::Notification> notification =
+      base::MakeUnique<message_center::Notification>(
+          message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title,
+          message,
+          gfx::Image(gfx::ImageSkia(std::move(source), kTetherSignalIconSize)),
+          base::string16() /* display_source */, GURL() /* origin_url */,
+          message_center::NotifierId(
+              message_center::NotifierId::NotifierType::SYSTEM_COMPONENT,
+              ash::system_notifier::kNotifierTether),
+          rich_notification_data, nullptr);
+  notification->SetSystemPriority();
+  return notification;
+}
 
-// static
-constexpr const char TetherNotificationPresenter::kTetherNotifierId[] =
-    "cros_tether_notification_ids.notifier_id";
+std::unique_ptr<message_center::Notification>
+CreateNotificationWithMediumSignalStrengthIcon(const std::string& id,
+                                               const base::string16& title,
+                                               const base::string16& message) {
+  return CreateNotification(id, title, message,
+                            message_center::RichNotificationData(),
+                            kMediumSignalStrength);
+}
+
+}  // namespace
 
 // static
 constexpr const char TetherNotificationPresenter::kActiveHostNotificationId[] =
@@ -82,44 +111,10 @@
 // static
 constexpr const char* const
     TetherNotificationPresenter::kIdsWhichOpenTetherSettingsOnClick[] = {
-        TetherNotificationPresenter::kTetherNotifierId,
         TetherNotificationPresenter::kActiveHostNotificationId,
         TetherNotificationPresenter::kPotentialHotspotNotificationId,
         TetherNotificationPresenter::kSetupRequiredNotificationId};
 
-// static
-std::unique_ptr<message_center::Notification>
-TetherNotificationPresenter::CreateNotificationWithMediumSignalStrengthIcon(
-    const std::string& id,
-    const base::string16& title,
-    const base::string16& message) {
-  return CreateNotification(id, title, message,
-                            message_center::RichNotificationData(),
-                            kMediumSignalStrength);
-}
-
-// static
-std::unique_ptr<message_center::Notification>
-TetherNotificationPresenter::CreateNotification(
-    const std::string& id,
-    const base::string16& title,
-    const base::string16& message,
-    const message_center::RichNotificationData rich_notification_data,
-    int signal_strength) {
-  auto source = base::MakeUnique<ash::network_icon::SignalStrengthImageSource>(
-      ash::network_icon::BARS, gfx::kGoogleBlue500, kTetherSignalIconSize,
-      GetNormalizedSignalStrength(signal_strength));
-  return base::MakeUnique<message_center::Notification>(
-      message_center::NotificationType::NOTIFICATION_TYPE_SIMPLE, id, title,
-      message,
-      gfx::Image(gfx::ImageSkia(std::move(source), kTetherSignalIconSize)),
-      base::string16() /* display_source */, GURL() /* origin_url */,
-      message_center::NotifierId(
-          message_center::NotifierId::NotifierType::SYSTEM_COMPONENT,
-          kTetherNotifierId),
-      rich_notification_data, nullptr);
-}
-
 TetherNotificationPresenter::TetherNotificationPresenter(
     Profile* profile,
     message_center::MessageCenter* message_center,
diff --git a/chrome/browser/chromeos/net/tether_notification_presenter.h b/chrome/browser/chromeos/net/tether_notification_presenter.h
index df4d2a1e..67d297c 100644
--- a/chrome/browser/chromeos/net/tether_notification_presenter.h
+++ b/chrome/browser/chromeos/net/tether_notification_presenter.h
@@ -73,8 +73,9 @@
   };
 
  private:
+  friend class TetherNotificationPresenterTest;
+
   // IDs associated with Tether notification types.
-  static const char kTetherNotifierId[];
   static const char kPotentialHotspotNotificationId[];
   static const char kActiveHostNotificationId[];
   static const char kSetupRequiredNotificationId[];
@@ -83,19 +84,6 @@
   // IDs of all notifications which, when clicked, open mobile data settings.
   static const char* const kIdsWhichOpenTetherSettingsOnClick[];
 
-  static std::unique_ptr<message_center::Notification>
-  CreateNotificationWithMediumSignalStrengthIcon(const std::string& id,
-                                                 const base::string16& title,
-                                                 const base::string16& message);
-  static std::unique_ptr<message_center::Notification> CreateNotification(
-      const std::string& id,
-      const base::string16& title,
-      const base::string16& message,
-      const message_center::RichNotificationData rich_notification_data,
-      int signal_strength);
-
-  friend class TetherNotificationPresenterTest;
-
   void SetSettingsUiDelegateForTesting(
       std::unique_ptr<SettingsUiDelegate> settings_ui_delegate);
   void ShowNotification(
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index f4bd758..ab4d066 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
 #include "chrome/browser/chromeos/net/shill_error.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/net/x509_certificate_model.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/login/login_state.h"
 #include "chromeos/network/network_configuration_handler.h"
diff --git a/chrome/browser/chromeos/system_logs/debug_log_writer.cc b/chrome/browser/chromeos/system_logs/debug_log_writer.cc
index abb84909..4829dfd 100644
--- a/chrome/browser/chromeos/system_logs/debug_log_writer.cc
+++ b/chrome/browser/chromeos/system_logs/debug_log_writer.cc
@@ -13,10 +13,10 @@
 #include "base/command_line.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
-#include "base/lazy_instance.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/sequenced_task_runner.h"
+#include "base/task_scheduler/lazy_task_runner.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/common/logging_chrome.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -33,15 +33,11 @@
 const char kGzipCommand[] = "/bin/gzip";
 const char kTarCommand[] = "/bin/tar";
 
-struct DebugLogWriterTaskRunner {
-  const scoped_refptr<base::SequencedTaskRunner> task_runner =
-      base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::BACKGROUND,
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
-};
-
-base::LazyInstance<DebugLogWriterTaskRunner>::Leaky g_sequenced_task_runner =
-    LAZY_INSTANCE_INITIALIZER;
+base::LazySequencedTaskRunner g_sequenced_task_runner =
+    LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(
+        base::TaskTraits(base::MayBlock(),
+                         base::TaskPriority::BACKGROUND,
+                         base::TaskShutdownBehavior::BLOCK_SHUTDOWN));
 
 // Called upon completion of |WriteDebugLogToFile|. Closes file
 // descriptor, deletes log file in the case of failure and calls
@@ -53,7 +49,7 @@
     bool succeeded) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!succeeded) {
-    bool posted = g_sequenced_task_runner.Get().task_runner->PostTaskAndReply(
+    bool posted = g_sequenced_task_runner.Get()->PostTaskAndReply(
         FROM_HERE,
         base::Bind(base::IgnoreResult(&base::DeleteFile), file_path, false),
         base::Bind(callback, file_path, false));
@@ -84,8 +80,7 @@
                  callback));
 
   // Close the file on an IO-allowed thread.
-  g_sequenced_task_runner.Get().task_runner->DeleteSoon(FROM_HERE,
-                                                        file.release());
+  g_sequenced_task_runner.Get()->DeleteSoon(FROM_HERE, file.release());
 }
 
 // Runs command with its parameters as defined in |argv|.
@@ -229,7 +224,7 @@
   int flags = base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE;
   std::unique_ptr<base::File> file(new base::File);
   base::File* file_ptr = file.get();
-  g_sequenced_task_runner.Get().task_runner->PostTaskAndReply(
+  g_sequenced_task_runner.Get()->PostTaskAndReply(
       FROM_HERE,
       base::Bind(&InitializeLogFile, base::Unretained(file_ptr), file_path,
                  flags),
diff --git a/chrome/browser/chromeos/tether/tether_service.cc b/chrome/browser/chromeos/tether/tether_service.cc
index 0a32f09..5a95cfd 100644
--- a/chrome/browser/chromeos/tether/tether_service.cc
+++ b/chrome/browser/chromeos/tether/tether_service.cc
@@ -143,12 +143,13 @@
   if (adapter_)
     adapter_->RemoveObserver(this);
   registrar_.RemoveAll();
-  notification_presenter_.reset();
 
   // Shut down the feature. Note that this does not change Tether's technology
   // state in NetworkStateHandler because doing so could cause visual jank just
   // as the user logs out.
   StopTetherIfNecessary();
+
+  notification_presenter_.reset();
 }
 
 void TetherService::SuspendImminent() {
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index e4d273b..4a3a53c 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -88,11 +88,6 @@
 
 namespace {
 
-// The first id assigned to a download when download database failed to
-// initialize.
-const uint32_t kFirstDownloadIdNoPersist =
-    content::DownloadItem::kInvalidId + 1;
-
 #if defined(FULL_SAFE_BROWSING)
 
 // String pointer used for identifying safebrowing data associated with
@@ -256,18 +251,8 @@
 void ChromeDownloadManagerDelegate::SetNextId(uint32_t next_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!profile_->IsOffTheRecord());
-
-  // |content::DownloadItem::kInvalidId| will be returned only when download
-  // database failed to initialize.
-  bool download_db_available = (next_id != content::DownloadItem::kInvalidId);
-  RecordDatabaseAvailability(download_db_available);
-  if (download_db_available) {
-    next_download_id_ = next_id;
-  } else {
-    // Still download files without download database, all download history in
-    // this browser session will not be persisted.
-    next_download_id_ = kFirstDownloadIdNoPersist;
-  }
+  DCHECK_NE(content::DownloadItem::kInvalidId, next_id);
+  next_download_id_ = next_id;
 
   IdCallbackVector callbacks;
   id_callbacks_.swap(callbacks);
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 731bff9..b19c7fa 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -152,11 +152,8 @@
       uint32_t download_id,
       const base::Closure& user_complete_callback);
 
-  // Sets the next download id based on download database records, and runs all
-  // cached id callbacks.
   void SetNextId(uint32_t id);
 
-  // Runs the |callback| with next id. Results in the download being started.
   void ReturnNextId(const content::DownloadIdCallback& callback);
 
   void OnDownloadTargetDetermined(
@@ -172,14 +169,7 @@
   bool ShouldBlockFile(content::DownloadDangerType danger_type) const;
 
   Profile* profile_;
-
-  // Incremented by one for each download, the first available download id is
-  // assigned from history database or 1 when history database fails to
-  // intialize.
   uint32_t next_download_id_;
-
-  // The |GetNextId| callbacks that may be cached before loading the download
-  // database.
   IdCallbackVector id_callbacks_;
   std::unique_ptr<DownloadPrefs> download_prefs_;
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index bb93527..9661b63 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -243,16 +243,12 @@
   DownloadPrefs* download_prefs();
   PrefService* pref_service();
 
-  const std::vector<uint32_t>& download_ids() const { return download_ids_; }
-  void GetNextId(uint32_t next_id) { download_ids_.emplace_back(next_id); }
-
  private:
   sync_preferences::TestingPrefServiceSyncable* pref_service_;
   base::ScopedTempDir test_download_dir_;
   std::unique_ptr<content::MockDownloadManager> download_manager_;
   std::unique_ptr<TestChromeDownloadManagerDelegate> delegate_;
   MockWebContentsDelegate web_contents_delegate_;
-  std::vector<uint32_t> download_ids_;
 };
 
 ChromeDownloadManagerDelegateTest::ChromeDownloadManagerDelegateTest()
@@ -619,30 +615,6 @@
   VerifyAndClearExpectations();
 }
 
-TEST_F(ChromeDownloadManagerDelegateTest, WithoutHistoryDbNextId) {
-  content::DownloadIdCallback id_callback = base::Bind(
-      &ChromeDownloadManagerDelegateTest::GetNextId, base::Unretained(this));
-  delegate()->GetNextId(id_callback);
-  delegate()->GetNextId(id_callback);
-  // When download database fails to initialize, id will be set to
-  // |content::DownloadItem::kInvalidId|.
-  delegate()->GetDownloadIdReceiverCallback().Run(
-      content::DownloadItem::kInvalidId);
-  std::vector<uint32_t> expected_ids = std::vector<uint32_t>{1u, 2u};
-  EXPECT_EQ(expected_ids, download_ids());
-}
-
-TEST_F(ChromeDownloadManagerDelegateTest, WithHistoryDbNextId) {
-  content::DownloadIdCallback id_callback = base::Bind(
-      &ChromeDownloadManagerDelegateTest::GetNextId, base::Unretained(this));
-  delegate()->GetNextId(id_callback);
-  delegate()->GetNextId(id_callback);
-  // Simulates a valid download database with no records.
-  delegate()->GetDownloadIdReceiverCallback().Run(1u);
-  std::vector<uint32_t> expected_ids = std::vector<uint32_t>{1u, 2u};
-  EXPECT_EQ(expected_ids, download_ids());
-}
-
 #if defined(FULL_SAFE_BROWSING)
 namespace {
 
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index bed151aa..6477de7d 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -50,7 +50,3 @@
                             open_method,
                             DOWNLOAD_OPEN_METHOD_LAST_ENTRY);
 }
-
-void RecordDatabaseAvailability(bool is_available) {
-  UMA_HISTOGRAM_BOOLEAN("Download.Database.IsAvailable", is_available);
-}
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index 495b783..cec8776 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -90,8 +90,4 @@
 // Record how a download was opened.
 void RecordDownloadOpenMethod(ChromeDownloadOpenMethod open_method);
 
-// Record if the database is available to provide the next download id before
-// starting all downloads.
-void RecordDatabaseAvailability(bool is_available);
-
 #endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STATS_H_
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
index 6988548..64031b6 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
@@ -176,25 +176,19 @@
 
 void CastMediaSinkService::OnChannelOpenedOnIOThread(
     const DnsSdService& service,
-    int channel_id,
-    cast_channel::ChannelError channel_error) {
-  if (channel_error != cast_channel::ChannelError::NONE) {
+    cast_channel::CastSocket* socket) {
+  DCHECK(socket);
+  if (socket->error_state() != cast_channel::ChannelError::NONE) {
     DVLOG(2) << "Fail to open channel " << service.ip_address << ": "
-             << service.service_host_port.ToString()
-             << " [ChannelError]: " << (int)channel_error;
-    return;
-  }
-
-  auto* socket = cast_socket_service_->GetSocket(channel_id);
-  if (!socket) {
-    DVLOG(2) << "Fail to find socket with [channel_id]: " << channel_id;
+             << service.service_host_port.ToString() << " [ChannelError]: "
+             << cast_channel::ChannelErrorToString(socket->error_state());
     return;
   }
 
   content::BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
       base::Bind(&CastMediaSinkService::OnChannelOpenedOnUIThread, this,
-                 service, channel_id, socket->audio_only()));
+                 service, socket->id(), socket->audio_only()));
 }
 
 void CastMediaSinkService::OnChannelOpenedOnUIThread(
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
index df6e60e..e2937ef 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
@@ -99,11 +99,10 @@
 
   // Invoked when opening cast channel on IO thread completes.
   // |service|: mDNS service description.
-  // |channel_id|: channel id of newly created cast channel.
-  // |channel_error|: error encounted when opending cast channel.
+  // |socket|: raw pointer of newly created cast channel. Does not take
+  // ownership of |socket|.
   void OnChannelOpenedOnIOThread(const DnsSdService& service,
-                                 int channel_id,
-                                 cast_channel::ChannelError channel_error);
+                                 cast_channel::CastSocket* socket);
 
   // Invoked by |OnChannelOpenedOnIOThread| to post task on UI thread.
   // |service|: mDNS service description.
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
index f2e54aa..ef01e0d 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
@@ -137,12 +137,10 @@
 TEST_F(CastMediaSinkServiceTest, TestOnChannelOpenedOnIOThread) {
   DnsSdService service = CreateDnsService(1);
   cast_channel::MockCastSocket socket;
-  EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1))
-      .WillOnce(Return(&socket));
+  socket.set_id(1);
 
   media_sink_service_->current_services_.push_back(service);
-  media_sink_service_->OnChannelOpenedOnIOThread(
-      service, 1, cast_channel::ChannelError::NONE);
+  media_sink_service_->OnChannelOpenedOnIOThread(service, &socket);
   // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread.
   base::RunLoop().RunUntilIdle();
 
@@ -158,24 +156,16 @@
   DnsSdService service3 = CreateDnsService(3);
 
   cast_channel::MockCastSocket socket2;
+  socket2.set_id(2);
   cast_channel::MockCastSocket socket3;
-  // Fail to open channel 1.
-  EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1))
-      .WillOnce(Return(nullptr));
-  EXPECT_CALL(*mock_cast_socket_service_, GetSocket(2))
-      .WillOnce(Return(&socket2));
-  EXPECT_CALL(*mock_cast_socket_service_, GetSocket(3))
-      .WillOnce(Return(&socket2));
+  socket3.set_id(3);
 
   // Current round of Dns discovery finds service1 and service 2.
   media_sink_service_->current_services_.push_back(service1);
   media_sink_service_->current_services_.push_back(service2);
-  media_sink_service_->OnChannelOpenedOnIOThread(
-      service1, 1, cast_channel::ChannelError::NONE);
-  media_sink_service_->OnChannelOpenedOnIOThread(
-      service2, 2, cast_channel::ChannelError::NONE);
-  media_sink_service_->OnChannelOpenedOnIOThread(
-      service3, 3, cast_channel::ChannelError::NONE);
+  // Fail to open channel 1.
+  media_sink_service_->OnChannelOpenedOnIOThread(service2, &socket2);
+  media_sink_service_->OnChannelOpenedOnIOThread(service3, &socket3);
   // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread.
   base::RunLoop().RunUntilIdle();
 
@@ -209,15 +199,12 @@
   base::RunLoop().RunUntilIdle();
 
   cast_channel::MockCastSocket socket1;
+  socket1.set_id(1);
   cast_channel::MockCastSocket socket2;
+  socket2.set_id(2);
 
-  EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1))
-      .WillOnce(Return(&socket1));
-  EXPECT_CALL(*mock_cast_socket_service_, GetSocket(2))
-      .WillOnce(Return(&socket2));
-
-  callback1.Run(1, cast_channel::ChannelError::NONE);
-  callback2.Run(2, cast_channel::ChannelError::NONE);
+  callback1.Run(&socket1);
+  callback2.Run(&socket2);
 
   // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread.
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 625b8b38..cb2861b 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -200,6 +200,10 @@
     tab_manager_->OnSessionRestoreFinishedLoadingTabs();
   }
 
+  void OnWillRestoreTab(WebContents* web_contents) override {
+    tab_manager_->OnWillRestoreTab(web_contents);
+  }
+
  private:
   TabManager* tab_manager_;
 };
@@ -590,6 +594,10 @@
   is_session_restore_loading_tabs_ = false;
 }
 
+bool TabManager::IsTabInSessionRestore(WebContents* web_contents) const {
+  return GetWebContentsData(web_contents)->is_in_session_restore();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // TabManager, private:
 
@@ -1147,6 +1155,12 @@
   return false;
 }
 
+void TabManager::OnWillRestoreTab(WebContents* web_contents) {
+  WebContentsData* data = GetWebContentsData(web_contents);
+  DCHECK(!data->is_in_session_restore());
+  data->SetIsInSessionRestore(true);
+}
+
 void TabManager::OnDidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   auto it = pending_navigations_.begin();
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 08b39009..5280b00 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -218,6 +218,10 @@
     return is_session_restore_loading_tabs_;
   }
 
+  // Returns true if the tab was created by session restore and has not finished
+  // the first navigation.
+  bool IsTabInSessionRestore(content::WebContents* web_contents) const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, PurgeBackgroundRenderer);
   FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ActivateTabResetPurgeState);
@@ -412,6 +416,7 @@
 
   void OnSessionRestoreStartedLoadingTabs();
   void OnSessionRestoreFinishedLoadingTabs();
+  void OnWillRestoreTab(content::WebContents* web_contents);
 
   // Returns true if TabManager can start loading next tab.
   bool CanLoadNextTab() const;
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
index bd6f3d4..4e4d06a 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.cc
@@ -63,6 +63,7 @@
 
 void TabManager::WebContentsData::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
+  SetIsInSessionRestore(false);
   g_browser_process->GetTabManager()->OnDidFinishNavigation(navigation_handle);
 }
 
@@ -83,6 +84,7 @@
   }
 
   SetTabLoadingState(TAB_IS_NOT_LOADING);
+  SetIsInSessionRestore(false);
   g_browser_process->GetTabManager()->OnWebContentsDestroyed(web_contents());
 }
 
@@ -209,7 +211,8 @@
       last_inactive_time(TimeTicks::UnixEpoch()),
       engagement_score(-1.0),
       is_auto_discardable(true),
-      tab_loading_state(TAB_IS_NOT_LOADING) {}
+      tab_loading_state(TAB_IS_NOT_LOADING),
+      is_in_session_restore(false) {}
 
 bool TabManager::WebContentsData::Data::operator==(const Data& right) const {
   return is_discarded == right.is_discarded &&
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
index 361e1db9..96172e0 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
@@ -137,6 +137,12 @@
     return tab_data_.tab_loading_state;
   }
 
+  void SetIsInSessionRestore(bool is_in_session_restore) {
+    tab_data_.is_in_session_restore = is_in_session_restore;
+  }
+
+  bool is_in_session_restore() const { return tab_data_.is_in_session_restore; }
+
  private:
   // Needed to access tab_data_.
   FRIEND_TEST_ALL_PREFIXES(TabManagerWebContentsDataTest, CopyState);
@@ -168,6 +174,9 @@
     bool is_auto_discardable;
     // Current loading state of this tab.
     TabLoadingState tab_loading_state;
+    // True if the tab was created by session restore. Remains true until the
+    // end of the first navigation or the tab is closed.
+    bool is_in_session_restore;
   };
 
   // Returns either the system's clock or the test clock. See |test_tick_clock_|
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
index 8d23d7c..a058b0b 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
@@ -11,6 +11,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using content::WebContents;
 using content::WebContentsTester;
@@ -41,7 +42,7 @@
   TabManager::WebContentsData* CreateWebContentsAndTabData(
       std::unique_ptr<WebContents>* web_contents) {
     web_contents->reset(
-        WebContents::Create(WebContents::CreateParams(profile())));
+        WebContentsTester::CreateTestWebContents(browser_context(), nullptr));
     TabManager::WebContentsData::CreateForWebContents(web_contents->get());
     return TabManager::WebContentsData::FromWebContents(web_contents->get());
   }
@@ -52,6 +53,8 @@
   base::SimpleTestTickClock test_clock_;
 };
 
+const char kDefaultUrl[] = "https://www.google.com";
+
 }  // namespace
 
 TEST_F(TabManagerWebContentsDataTest, DiscardState) {
@@ -212,4 +215,24 @@
   histograms.ExpectBucketCount(kHistogramName, 12000, 1);
 }
 
+TEST_F(TabManagerWebContentsDataTest, IsInSessionRestoreWithTabLoading) {
+  EXPECT_FALSE(tab_data()->is_in_session_restore());
+  tab_data()->SetIsInSessionRestore(true);
+  EXPECT_TRUE(tab_data()->is_in_session_restore());
+
+  WebContents* contents = tab_data()->web_contents();
+  WebContentsTester::For(contents)->NavigateAndCommit(GURL(kDefaultUrl));
+  WebContentsTester::For(contents)->TestSetIsLoading(false);
+  EXPECT_FALSE(tab_data()->is_in_session_restore());
+}
+
+TEST_F(TabManagerWebContentsDataTest, IsInSessionRestoreWithTabClose) {
+  EXPECT_FALSE(tab_data()->is_in_session_restore());
+  tab_data()->SetIsInSessionRestore(true);
+  EXPECT_TRUE(tab_data()->is_in_session_restore());
+
+  tab_data()->WebContentsDestroyed();
+  EXPECT_FALSE(tab_data()->is_in_session_restore());
+}
+
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index f680fbc..50d5fbd 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -197,7 +197,8 @@
   // Editable nodes are within a text-like field and don't make sense when
   // performing object navigation. Users should use line, word, or character
   // navigation. Only navigate to the top level node.
-  if (node.parent && node.parent.state.editable)
+  if (node.parent && node.parent.state.editable &&
+      !node.parent.state[State.RICHLY_EDITABLE])
     return false;
 
   // Descend into large nodes.
@@ -298,11 +299,24 @@
     case Role.ROOT_WEB_AREA:
       return !node.parent || node.parent.root.role == Role.DESKTOP;
     default:
-      return node.state.richlyEditable && node.state.focused;
+      return false;
   }
 };
 
 /**
+ * Returns whether the given node should not be crossed when performing
+ * traversal inside of an editable. Note that this predicate should not be
+ * applied everywhere since there would be no way for a user to exit the
+ * editable.
+ * @param {AutomationNode} node
+ * @return {boolean}
+ */
+AutomationPredicate.editableRoot = function(node) {
+  return AutomationPredicate.root(node) ||
+      node.state.richlyEditable && node.state.focused;
+};
+
+/**
  * Nodes that should be ignored while traversing the automation tree. For
  * example, apply this predicate when moving to the next object.
  * @param {!AutomationNode} node
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index dafce56..0c9805a 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -487,10 +487,6 @@
       if (!lca || lca.state[StateType.EDITABLE] ||
           !range.start.node.state[StateType.EDITABLE])
         range.select();
-
-      // Richly editable output gets handled by editing.js.
-      if (lca && lca.state.richlyEditable)
-        return;
     }
 
     o.withRichSpeechAndBraille(
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
index ec0d088..62632fb 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -508,13 +508,13 @@
 
         // Stop if we've wrapped back to the document.
         var maybeDoc = newRange.start.node;
-        if (maybeDoc.role == RoleType.ROOT_WEB_AREA &&
-            maybeDoc.parent.root.role == RoleType.DESKTOP) {
+        if (AutomationPredicate.root(maybeDoc)) {
           ChromeVoxState.isReadingContinuously = false;
           return;
         }
 
         ChromeVoxState.instance.setCurrentRange(newRange);
+        newRange.select();
 
         new Output()
             .withRichSpeechAndBraille(
@@ -523,11 +523,11 @@
             .onSpeechEnd(continueReading)
             .go();
       }.bind(this);
-
+      var startNode = ChromeVoxState.instance.currentRange.start.node;
+      var collapsedRange = cursors.Range.fromNode(startNode);
       new Output()
           .withRichSpeechAndBraille(
-              ChromeVoxState.instance.currentRange_, null,
-              Output.EventType.NAVIGATE)
+              collapsedRange, collapsedRange, Output.EventType.NAVIGATE)
           .onSpeechEnd(continueReading)
           .go();
 
@@ -726,7 +726,8 @@
     var bound = current.getBound(dir).node;
     if (bound) {
       var node = AutomationUtil.findNextNode(
-          bound, dir, pred, {skipInitialAncestry: true});
+          bound, dir, pred,
+          {skipInitialAncestry: true, root: AutomationPredicate.editableRoot});
 
       if (node && !skipSync) {
         node = AutomationUtil.findNodePre(
@@ -739,7 +740,7 @@
       } else {
         cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP);
         var root = bound;
-        while (root && !AutomationPredicate.root(root))
+        while (root && !AutomationPredicate.editableRoot(root))
           root = root.parent;
 
         if (!root)
@@ -752,8 +753,10 @@
                       root, dir, AutomationPredicate.leaf) ||
               bound;
         }
-        node = AutomationUtil.findNextNode(
-            bound, dir, pred, {skipInitialAncestry: true});
+        node = AutomationUtil.findNextNode(bound, dir, pred, {
+          skipInitialAncestry: true,
+          root: AutomationPredicate.editableRoot
+        });
 
         if (node && !skipSync) {
           node = AutomationUtil.findNodePre(
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
index 3e3106c..84871bd 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/editing.js
@@ -92,7 +92,7 @@
         evt.target != this.node_)
       return;
 
-    this.editableText_.onUpdate();
+    this.editableText_.onUpdate(evt.eventFrom);
   },
 };
 
@@ -124,8 +124,9 @@
 
   /**
    * Called when the text field has been updated.
+   * @param {string|undefined} eventFrom
    */
-  onUpdate: function() {
+  onUpdate: function(eventFrom) {
     var newValue = this.node_.value || '';
 
     if (this.value != newValue)
@@ -227,7 +228,7 @@
   __proto__: AutomationEditableText.prototype,
 
   /** @override */
-  onUpdate: function() {
+  onUpdate: function(eventFrom) {
     var root = this.node_.root;
     if (!root.anchorObject || !root.focusObject ||
         root.anchorOffset === undefined || root.focusOffset === undefined)
@@ -263,6 +264,24 @@
     var prev = this.line_;
     this.line_ = cur;
 
+    var finish = function() {
+      // The state in EditableTextBase needs to get updated with the new line
+      // contents, so that subsequent intra-line changes get the right state
+      // transitions.
+      this.value = cur.text;
+      this.start = cur.startOffset;
+      this.end = cur.endOffset;
+    }.bind(this);
+
+    // During continuous read, skip speech (which gets handled in
+    // CommandHandler). We use the speech end callback to trigger additional
+    // speech.
+    if (ChromeVoxState.isReadingContinuously) {
+      this.brailleCurrentRichLine_();
+      finish();
+      return;
+    }
+
     // Selection stayed within the same line(s) and didn't cross into new lines.
     if (anchorLine.isSameLine(prevAnchorLine) &&
         focusLine.isSameLine(prevFocusLine)) {
@@ -397,13 +416,7 @@
       this.speakCurrentRichLine_(prev);
       this.brailleCurrentRichLine_();
     }
-
-    // The state in EditableTextBase needs to get updated with the new line
-    // contents, so that subsequent intra-line changes get the right state
-    // transitions.
-    this.value = cur.text;
-    this.start = cur.startOffset;
-    this.end = cur.endOffset;
+    finish();
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index bf3710f..5775f2c 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -843,8 +843,11 @@
         var valueEnd = buff.getSpanEnd(selSpan);
         startIndex = valueStart + selSpan.startIndex;
         endIndex = valueStart + selSpan.endIndex;
-        buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd);
-        buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex);
+        try {
+          buff.setSpan(new cvox.ValueSpan(0), valueStart, valueEnd);
+          buff.setSpan(new cvox.ValueSelectionSpan(), startIndex, endIndex);
+        } catch (e) {
+        }
       }
 
       var output = new cvox.NavBraille(
diff --git a/chrome/browser/resources/md_extensions/compiled_resources2.gyp b/chrome/browser/resources/md_extensions/compiled_resources2.gyp
index 367d0fb2..00e8564 100644
--- a/chrome/browser/resources/md_extensions/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_extensions/compiled_resources2.gyp
@@ -154,7 +154,7 @@
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-	'<(EXTERNS_GYP):developer_private',
+        '<(EXTERNS_GYP):developer_private',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
@@ -163,6 +163,7 @@
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        '<(EXTERNS_GYP):developer_private',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/md_extensions/pack_dialog.html b/chrome/browser/resources/md_extensions/pack_dialog.html
index 83eeb34..c793c636 100644
--- a/chrome/browser/resources/md_extensions/pack_dialog.html
+++ b/chrome/browser/resources/md_extensions/pack_dialog.html
@@ -5,8 +5,10 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="pack_dialog_alert.html">
 
 <dom-module id="extensions-pack-dialog">
   <template>
@@ -28,14 +30,13 @@
         color: var(--google-blue-500);
       }
     </style>
-
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
       <div slot="title">$i18n{packDialogTitle}</div>
       <div slot="body">
         <div>$i18n{packDialogContent}</div>
         <div class="file-input">
           <paper-input id="root-dir" label="$i18n{packDialogExtensionRoot}"
-              always-float-label value="[[packDirectory_]]">
+              always-float-label value="{{packDirectory_}}">
           </paper-input>
           <paper-button id="root-dir-browse" on-tap="onRootBrowse_">
             $i18n{packDialogBrowse}
@@ -43,7 +44,7 @@
         </div>
         <div class="file-input">
           <paper-input id="key-file" label="$i18n{packDialogKeyFile}"
-              always-float-label value="[[keyFile_]]">
+              always-float-label value="{{keyFile_}}">
           </paper-input>
           <paper-button id="key-file-browse" on-tap="onKeyBrowse_">
             $i18n{packDialogBrowse}
@@ -51,14 +52,20 @@
         </div>
       </div>
       <div slot="button-container">
-        <paper-button class="cancel-button" on-tap="close">
+        <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{packDialogCancel}
         </paper-button>
-        <paper-button class="action-button" on-tap="onConfirmTap_">
+        <paper-button class="action-button" on-tap="onConfirmTap_"
+            disabled="[[!packDirectory_]]">
           $i18n{packDialogConfirm}
         </paper-button>
       </div>
     </dialog>
+    <template is="dom-if" if="[[lastResponse_]]" restamp>
+      <extensions-pack-dialog-alert model="[[lastResponse_]]"
+          on-warning-confirmed="onWarningConfirmed_" on-close="resetResponse_">
+      </extensions-pack-dialog-alert>
+    </template>
   </template>
   <script src="chrome://extensions/pack_dialog.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/md_extensions/pack_dialog.js b/chrome/browser/resources/md_extensions/pack_dialog.js
index 72840cd..c6c527fa 100644
--- a/chrome/browser/resources/md_extensions/pack_dialog.js
+++ b/chrome/browser/resources/md_extensions/pack_dialog.js
@@ -27,6 +27,8 @@
      * Packs the extension into a .crx.
      * @param {string} rootPath
      * @param {string} keyPath
+     * @param {number=} flag
+     * @param {function(chrome.developerPrivate.PackDirectoryResponse)=} callback
      */
     packExtension: assertNotReached,
   };
@@ -38,18 +40,20 @@
       delegate: Object,
 
       /** @private */
-      packDirectory_: String,
+      packDirectory_: {
+        type: String,
+        value: '',  // Initialized to trigger binding when attached.
+      },
 
       /** @private */
       keyFile_: String,
+
+      /** @private {?chrome.developerPrivate.PackDirectoryResponse} */
+      lastResponse_: Object,
     },
 
     show: function() {
-      this.$$('dialog').showModal();
-    },
-
-    close: function() {
-      this.$$('dialog').close();
+      this.$.dialog.showModal();
     },
 
     /** @private */
@@ -69,9 +73,43 @@
     },
 
     /** @private */
+    onCancelTap_: function() {
+      this.$.dialog.cancel();
+    },
+
+    /** @private */
     onConfirmTap_: function() {
-      this.delegate.packExtension(this.packDirectory_, this.keyFile_);
-      this.close();
+      this.delegate.packExtension(
+          this.packDirectory_, this.keyFile_, 0,
+          this.onPackResponse_.bind(this));
+    },
+
+    /**
+     * @param {chrome.developerPrivate.PackDirectoryResponse} response the
+     *    response from request to pack an extension.
+     * @private
+     */
+    onPackResponse_: function(response) {
+      if (response.status === chrome.developerPrivate.PackStatus.SUCCESS) {
+        this.$.dialog.close();
+      } else {
+        this.set('lastResponse_', response);
+      }
+    },
+
+    /**
+     * The handler function when user chooses to 'Proceed Anyway' upon
+     * receiving a waring.
+     * @private
+     */
+    onWarningConfirmed_: function() {
+      this.delegate.packExtension(
+          this.lastResponse_.item_path, this.lastResponse_.pem_path,
+          this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
+    },
+
+    resetResponse_: function() {
+      this.lastResponse_ = null;
     },
   });
 
diff --git a/chrome/browser/resources/md_extensions/pack_dialog_alert.html b/chrome/browser/resources/md_extensions/pack_dialog_alert.html
new file mode 100644
index 0000000..81810d8
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/pack_dialog_alert.html
@@ -0,0 +1,33 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+
+<dom-module id="extensions-pack-dialog-alert">
+  <template>
+    <style include="cr-shared-style paper-button-style">
+    </style>
+
+    <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+      <div class="title" slot="title">[[title_]]</div>
+      <div class="body" slot="body">
+        [[model.message]]
+      </div>
+      <div class="button-container" slot="button-container">
+        <paper-button class="cancel-button" on-tap="onCancelTap_"
+            hidden="[[!cancelLabel_]]">
+          [[cancelLabel_]]
+        </paper-button>
+        <paper-button class="action-button" on-tap="onConfirmTap_"
+            hidden="[[!confirmLabel_]]">
+          [[confirmLabel_]]
+        </paper-button>
+      </div>
+    </dialog>
+  </template>
+  <script src="chrome://extensions/pack_dialog_alert.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_extensions/pack_dialog_alert.js b/chrome/browser/resources/md_extensions/pack_dialog_alert.js
new file mode 100644
index 0000000..619dd80
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/pack_dialog_alert.js
@@ -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.
+
+cr.define('extensions', function() {
+  'use strict';
+
+  var PackDialogAlert = Polymer({
+    is: 'extensions-pack-dialog-alert',
+    properties: {
+      /** @private {chrome.developerPrivate.PackDirectoryResponse} */
+      model: Object,
+
+      /** @private */
+      title_: String,
+
+      /** @private */
+      message_: String,
+
+      /** @private */
+      cancelLabel_: String,
+
+      /** @private */
+      confirmLabel_: String,
+    },
+
+    /** @override */
+    ready: function() {
+      // Initialize button label values for initial html binding.
+      this.cancelLabel_ = null;
+      this.confirmLabel_ = null;
+
+      switch (this.model.status) {
+        case chrome.developerPrivate.PackStatus.WARNING:
+          this.title_ = loadTimeData.getString('packDialogWarningTitle');
+          this.cancelLabel_ = loadTimeData.getString('cancel');
+          this.confirmLabel_ =
+              loadTimeData.getString('packDialogProceedAnyway');
+          break;
+        case chrome.developerPrivate.PackStatus.ERROR:
+          this.title_ = loadTimeData.getString('packDialogErrorTitle');
+          this.cancelLabel_ = loadTimeData.getString('ok');
+          break;
+        // If status were success, this dialog should not be attached at all.
+        case chrome.developerPrivate.PackStatus.SUCCESS:
+        default:
+          assertNotReached();
+          return;
+      }
+    },
+
+    /** @override */
+    attached: function() {
+      this.$.dialog.showModal();
+    },
+
+    /** @private */
+    onCancelTap_: function() {
+      this.$.dialog.cancel();
+    },
+
+    /** @private */
+    onConfirmTap_: function() {
+      // The confirm button should only be available in WARNING state.
+      assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING);
+      this.fire('warning-confirmed');
+      this.$.dialog.close();
+    }
+  });
+
+  return {PackDialogAlert: PackDialogAlert};
+});
diff --git a/chrome/browser/resources/md_extensions/service.js b/chrome/browser/resources/md_extensions/service.js
index 8f173d8..722f8019 100644
--- a/chrome/browser/resources/md_extensions/service.js
+++ b/chrome/browser/resources/md_extensions/service.js
@@ -291,8 +291,8 @@
     }
 
     /** @override */
-    packExtension(rootPath, keyPath) {
-      chrome.developerPrivate.packDirectory(rootPath, keyPath);
+    packExtension(rootPath, keyPath, flag, callback) {
+      chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback);
     }
 
     /** @override */
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp b/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp
index 6d0df4cf..b61b25173 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp
@@ -52,7 +52,7 @@
       'target_name': 'password_list_item',
       'dependencies': [
         '../compiled_resources2.gyp:focus_row_behavior',
-        '<(EXTERNS_GYP):passwords_private',
+        'show_password_behavior',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
@@ -74,6 +74,13 @@
       'target_name': 'password_edit_dialog',
       'dependencies': [
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
+        'show_password_behavior',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'show_password_behavior',
+      'dependencies': [
         '<(EXTERNS_GYP):passwords_private',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
index 9d93f68c..f84bd88 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
 <link rel="import" href="../icons.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="show_password_behavior.html">
 
 <dom-module id="password-edit-dialog">
   <template>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
index 6d76f1b..e0f1de2 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.js
@@ -13,20 +13,10 @@
 Polymer({
   is: 'password-edit-dialog',
 
-  properties: {
-    /**
-     * The password that is being displayed.
-     * @type {!chrome.passwordsPrivate.PasswordUiEntry}
-     */
-    item: Object,
-
-    /** Holds the plaintext password when requested. */
-    password: String,
-  },
+  behaviors: [ShowPasswordBehavior],
 
   /** @override */
   attached: function() {
-    this.password = '';
     this.$.dialog.showModal();
   },
 
@@ -36,61 +26,6 @@
   },
 
   /**
-   * Gets the password input's type. Should be 'text' when password is visible
-   * or when there's federated text otherwise 'password'.
-   * @private
-   */
-  getPasswordInputType_: function() {
-    return this.password || this.item.federationText ? 'text' : 'password';
-  },
-
-  /**
-   * Gets the title text for the show/hide icon.
-   * @param {string} password
-   * @param {string} hide The i18n text to use for 'Hide'
-   * @param {string} show The i18n text to use for 'Show'
-   * @private
-   */
-  showPasswordTitle_: function(password, hide, show) {
-    return password ? hide : show;
-  },
-
-  /**
-   * Get the right icon to display when hiding/showing a password.
-   * @return {string}
-   * @private
-   */
-  getIconClass_: function() {
-    return this.password ? 'icon-visibility-off' : 'icon-visibility';
-  },
-
-  /**
-   * Gets the text of the password. Will use the value of |password| unless it
-   * cannot be shown, in which case it will be spaces. It can also be the
-   * federated text.
-   * @private
-   */
-  getPassword_: function() {
-    if (!this.item)
-      return '';
-
-    return this.item.federationText || this.password ||
-        ' '.repeat(this.item.numCharactersInPassword);
-  },
-
-  /**
-   * Handler for tapping the show/hide button. Will fire an event to request the
-   * password for this login pair.
-   * @private
-   */
-  onShowPasswordButtonTap_: function() {
-    if (this.password)
-      this.password = '';
-    else
-      this.fire('show-password', this.item.loginPair);  // Request the password.
-  },
-
-  /**
    * Handler for tapping the 'done' button. Should just dismiss the dialog.
    * @private
    */
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
index 765090e6..9414e73 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
@@ -5,6 +5,7 @@
 <link rel="import" href="../focus_row_behavior.html">
 <link rel="import" href="../settings_shared_css.html">
 <link rel="import" href="passwords_shared_css.html">
+<link rel="import" href="show_password_behavior.html">
 
 <dom-module id="password-list-item">
   <template>
@@ -18,6 +19,15 @@
          direction: rtl;
          display: flex;
       }
+
+      #password {
+        /* Since #password is an input element this is necessary to prevent
+         * Chrome from using the operating system's font instead of the Material
+         * Design font.
+         */
+        font-family: inherit;
+        font-size: inherit;
+      }
     </style>
     <div class="list-item" focus-row-container>
       <div class="website-column no-min-width"
@@ -36,21 +46,30 @@
            id="username">[[item.loginPair.username]]</div>
       <div class="password-column">
         <template is="dom-if" if="[[!item.federationText]]">
-          <!-- Password type and disabled in order to match mock. -->
           <input id="password" aria-label=$i18n{editPasswordPasswordLabel}
-              type="password" class="password-field text-elide" disabled
-              value="[[getEmptyPassword_(item.numCharactersInPassword)]]">
+              type="[[getPasswordInputType_(item, password)]]"
+              on-tap="onReadonlyInputTap_" class="password-field" readonly
+              value="[[getPassword_(item, password)]]">
           </input>
+          <button is="paper-icon-button-light" id="showPasswordButton"
+              class$="[[getIconClass_(item, password)]]"
+              on-tap="onShowPasswordButtonTap_"
+              title="[[showPasswordTitle_(password,
+                  '$i18nPolymer{hidePassword}','$i18nPolymer{showPassword}')]]"
+              focus-row-control focus-type="showPassword">
+          </button>
         </template>
         <template is="dom-if" if="[[item.federationText]]">
-          <span class="password-field text-elide">[[item.federationText]]</span>
+          <span class="password-field text-elide" id="federated">
+            [[item.federationText]]
+          </span>
         </template>
-        <button is="paper-icon-button-light" id="passwordMenu"
-            class="icon-more-vert" on-tap="onPasswordMenuTap_"
-            title="$i18n{moreActions}" focus-row-control
-            focus-type="passwordMenu">
-        </button>
       </div>
+      <button is="paper-icon-button-light" id="passwordMenu"
+          class="icon-more-vert" on-tap="onPasswordMenuTap_"
+          title="$i18n{moreActions}" focus-row-control
+          focus-type="passwordMenu">
+      </button>
     </div>
   </template>
   <script src="password_list_item.js"></script>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js
index 688d934e..1ade257 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.js
@@ -10,24 +10,15 @@
 Polymer({
   is: 'password-list-item',
 
-  behaviors: [FocusRowBehavior],
-
-  properties: {
-    /**
-     * The password whose info should be displayed.
-     * @type {!chrome.passwordsPrivate.PasswordUiEntry}
-     */
-    item: Array,
-  },
+  behaviors: [FocusRowBehavior, ShowPasswordBehavior],
 
   /**
-   * Creates an empty password of specified length.
-   * @param {number} length
-   * @return {string} password
+   * Selects the password on tap if revealed.
    * @private
    */
-  getEmptyPassword_: function(length) {
-    return ' '.repeat(length);
+  onReadonlyInputTap_: function() {
+    if (this.password)
+      this.$$('#password').select();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
index cd9e9052..8f18056 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -18,7 +18,16 @@
 
 <dom-module id="passwords-section">
   <template>
-    <style include="settings-shared passwords-shared"></style>
+    <style include="settings-shared passwords-shared">
+      #savedPasswordsHeading {
+        /* This adds enough padding so that the labels are aligned with the
+         * columns. It is necessary due to the absence of the "more actions"
+         * button in the heading.
+         */
+        -webkit-padding-end: calc(
+          var(--cr-icon-ripple-size) + var(--cr-icon-button-margin-start));
+      }
+   </style>
     <div class="settings-box first">
       <settings-toggle-button id="passwordToggle" class="start primary-toggle"
           aria-label="$i18n{passwords}" no-extension-indicator
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
index c7c941b94..53525e7 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
@@ -277,19 +277,6 @@
   },
 
   /**
-   * Sets the password in the current password dialog if the loginPair matches.
-   * @param {!chrome.passwordsPrivate.LoginPair} loginPair
-   * @param {string} password
-   */
-  setPassword: function(loginPair, password) {
-    if (this.activePassword &&
-        this.activePassword.loginPair.urls.origin == loginPair.urls.origin &&
-        this.activePassword.loginPair.username == loginPair.username) {
-      this.$$('password-edit-dialog').password = password;
-    }
-  },
-
-  /**
    * Shows the edit password dialog.
    * @param {!Event} e
    * @private
@@ -385,8 +372,9 @@
    */
   showPassword_: function(event) {
     this.passwordManager_.getPlaintextPassword(
-        /** @type {!PasswordManager.LoginPair} */ (event.detail), item => {
-          this.setPassword(item.loginPair, item.plaintextPassword);
+        /** @type {!PasswordManager.LoginPair} */ (event.detail.item.loginPair),
+        item => {
+          event.detail.password = item.plaintextPassword;
         });
   },
 
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
index 0933fe0..5bcd1e9 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
@@ -13,18 +13,18 @@
 
       .website-column {
         display: flex;
-        flex: 3;
+        flex: 1;
       }
 
       .username-column {
-        flex: 2;
+        flex: 1;
         margin: 0 8px;
       }
 
       .password-column {
         align-items: center;
         display: flex;
-        flex: 2;
+        flex: 1;
       }
 
       .password-field {
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.html b/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.html
new file mode 100644
index 0000000..73ee8c0
--- /dev/null
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<script src="show_password_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js b/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js
new file mode 100644
index 0000000..8c4a54b
--- /dev/null
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/show_password_behavior.js
@@ -0,0 +1,85 @@
+// 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.
+
+/**
+ * This behavior bundles functionality required to show a password to the user.
+ * It is used by both <password-list-item> and <password-edit-dialog>.
+ *
+ * @polymerBehavior
+ */
+var ShowPasswordBehavior = {
+
+  properties: {
+    /**
+     * The password that is being displayed.
+     * @type {!chrome.passwordsPrivate.PasswordUiEntry}
+     */
+    item: Object,
+
+    /**
+     * Holds the plaintext password when requested.
+     * Initializing it to the empty string is necessary to indicate that the
+     * password hasn't been fetched yet.
+     */
+    password: {
+      type: String,
+      value: '',
+    },
+  },
+
+  /**
+   * Gets the password input's type. Should be 'text' when password is visible
+   * or when there's federated text otherwise 'password'.
+   * @private
+   */
+  getPasswordInputType_: function() {
+    return this.password || this.item.federationText ? 'text' : 'password';
+  },
+
+  /**
+   * Gets the title text for the show/hide icon.
+   * @param {string} password
+   * @param {string} hide The i18n text to use for 'Hide'
+   * @param {string} show The i18n text to use for 'Show'
+   * @private
+   */
+  showPasswordTitle_: function(password, hide, show) {
+    return password ? hide : show;
+  },
+
+  /**
+   * Get the right icon to display when hiding/showing a password.
+   * @return {string}
+   * @private
+   */
+  getIconClass_: function() {
+    return this.password ? 'icon-visibility-off' : 'icon-visibility';
+  },
+
+  /**
+   * Gets the text of the password. Will use the value of |password| unless it
+   * cannot be shown, in which case it will be spaces. It can also be the
+   * federated text.
+   * @private
+   */
+  getPassword_: function() {
+    if (!this.item)
+      return '';
+
+    return this.item.federationText || this.password ||
+        ' '.repeat(this.item.numCharactersInPassword);
+  },
+
+  /**
+   * Handler for tapping the show/hide button. Will fire an event to request the
+   * password for this login pair.
+   * @private
+   */
+  onShowPasswordButtonTap_: function() {
+    if (this.password)
+      this.password = '';
+    else
+      this.fire('show-password', this);  // Request the password.
+  },
+};
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index eb33929..cbd941e 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -714,6 +714,12 @@
       <structure name="IDR_SETTINGS_ADDRESS_EDIT_DIALOG_JS"
                  file="passwords_and_forms_page/address_edit_dialog.js"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_SHOW_PASSWORD_BEHAVIOR_HTML"
+                 file="passwords_and_forms_page/show_password_behavior.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SHOW_PASSWORD_BEHAVIOR_JS"
+                 file="passwords_and_forms_page/show_password_behavior.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_PASSWORD_LIST_ITEM_HTML"
                  file="passwords_and_forms_page/password_list_item.html"
                  type="chrome_html" />
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
index dcba4d2..ec2798a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -1166,14 +1166,9 @@
                            referrer_chain.Get(2));
 }
 
-#if defined(OS_WIN)
-#define MAYBE_SubFrameDirectDownload DISABLED_SubFrameDirectDownload
-#else
-#define MAYBE_SubFrameDirectDownload SubFrameDirectDownload
-#endif
 // Click a link in a subframe and start download.
 IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
-                       MAYBE_SubFrameDirectDownload) {
+                       SubFrameDirectDownload) {
   GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
   ClickTestLink("sub_frame_download_attribution", 1, initial_url);
   std::string test_name =
@@ -1205,22 +1200,43 @@
                         true,                  // has_committed
                         false,                 // has_server_redirect
                         nav_list->Get(1));
-  VerifyNavigationEvent(GURL(),                // source_url
-                        multi_frame_test_url,  // source_main_frame_url
-                        iframe_url,            // original_request_url
-                        iframe_url,            // destination_url
-                        false,                 // is_user_initiated,
-                        true,                  // has_committed
-                        false,                 // has_server_redirect
-                        nav_list->Get(2));
-  VerifyNavigationEvent(GURL(),                  // source_url
-                        multi_frame_test_url,    // source_main_frame_url
-                        iframe_retargeting_url,  // original_request_url
-                        iframe_retargeting_url,  // destination_url
-                        false,                   // is_user_initiated,
-                        true,                    // has_committed
-                        false,                   // has_server_redirect
-                        nav_list->Get(3));
+  // The order of the next two navigation events may vary. We check for both
+  // possibilities. Their order doesn't impact referrer chain attribution logic.
+  if (nav_list->Get(2)->original_request_url == iframe_url) {
+    VerifyNavigationEvent(GURL(),                // source_url
+                          multi_frame_test_url,  // source_main_frame_url
+                          iframe_url,            // original_request_url
+                          iframe_url,            // destination_url
+                          false,                 // is_user_initiated,
+                          true,                  // has_committed
+                          false,                 // has_server_redirect
+                          nav_list->Get(2));
+    VerifyNavigationEvent(GURL(),                  // source_url
+                          multi_frame_test_url,    // source_main_frame_url
+                          iframe_retargeting_url,  // original_request_url
+                          iframe_retargeting_url,  // destination_url
+                          false,                   // is_user_initiated,
+                          true,                    // has_committed
+                          false,                   // has_server_redirect
+                          nav_list->Get(3));
+  } else {
+    VerifyNavigationEvent(GURL(),                  // source_url
+                          multi_frame_test_url,    // source_main_frame_url
+                          iframe_retargeting_url,  // original_request_url
+                          iframe_retargeting_url,  // destination_url
+                          false,                   // is_user_initiated,
+                          true,                    // has_committed
+                          false,                   // has_server_redirect
+                          nav_list->Get(2));
+    VerifyNavigationEvent(GURL(),                // source_url
+                          multi_frame_test_url,  // source_main_frame_url
+                          iframe_url,            // original_request_url
+                          iframe_url,            // destination_url
+                          false,                 // is_user_initiated,
+                          true,                  // has_committed
+                          false,                 // has_server_redirect
+                          nav_list->Get(3));
+  }
   VerifyNavigationEvent(iframe_url,            // source_url
                         multi_frame_test_url,  // source_main_frame_url
                         download_url,          // original_request_url
@@ -1272,14 +1288,9 @@
                            referrer_chain.Get(3));
 }
 
-#if defined(OS_WIN)
-#define MAYBE_SubFrameNewTabDownload DISABLED_SubFrameNewTabDownload
-#else
-#define MAYBE_SubFrameNewTabDownload SubFrameNewTabDownload
-#endif
 // Click a link in a subframe and open download in a new tab.
 IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
-                       MAYBE_SubFrameNewTabDownload) {
+                       SubFrameNewTabDownload) {
   GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
   ClickTestLink("sub_frame_download_attribution", 1, initial_url);
   std::string test_name =
@@ -1312,22 +1323,43 @@
                         true,                  // has_committed
                         false,                 // has_server_redirect
                         nav_list->Get(1));
-  VerifyNavigationEvent(GURL(),                // source_url
-                        multi_frame_test_url,  // source_main_frame_url
-                        iframe_url,            // original_request_url
-                        iframe_url,            // destination_url
-                        false,                 // is_user_initiated,
-                        true,                  // has_committed
-                        false,                 // has_server_redirect
-                        nav_list->Get(2));
-  VerifyNavigationEvent(GURL(),                  // source_url
-                        multi_frame_test_url,    // source_main_frame_url
-                        iframe_retargeting_url,  // original_request_url
-                        iframe_retargeting_url,  // destination_url
-                        false,                   // is_user_initiated,
-                        true,                    // has_committed
-                        false,                   // has_server_redirect
-                        nav_list->Get(3));
+  // The order of the next two navigation events may vary. We check for both
+  // possibilities. Their order doesn't impact referrer chain attribution logic.
+  if (nav_list->Get(2)->original_request_url == iframe_url) {
+    VerifyNavigationEvent(GURL(),                // source_url
+                          multi_frame_test_url,  // source_main_frame_url
+                          iframe_url,            // original_request_url
+                          iframe_url,            // destination_url
+                          false,                 // is_user_initiated,
+                          true,                  // has_committed
+                          false,                 // has_server_redirect
+                          nav_list->Get(2));
+    VerifyNavigationEvent(GURL(),                  // source_url
+                          multi_frame_test_url,    // source_main_frame_url
+                          iframe_retargeting_url,  // original_request_url
+                          iframe_retargeting_url,  // destination_url
+                          false,                   // is_user_initiated,
+                          true,                    // has_committed
+                          false,                   // has_server_redirect
+                          nav_list->Get(3));
+  } else {
+    VerifyNavigationEvent(GURL(),                  // source_url
+                          multi_frame_test_url,    // source_main_frame_url
+                          iframe_retargeting_url,  // original_request_url
+                          iframe_retargeting_url,  // destination_url
+                          false,                   // is_user_initiated,
+                          true,                    // has_committed
+                          false,                   // has_server_redirect
+                          nav_list->Get(2));
+    VerifyNavigationEvent(GURL(),                // source_url
+                          multi_frame_test_url,  // source_main_frame_url
+                          iframe_url,            // original_request_url
+                          iframe_url,            // destination_url
+                          false,                 // is_user_initiated,
+                          true,                  // has_committed
+                          false,                 // has_server_redirect
+                          nav_list->Get(3));
+  }
   VerifyNavigationEvent(iframe_retargeting_url,  // source_url
                         multi_frame_test_url,    // source_main_frame_url
                         blank_url,               // original_request_url
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 6db5577..b84ce84 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -225,6 +225,7 @@
       web_contents = chrome::ReplaceRestoredTab(
           browser, tab.navigations, selected_index, true, tab.extension_app_id,
           nullptr, tab.user_agent_override);
+      SessionRestore::OnWillRestoreTab(web_contents);
     } else {
       int tab_index =
           use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1;
@@ -233,6 +234,7 @@
           tab.extension_app_id,
           disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB,  // selected
           tab.pinned, true, nullptr, tab.user_agent_override);
+      SessionRestore::OnWillRestoreTab(web_contents);
       // Start loading the tab immediately.
       web_contents->GetController().LoadIfNecessary();
     }
@@ -604,6 +606,8 @@
     if (!web_contents)
       return;
 
+    SessionRestore::OnWillRestoreTab(web_contents);
+
     // Sanitize the last active time.
     base::TimeDelta delta = highest_time - tab.last_active_time;
     web_contents->SetLastActiveTime(now - delta);
@@ -875,6 +879,12 @@
 }
 
 // static
+void SessionRestore::OnWillRestoreTab(content::WebContents* web_contents) {
+  for (auto& observer : *observers())
+    observer.OnWillRestoreTab(web_contents);
+}
+
+// static
 base::CallbackList<void(int)>*
     SessionRestore::on_session_restored_callbacks_ = nullptr;
 
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h
index 17090a5..77fa7c0a 100644
--- a/chrome/browser/sessions/session_restore.h
+++ b/chrome/browser/sessions/session_restore.h
@@ -152,6 +152,9 @@
   // the first session restore.
   static void NotifySessionRestoreStartedLoadingTabs();
 
+  // Is called when session restore is going to restore a tab.
+  static void OnWillRestoreTab(content::WebContents* web_contents);
+
   // Contains all registered observers for session restore events.
   static SessionRestoreObserverList* observers_;
 
diff --git a/chrome/browser/sessions/session_restore_observer.h b/chrome/browser/sessions/session_restore_observer.h
index e9ee48dd..75d97b8 100644
--- a/chrome/browser/sessions/session_restore_observer.h
+++ b/chrome/browser/sessions/session_restore_observer.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_
 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_
 
+namespace content {
+class WebContents;
+}
+
 // Observer of events during session restore. This observer does not cover
 // SessionRestoreImpl::RestoreForeignTab() which restores a single foreign tab.
 class SessionRestoreObserver {
@@ -22,6 +26,10 @@
   // of memory pressure). This is called on the last session restore when
   // multiple concurrent session restores (on all profiles) occur.
   virtual void OnSessionRestoreFinishedLoadingTabs() {}
+
+  // OnWillRestoreTab() is called right after a tab is created by session
+  // restore.
+  virtual void OnWillRestoreTab(content::WebContents* web_contents) {}
 };
 
 #endif  // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_OBSERVER_H_
diff --git a/chrome/browser/sessions/session_restore_observer_unittest.cc b/chrome/browser/sessions/session_restore_observer_unittest.cc
index 6493d22..1845c17 100644
--- a/chrome/browser/sessions/session_restore_observer_unittest.cc
+++ b/chrome/browser/sessions/session_restore_observer_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/sessions/session_restore_observer.h"
 
+#include <set>
+#include <vector>
+
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -35,19 +38,30 @@
     return session_restore_events_;
   }
 
+  const std::set<content::WebContents*>& tabs_restoring() const {
+    return tabs_restoring_;
+  }
+
   // SessionRestoreObserver implementation:
   void OnSessionRestoreStartedLoadingTabs() override {
     session_restore_events_.emplace_back(
         SessionRestoreEvent::STARTED_LOADING_TABS);
   }
-
   void OnSessionRestoreFinishedLoadingTabs() override {
     session_restore_events_.emplace_back(
         SessionRestoreEvent::FINISHED_LOADING_TABS);
   }
+  void OnWillRestoreTab(content::WebContents* contents) override {
+    tabs_restoring_.emplace(contents);
+  }
+
+  void OnDidRestoreTab(content::WebContents* contents) {
+    tabs_restoring_.erase(contents);
+  }
 
  private:
   std::vector<SessionRestoreEvent> session_restore_events_;
+  std::set<content::WebContents*> tabs_restoring_;
 
   DISALLOW_COPY_AND_ASSIGN(MockSessionRestoreObserver);
 };
@@ -77,6 +91,7 @@
   void LoadWebContents(content::WebContents* contents) {
     WebContentsTester::For(contents)->NavigateAndCommit(GURL(kDefaultUrl));
     WebContentsTester::For(contents)->TestSetIsLoading(false);
+    mock_observer_.OnDidRestoreTab(contents);
   }
 
   const std::vector<MockSessionRestoreObserver::SessionRestoreEvent>&
@@ -88,6 +103,10 @@
     return session_restore_events().size();
   }
 
+  size_t number_of_tabs_restoring() const {
+    return mock_observer_.tabs_restoring().size();
+  }
+
  private:
   MockSessionRestoreObserver mock_observer_;
   std::vector<RestoredTab> restored_tabs_;
@@ -97,35 +116,53 @@
 
 TEST_F(SessionRestoreObserverTest, SingleSessionRestore) {
   SessionRestore::NotifySessionRestoreStartedLoadingTabs();
+  SessionRestore::OnWillRestoreTab(web_contents());
   RestoreTabs();
+
   ASSERT_EQ(1u, number_of_session_restore_events());
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS,
       session_restore_events()[0]);
+  EXPECT_EQ(1u, number_of_tabs_restoring());
 
   LoadWebContents(web_contents());
+
   ASSERT_EQ(2u, number_of_session_restore_events());
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS,
       session_restore_events()[1]);
+  EXPECT_EQ(0u, number_of_tabs_restoring());
 }
 
 TEST_F(SessionRestoreObserverTest, SequentialSessionRestores) {
-  const int number_of_session_restores = 3;
+  const size_t number_of_session_restores = 3;
   size_t event_index = 0;
-  for (int i = 0; i < number_of_session_restores; ++i) {
+  std::vector<std::unique_ptr<content::WebContents>> different_test_contents;
+
+  for (size_t i = 0; i < number_of_session_restores; ++i) {
+    different_test_contents.emplace_back(
+        WebContentsTester::CreateTestWebContents(browser_context(), nullptr));
+    content::WebContents* test_contents = different_test_contents.back().get();
+    std::vector<RestoredTab> restored_tabs{
+        RestoredTab(test_contents, false, false, false)};
+
     SessionRestore::NotifySessionRestoreStartedLoadingTabs();
-    RestoreTabs();
+    SessionRestore::OnWillRestoreTab(test_contents);
+    TabLoader::RestoreTabs(restored_tabs, base::TimeTicks());
+
     ASSERT_EQ(event_index + 1, number_of_session_restore_events());
     EXPECT_EQ(
         MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS,
         session_restore_events()[event_index++]);
+    EXPECT_EQ(1u, number_of_tabs_restoring());
 
-    LoadWebContents(web_contents());
+    LoadWebContents(test_contents);
+
     ASSERT_EQ(event_index + 1, number_of_session_restore_events());
     EXPECT_EQ(
         MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS,
         session_restore_events()[event_index++]);
+    EXPECT_EQ(0u, number_of_tabs_restoring());
   }
 }
 
@@ -136,12 +173,16 @@
   another_restored_tabs.emplace_back(test_contents.get(), false, false, false);
 
   SessionRestore::NotifySessionRestoreStartedLoadingTabs();
+  SessionRestore::OnWillRestoreTab(web_contents());
+  SessionRestore::OnWillRestoreTab(test_contents.get());
   RestoreTabs();
   TabLoader::RestoreTabs(another_restored_tabs, base::TimeTicks());
+
   ASSERT_EQ(1u, number_of_session_restore_events());
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::STARTED_LOADING_TABS,
       session_restore_events()[0]);
+  EXPECT_EQ(2u, number_of_tabs_restoring());
 
   LoadWebContents(web_contents());
   LoadWebContents(test_contents.get());
@@ -150,6 +191,7 @@
   EXPECT_EQ(
       MockSessionRestoreObserver::SessionRestoreEvent::FINISHED_LOADING_TABS,
       session_restore_events()[1]);
+  EXPECT_EQ(0u, number_of_tabs_restoring());
 }
 
 TEST_F(SessionRestoreObserverTest, TabManagerShouldObserveSessionRestore) {
@@ -163,13 +205,17 @@
   resource_coordinator::TabManager* tab_manager =
       g_browser_process->GetTabManager();
   EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_FALSE(tab_manager->IsTabInSessionRestore(test_contents.get()));
 
   SessionRestore::NotifySessionRestoreStartedLoadingTabs();
+  SessionRestore::OnWillRestoreTab(test_contents.get());
   EXPECT_TRUE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_TRUE(tab_manager->IsTabInSessionRestore(test_contents.get()));
   TabLoader::RestoreTabs(restored_tabs, base::TimeTicks());
 
   WebContentsTester::For(test_contents.get())
       ->NavigateAndCommit(GURL("about:blank"));
   WebContentsTester::For(test_contents.get())->TestSetIsLoading(false);
   EXPECT_FALSE(tab_manager->IsSessionRestoreLoadingTabs());
+  EXPECT_FALSE(tab_manager->IsTabInSessionRestore(test_contents.get()));
 }
diff --git a/chrome/browser/task_manager/providers/child_process_task.cc b/chrome/browser/task_manager/providers/child_process_task.cc
index 5831758..cde7dba5 100644
--- a/chrome/browser/task_manager/providers/child_process_task.cc
+++ b/chrome/browser/task_manager/providers/child_process_task.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/command_line.h"
 #include "base/i18n/rtl.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -13,6 +14,7 @@
 #include "chrome/browser/process_resource_usage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/task_manager/task_manager_observer.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/nacl/common/nacl_process_type.h"
@@ -98,9 +100,16 @@
       return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NACL_PREFIX,
                                         result_title);
     }
+    case content::PROCESS_TYPE_RENDERER: {
+      // TODO: (cburn) Start the UI Localization process for this. Currently the
+      // best name for this is "Renderer".
+      if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kTaskManagerShowExtraRenderers)) {
+        return base::ASCIIToUTF16("Renderer");
+      }
+    }
     // These types don't need display names or get them from elsewhere.
     case content::PROCESS_TYPE_BROWSER:
-    case content::PROCESS_TYPE_RENDERER:
     case content::PROCESS_TYPE_ZYGOTE:
     case content::PROCESS_TYPE_SANDBOX_HELPER:
     case content::PROCESS_TYPE_MAX:
@@ -210,6 +219,8 @@
     case PROCESS_TYPE_NACL_LOADER:
     case PROCESS_TYPE_NACL_BROKER:
       return Task::NACL;
+    case content::PROCESS_TYPE_RENDERER:
+      return Task::RENDERER;
     default:
       return Task::UNKNOWN;
   }
diff --git a/chrome/browser/task_manager/providers/render_process_host_task_provider.cc b/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
new file mode 100644
index 0000000..e695f94
--- /dev/null
+++ b/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
@@ -0,0 +1,126 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/task_manager/providers/render_process_host_task_provider.h"
+
+#include "base/process/process.h"
+#include "chrome/browser/task_manager/providers/child_process_task.h"
+#include "content/public/browser/browser_child_process_host_iterator.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/process_type.h"
+#include "extensions/features/features.h"
+
+using content::RenderProcessHost;
+using content::BrowserThread;
+using content::ChildProcessData;
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/browser/process_map.h"
+#endif
+
+namespace task_manager {
+
+RenderProcessHostTaskProvider::RenderProcessHostTaskProvider()
+    : weak_ptr_factory_(this) {
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+}
+
+RenderProcessHostTaskProvider::~RenderProcessHostTaskProvider() {}
+
+Task* RenderProcessHostTaskProvider::GetTaskOfUrlRequest(int origin_pid,
+                                                         int child_id,
+                                                         int route_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  auto itr = tasks_by_rph_id_.find(child_id);
+  if (itr == tasks_by_rph_id_.end())
+    return nullptr;
+
+  return itr->second.get();
+}
+
+void RenderProcessHostTaskProvider::StartUpdating() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(tasks_by_rph_id_.empty());
+  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+       !it.IsAtEnd(); it.Advance()) {
+    RenderProcessHost* host = it.GetCurrentValue();
+    if (host->GetHandle()) {
+      CreateTask(host->GetID());
+    } else {
+      // If the host isn't ready do nothing and we will learn of its creation
+      // from the notification service.
+    }
+  }
+}
+
+void RenderProcessHostTaskProvider::StopUpdating() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  // Then delete all tasks (if any).
+  tasks_by_rph_id_.clear();
+}
+
+void RenderProcessHostTaskProvider::CreateTask(
+    const int render_process_host_id) {
+  // Checks that the task by RenderProcessHost ID isn't already a task in the
+  // map and deletes it if it is so they new task can be cleanly added.
+  DeleteTask(render_process_host_id);
+  std::unique_ptr<ChildProcessTask>& task =
+      tasks_by_rph_id_[render_process_host_id];
+
+  RenderProcessHost* host = RenderProcessHost::FromID(render_process_host_id);
+
+  // Create the task and notify the observer.
+  ChildProcessData data(content::PROCESS_TYPE_RENDERER);
+  data.handle = host->GetHandle();
+  data.id = host->GetID();
+  task.reset(new ChildProcessTask(data));
+  NotifyObserverTaskAdded(task.get());
+}
+
+void RenderProcessHostTaskProvider::DeleteTask(
+    const int render_process_host_id) {
+  auto itr = tasks_by_rph_id_.find(render_process_host_id);
+  // If the render process host id isn't being tracked in |tasks_by_rph_id| do
+  // nothing.
+  if (itr == tasks_by_rph_id_.end())
+    return;
+
+  NotifyObserverTaskRemoved(itr->second.get());
+
+  // Finally delete the task.
+  tasks_by_rph_id_.erase(itr);
+}
+
+void RenderProcessHostTaskProvider::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  content::RenderProcessHost* host =
+      content::Source<content::RenderProcessHost>(source).ptr();
+  ChildProcessData data(content::PROCESS_TYPE_RENDERER);
+  switch (type) {
+    case content::NOTIFICATION_RENDERER_PROCESS_CREATED:
+      CreateTask(host->GetID());
+      break;
+    case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
+    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
+      DeleteTask(host->GetID());
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+}  // namespace task_manager
diff --git a/chrome/browser/task_manager/providers/render_process_host_task_provider.h b/chrome/browser/task_manager/providers/render_process_host_task_provider.h
new file mode 100644
index 0000000..9b9fd7c0
--- /dev/null
+++ b/chrome/browser/task_manager/providers/render_process_host_task_provider.h
@@ -0,0 +1,69 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TASK_MANAGER_PROVIDERS_RENDER_PROCESS_HOST_TASK_PROVIDER_H_
+#define CHROME_BROWSER_TASK_MANAGER_PROVIDERS_RENDER_PROCESS_HOST_TASK_PROVIDER_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/task_manager/providers/task_provider.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+
+namespace task_manager {
+
+class ChildProcessTask;
+
+// Defines a provider to provide possibly redundant tasks that represent RPHs
+// that are active. This can track interstitial pages and tracks RPHs that have
+// service workers still alive in them.
+class RenderProcessHostTaskProvider : public TaskProvider,
+                                      public content::NotificationObserver {
+ public:
+  RenderProcessHostTaskProvider();
+  ~RenderProcessHostTaskProvider() override;
+
+  // task_manager::TaskProvider:
+  Task* GetTaskOfUrlRequest(int origin_pid,
+                            int child_id,
+                            int route_id) override;
+
+  // content::NotificationObserver:
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override;
+
+ private:
+  // task_manager::TaskProvider:
+  void StartUpdating() override;
+  void StopUpdating() override;
+
+  // Creates a RenderProcessHostTask from the given |data| and notifies the
+  // observer of its addition.
+  void CreateTask(const int render_process_host_id);
+
+  // Deletes a RenderProcessHostTask whose |render_process_host_ID| is provided
+  // after notifying the observer of its deletion.
+  void DeleteTask(const int render_process_host_id);
+
+  std::map<int, std::unique_ptr<ChildProcessTask>> tasks_by_rph_id_;
+
+  // Object for registering notification requests.
+  content::NotificationRegistrar registrar_;
+
+  // Always keep this the last member of this class to make sure it's the
+  // first thing to be destructed.
+  base::WeakPtrFactory<RenderProcessHostTaskProvider> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderProcessHostTaskProvider);
+};
+
+}  // namespace task_manager
+
+#endif  // CHROME_BROWSER_TASK_MANAGER_PROVIDERS_RENDER_PROCESS_HOST_TASK_PROVIDER_H_
diff --git a/chrome/browser/task_manager/providers/task.cc b/chrome/browser/task_manager/providers/task.cc
index 9fe047f2..565aeaa 100644
--- a/chrome/browser/task_manager/providers/task.cc
+++ b/chrome/browser/task_manager/providers/task.cc
@@ -69,10 +69,17 @@
 }
 
 bool Task::IsKillable() {
+  // Protects from trying to kill a task that doesn't have an accurate process
+  // Id yet. This can result in calling "kill 0" which kills all processes in
+  // the process group.
+  if (process_id() == base::kNullProcessId)
+    return false;
   return true;
 }
 
 void Task::Kill() {
+  if (!IsKillable())
+    return;
   DCHECK_NE(process_id(), base::GetCurrentProcId());
   base::Process process = base::Process::Open(process_id());
   process.Terminate(content::RESULT_CODE_KILLED, false);
diff --git a/chrome/browser/task_manager/providers/web_contents/renderer_task.cc b/chrome/browser/task_manager/providers/web_contents/renderer_task.cc
index 0a5376a..187b4e5 100644
--- a/chrome/browser/task_manager/providers/web_contents/renderer_task.cc
+++ b/chrome/browser/task_manager/providers/web_contents/renderer_task.cc
@@ -74,8 +74,6 @@
       profile_name_(GetRendererProfileName(render_process_host_)),
       termination_status_(base::TERMINATION_STATUS_STILL_RUNNING),
       termination_error_code_(0) {
-  // All renderer tasks are capable of reporting network usage, so the default
-  // invalid value of -1 doesn't apply here.
   OnNetworkBytesRead(0);
 
   // Tag the web_contents with a |ContentFaviconDriver| (if needed) so that
diff --git a/chrome/browser/task_manager/sampling/task_group_unittest.cc b/chrome/browser/task_manager/sampling/task_group_unittest.cc
index 8852e46a..33220c8 100644
--- a/chrome/browser/task_manager/sampling/task_group_unittest.cc
+++ b/chrome/browser/task_manager/sampling/task_group_unittest.cc
@@ -342,7 +342,7 @@
 }
 
 // Tests that the network usage rate does not get affected until a refresh is
-// called and that the cumulative is as up to date as possible
+// called and that the cumulative is as up to date as possible.
 TEST_F(TaskGroupTest, NetworkBytesTransferredRefreshOutOfOrder) {
   const int read_bytes = 1024;
   const int sent_bytes = 1;
@@ -429,7 +429,7 @@
 
 // Tests that after two tasks in a task group read bytes that a refresh will
 // zero out network usage rate while maintaining the correct cumulative network
-// usage
+// usage.
 TEST_F(TaskGroupTest, NetworkBytesReadAsGroupThenNone) {
   const int read_bytes1 = 1013;
   const int read_bytes2 = 679;
@@ -459,7 +459,7 @@
 
 // Tests that after two tasks in a task group send bytes that a refresh will
 // zero out network usage rate while maintaining the correct cumulative network
-// usage
+// usage.
 TEST_F(TaskGroupTest, NetworkBytesSentAsGroupThenNone) {
   const int sent_bytes1 = 1023;
   const int sent_bytes2 = 678;
@@ -489,7 +489,7 @@
 
 // Tests that after two tasks in a task group transferred bytes that a refresh
 // will zero out network usage rate while maintaining the correct cumulative
-// network usage
+// network usage.
 TEST_F(TaskGroupTest, NetworkBytesTransferredAsGroupThenNone) {
   const int read_bytes = 321;
   const int sent_bytes = 987;
@@ -517,4 +517,10 @@
             task_group_.cumulative_per_process_network_usage());
 }
 
+// Test the task can't be killed with a PID of base::kNullProcessId.
+TEST_F(TaskGroupTest, TaskWithPidZero) {
+  FakeTask fake_task(base::kNullProcessId, Task::RENDERER);
+  EXPECT_FALSE(fake_task.IsKillable());
+}
+
 }  // namespace task_manager
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.cc b/chrome/browser/task_manager/sampling/task_manager_impl.cc
index 9885a76..0b154eb 100644
--- a/chrome/browser/task_manager/sampling/task_manager_impl.cc
+++ b/chrome/browser/task_manager/sampling/task_manager_impl.cc
@@ -10,13 +10,16 @@
 #include <unordered_set>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/containers/adapters.h"
 #include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/task_manager/providers/browser_process_task_provider.h"
 #include "chrome/browser/task_manager/providers/child_process_task_provider.h"
+#include "chrome/browser/task_manager/providers/render_process_host_task_provider.h"
 #include "chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.h"
 #include "chrome/browser/task_manager/sampling/shared_sampler.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/render_frame_host.h"
@@ -52,6 +55,11 @@
   task_providers_.emplace_back(new BrowserProcessTaskProvider());
   task_providers_.emplace_back(new ChildProcessTaskProvider());
   task_providers_.emplace_back(new WebContentsTaskProvider());
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTaskManagerShowExtraRenderers)) {
+    task_providers_.emplace_back(new RenderProcessHostTaskProvider());
+  }
+
 #if defined(OS_CHROMEOS)
   if (arc::IsArcAvailable())
     task_providers_.emplace_back(new ArcProcessTaskProvider());
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
index 8e3ac4d..b872cfa 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
@@ -115,12 +115,13 @@
 // an NSTableView. Future events may make cause the table view to query its
 // dataSource, which will have been deallocated.
 //
-// Linking against the 10.12 SDK does not "fix" this issue, since
-// NSTableView.dataSource is a "weak" reference, which in non-ARC land still
-// translates to "raw pointer".
+// NSTableView.dataSource becomes a zeroing weak reference starting in 10.11,
+// so this workaround can be removed once we're on the 10.11 SDK.
 //
-// See https://crbug.com/653093, https://crbug.com/750242 and rdar://29409207
-// for more information.
+// See https://crbug.com/653093 and rdar://29409207 for more information.
+
+#if !defined(MAC_OS_X_VERSION_10_11) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
 
 void ClearTableViewDataSources(NSView* view) {
   if (auto table_view = base::mac::ObjCCast<NSTableView>(view)) {
@@ -150,6 +151,12 @@
                             base::Unretained(leaked_window)));
 }
 
+#else
+
+void ClearTableViewDataSourcesIfNeeded(NSWindow*) {}
+
+#endif  // MAC_OS_X_VERSION_10_11
+
 }  // namespace
 
 @implementation SSLClientCertificateSelectorCocoa
diff --git a/chrome/browser/ui/cocoa/web_textfield_touch_bar_controller.mm b/chrome/browser/ui/cocoa/web_textfield_touch_bar_controller.mm
index 5746887..d4a0ffc2 100644
--- a/chrome/browser/ui/cocoa/web_textfield_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/web_textfield_touch_bar_controller.mm
@@ -31,7 +31,10 @@
 
   window_ = [popupView window];
 
+  // Remove any existing notifications before registering for new ones.
   NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+  [center removeObserver:self name:NSWindowWillCloseNotification object:nil];
+
   [center addObserver:self
              selector:@selector(popupWindowWillClose:)
                  name:NSWindowWillCloseNotification
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index f6b72930..54067f9 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -109,6 +109,8 @@
 
   // Add common strings.
   source->AddLocalizedString("close", IDS_CLOSE);
+  source->AddLocalizedString("ok", IDS_OK);
+  source->AddLocalizedString("cancel", IDS_CANCEL);
 
   // Add extension-specific strings.
   source->AddLocalizedString("title",
@@ -207,6 +209,12 @@
                              IDS_EXTENSIONS_ERROR_NO_ERRORS_CODE_MESSAGE);
   source->AddLocalizedString("packDialogTitle",
                              IDS_MD_EXTENSIONS_PACK_DIALOG_TITLE);
+  source->AddLocalizedString("packDialogWarningTitle",
+                             IDS_MD_EXTENSIONS_PACK_DIALOG_WARNING_TITLE);
+  source->AddLocalizedString("packDialogErrorTitle",
+                             IDS_MD_EXTENSIONS_PACK_DIALOG_ERROR_TITLE);
+  source->AddLocalizedString("packDialogProceedAnyway",
+                             IDS_MD_EXTENSIONS_PACK_DIALOG_PROCEED_ANYWAY);
   source->AddLocalizedString("packDialogBrowse",
                              IDS_MD_EXTENSIONS_PACK_DIALOG_BROWSE_BUTTON);
   source->AddLocalizedString(
@@ -298,6 +306,10 @@
   source->AddResourcePath("pack_dialog.html",
                           IDR_MD_EXTENSIONS_PACK_DIALOG_HTML);
   source->AddResourcePath("pack_dialog.js", IDR_MD_EXTENSIONS_PACK_DIALOG_JS);
+  source->AddResourcePath("pack_dialog_alert.html",
+                          IDR_MD_EXTENSIONS_PACK_DIALOG_ALERT_HTML);
+  source->AddResourcePath("pack_dialog_alert.js",
+                          IDR_MD_EXTENSIONS_PACK_DIALOG_ALERT_JS);
   source->AddResourcePath("service.html", IDR_MD_EXTENSIONS_SERVICE_HTML);
   source->AddResourcePath("service.js", IDR_MD_EXTENSIONS_SERVICE_JS);
   source->AddResourcePath("shortcut_input.html",
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 1362f17..b4e4f346e 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -134,16 +134,17 @@
   return chrome::FindBrowserWithWebContents(initiator());
 }
 
-void MediaRouterUI::OpenTabWithUrl(const GURL url) {
+content::WebContents* MediaRouterUI::OpenTabWithUrl(const GURL url) {
   // Check if the current page is a new tab. If so open file in current page.
   // If not then open a new page.
   if (initiator_->GetVisibleURL() == chrome::kChromeUINewTabURL) {
     content::NavigationController::LoadURLParams load_params(url);
     load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
     initiator_->GetController().LoadURLWithParams(load_params);
+    return initiator_;
   } else {
-    initiator_ = chrome::AddSelectedTabWithURL(GetBrowser(), url,
-                                               ui::PAGE_TRANSITION_LINK);
+    return chrome::AddSelectedTabWithURL(GetBrowser(), url,
+                                         ui::PAGE_TRANSITION_LINK);
   }
 }
 
@@ -488,18 +489,27 @@
   base::TimeDelta timeout;
   bool incognito;
 
+  // Default the tab casting the content to the initiator, and change if
+  // necessary.
+  content::WebContents* tab_contents = initiator_;
+
   if (cast_mode == MediaCastMode::LOCAL_FILE) {
     GURL url = media_router_file_dialog_->GetLastSelectedFileUrl();
-    OpenTabWithUrl(url);
-  }
+    tab_contents = OpenTabWithUrl(url);
 
-  if (!SetRouteParameters(sink_id, cast_mode, &source_id, &origin,
-                          &route_response_callbacks, &timeout, &incognito)) {
+    SessionID::id_type tab_id = SessionTabHelper::IdForTab(tab_contents);
+    source_id = MediaSourceForTab(tab_id).id();
+
+    SetLocalFileRouteParameters(sink_id, &origin, &route_response_callbacks,
+                                &timeout, &incognito);
+  } else if (!SetRouteParameters(sink_id, cast_mode, &source_id, &origin,
+                                 &route_response_callbacks, &timeout,
+                                 &incognito)) {
     SendIssueForUnableToCast(cast_mode);
     return false;
   }
 
-  router_->CreateRoute(source_id, sink_id, origin, initiator_,
+  router_->CreateRoute(source_id, sink_id, origin, tab_contents,
                        std::move(route_response_callbacks), timeout, incognito);
   return true;
 }
@@ -583,18 +593,43 @@
       base::BindOnce(&MediaRouterUI::MaybeReportCastingSource,
                      weak_factory_.GetWeakPtr(), cast_mode));
 
-  if (cast_mode == MediaCastMode::LOCAL_FILE) {
-    route_response_callbacks->push_back(
-        base::BindOnce(&MediaRouterUI::MaybeReportFileInformation,
-                       weak_factory_.GetWeakPtr()));
-  }
-
   *timeout = GetRouteRequestTimeout(cast_mode);
   *incognito = Profile::FromWebUI(web_ui())->IsOffTheRecord();
 
   return true;
 }
 
+// TODO(Issue 751317) This function and the above function are messy, this code
+// would be much neater if the route params were combined in a single struct,
+// which will require mojo changes as well.
+bool MediaRouterUI::SetLocalFileRouteParameters(
+    const MediaSink::Id& sink_id,
+    url::Origin* origin,
+    std::vector<MediaRouteResponseCallback>* route_response_callbacks,
+    base::TimeDelta* timeout,
+    bool* incognito) {
+  // Use a placeholder URL as origin for local file casting, which is
+  // essentially mirroring.
+  *origin = url::Origin(GURL(chrome::kChromeUIMediaRouterURL));
+
+  route_response_callbacks->push_back(base::BindOnce(
+      &MediaRouterUI::OnRouteResponseReceived, weak_factory_.GetWeakPtr(),
+      current_route_request_id_, sink_id, MediaCastMode::LOCAL_FILE,
+      base::UTF8ToUTF16(GetTruncatedPresentationRequestSourceName())));
+
+  route_response_callbacks->push_back(
+      base::BindOnce(&MediaRouterUI::MaybeReportCastingSource,
+                     weak_factory_.GetWeakPtr(), MediaCastMode::LOCAL_FILE));
+
+  route_response_callbacks->push_back(base::BindOnce(
+      &MediaRouterUI::MaybeReportFileInformation, weak_factory_.GetWeakPtr()));
+
+  *timeout = GetRouteRequestTimeout(MediaCastMode::LOCAL_FILE);
+  *incognito = Profile::FromWebUI(web_ui())->IsOffTheRecord();
+
+  return true;
+}
+
 bool MediaRouterUI::ConnectRoute(const MediaSink::Id& sink_id,
                                  const MediaRoute::Id& route_id) {
   MediaSource::Id source_id;
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 513a527..9fa34ea 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -267,8 +267,8 @@
   // Retrieves the browser associated with this UI.
   Browser* GetBrowser();
 
-  // Opens the URL in a tab which is then |initator_|.
-  void OpenTabWithUrl(const GURL url);
+  // Opens the URL in a tab, returns the tab it was opened in.
+  content::WebContents* OpenTabWithUrl(const GURL url);
 
   // Methods for MediaRouterFileDialogDelegate
   void FileDialogFileSelected(const ui::SelectedFileInfo& file_info) override;
@@ -341,6 +341,15 @@
       base::TimeDelta* timeout,
       bool* incognito);
 
+  // Populates route-related parameters for CreateRoute() when doing file
+  // casting.
+  bool SetLocalFileRouteParameters(
+      const MediaSink::Id& sink_id,
+      url::Origin* origin,
+      std::vector<MediaRouteResponseCallback>* route_response_callbacks,
+      base::TimeDelta* timeout,
+      bool* incognito);
+
   // Updates the set of supported cast modes and sends the updated set to
   // |handler_|.
   void UpdateCastModes();
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index a71c7203..1971fa9 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -717,6 +717,11 @@
 // testing purposes.
 const char kSystemLogUploadFrequency[] = "system-log-upload-frequency";
 
+// Sets the task manager to track extra renderer processes that might not
+// normally be displayed in the task manager.
+const char kTaskManagerShowExtraRenderers[] =
+    "task-manager-show-extra-renderers";
+
 // Passes the name of the current running automated test to Chrome.
 const char kTestName[]                      = "test-name";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 4ac9fa1..a58e352 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -207,6 +207,7 @@
 extern const char kSupervisedUserId[];
 extern const char kSupervisedUserSyncToken[];
 extern const char kSystemLogUploadFrequency[];
+extern const char kTaskManagerShowExtraRenderers[];
 extern const char kTestName[];
 extern const char kTrustedDownloadSources[];
 extern const char kTryChromeAgain[];
diff --git a/chrome/test/data/webui/bluetooth_internals_browsertest.js b/chrome/test/data/webui/bluetooth_internals_browsertest.js
index 4cf4ec1..2908a32 100644
--- a/chrome/test/data/webui/bluetooth_internals_browsertest.js
+++ b/chrome/test/data/webui/bluetooth_internals_browsertest.js
@@ -55,24 +55,20 @@
         /**
          * A test adapter factory proxy for the chrome://bluetooth-internals
          * page.
-         *
-         * @constructor
-         * @extends {TestBrowserProxy}
          */
-        var TestAdapterFactoryProxy = function() {
-          TestBrowserProxy.call(this, [
-            'getAdapter',
-          ]);
+        class TestAdapterFactoryProxy extends TestBrowserProxy {
+          constructor() {
+            super([
+              'getAdapter',
+            ]);
 
-          this.binding = new bindings.Binding(adapter.AdapterFactory, this);
-          this.adapter = new TestAdapterProxy();
-          this.adapterBinding_ = new bindings.Binding(adapter.Adapter,
-                                                      this.adapter);
-        };
+            this.binding = new bindings.Binding(adapter.AdapterFactory, this);
+            this.adapter = new TestAdapterProxy();
+            this.adapterBinding_ = new bindings.Binding(adapter.Adapter,
+                                                        this.adapter);
+          }
 
-        TestAdapterFactoryProxy.prototype = {
-          __proto__: TestBrowserProxy.prototype,
-          getAdapter: function() {
+          getAdapter() {
             this.methodCalled('getAdapter');
 
             // Create message pipe bound to TestAdapter.
@@ -80,30 +76,26 @@
               adapter: this.adapterBinding_.createInterfacePtrAndBind(),
             });
           }
-        };
+        }
 
         /**
          * A test adapter proxy for the chrome://bluetooth-internals page.
-         * @constructor
-         * @extends {TestBrowserProxy}
          */
-        var TestAdapterProxy = function() {
-          TestBrowserProxy.call(this, [
-            'getInfo',
-            'getDevices',
-            'setClient',
-          ]);
+        class TestAdapterProxy extends TestBrowserProxy {
+          constructor() {
+            super([
+              'getInfo',
+              'getDevices',
+              'setClient',
+            ]);
 
-          this.deviceProxyMap = new Map();
-          this.adapterInfo_ = null;
-          this.devices_ = [];
-          this.connectResult_ = adapter.AdapterInfo.SUCCESS;
-        };
+            this.deviceProxyMap = new Map();
+            this.adapterInfo_ = null;
+            this.devices_ = [];
+            this.connectResult_ = adapter.AdapterInfo.SUCCESS;
+          }
 
-        TestAdapterProxy.prototype = {
-          __proto__: TestBrowserProxy.prototype,
-
-          connectToDevice: function(address) {
+          connectToDevice(address) {
             assert(this.deviceProxyMap.has(address), 'Device does not exist');
 
             return Promise.resolve({
@@ -111,78 +103,74 @@
               device: this.deviceProxyMap.get(
                   address).binding.createInterfacePtrAndBind(),
             });
-          },
+          }
 
-          getInfo: function() {
+          getInfo() {
             this.methodCalled('getInfo');
             return Promise.resolve({info: this.adapterInfo_});
-          },
+          }
 
-          getDevices: function() {
+          getDevices() {
             this.methodCalled('getDevices');
             return Promise.resolve({devices: this.devices_});
-          },
+          }
 
-          setClient: function(client) {
+          setClient(client) {
             this.methodCalled('setClient', client);
-          },
+          }
 
-          setTestAdapter: function(adapterInfo) {
+          setTestAdapter(adapterInfo) {
             this.adapterInfo_ = adapterInfo;
-          },
+          }
 
-          setTestConnectResult: function(connectResult) {
+          setTestConnectResult(connectResult) {
             this.connectResult_ = connectResult;
-          },
+          }
 
-          setTestDevices: function(devices) {
+          setTestDevices(devices) {
             this.devices_ = devices;
             this.devices_.forEach(function(device) {
               this.deviceProxyMap.set(
                   device.address, new TestDeviceProxy(device));
             }, this);
-          },
-        };
+          }
+        }
 
         /**
          * A test Device proxy for the chrome://bluetooth-internals
          * page. Proxies are generated by a TestAdapterProxy which provides
          * the DeviceInfo.
-         * @constructor
-         * @extends {TestBrowserProxy}
          * @param {!device.DeviceInfo} info
          */
-        var TestDeviceProxy = function(info) {
-          TestBrowserProxy.call(this, [
-            'getInfo',
-            'getServices',
-          ]);
+        class TestDeviceProxy extends TestBrowserProxy {
+          constructor(info) {
+            super([
+              'getInfo',
+              'getServices',
+            ]);
 
-          this.binding = new bindings.Binding(device.Device, this);
-          this.info_ = info;
-          this.services_ = [];
-        }
+            this.binding = new bindings.Binding(device.Device, this);
+            this.info_ = info;
+            this.services_ = [];
+          }
 
-        TestDeviceProxy.prototype = {
-          __proto__: TestBrowserProxy.prototype,
-
-          disconnect: function() {
+          disconnect() {
             this.binding.close();
-          },
+          }
 
-          getInfo: function() {
+          getInfo() {
             this.methodCalled('getInfo');
             return Promise.resolve({info: this.info_});
-          },
+          }
 
-          getServices: function() {
+          getServices() {
             this.methodCalled('getServices');
             return Promise.resolve({services: this.services_});
-          },
+          }
 
-          setTestServices: function(services) {
+          setTestServices(services) {
             this.services_ = services;
-          },
+          }
         }
 
         frameInterfaces.addInterfaceOverrideForTesting(
@@ -207,7 +195,6 @@
 
               this.setupResolver.resolve();
             }.bind(this));
-
       }.bind(this));
     }.bind(this);
   },
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 6e78687..9cf685d 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -329,6 +329,28 @@
   mocha.grep(assert(extension_pack_dialog_tests.TestNames.Interaction)).run();
 });
 
+TEST_F(
+    'CrExtensionsBrowserTest', 'ExtensionPackDialogPackSuccessTest',
+    function() {
+      extension_pack_dialog_tests.registerTests();
+      mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackSuccess))
+          .run();
+    });
+
+TEST_F(
+    'CrExtensionsBrowserTest', 'ExtensionPackDialogPackErrorTest', function() {
+      extension_pack_dialog_tests.registerTests();
+      mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackError)).run();
+    });
+
+TEST_F(
+    'CrExtensionsBrowserTest', 'ExtensionPackDialogPackWarningTest',
+    function() {
+      extension_pack_dialog_tests.registerTests();
+      mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackWarning))
+          .run();
+    });
+
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Options Dialog Tests
 
diff --git a/chrome/test/data/webui/extensions/extension_pack_dialog_test.js b/chrome/test/data/webui/extensions/extension_pack_dialog_test.js
index 60b8860c..36e8ec9 100644
--- a/chrome/test/data/webui/extensions/extension_pack_dialog_test.js
+++ b/chrome/test/data/webui/extensions/extension_pack_dialog_test.js
@@ -7,13 +7,20 @@
   /** @enum {string} */
   var TestNames = {
     Interaction: 'Interaction',
+    PackSuccess: 'PackSuccess',
+    PackWarning: 'PackWarning',
+    PackError: 'PackError',
   };
 
   /**
    * @implements {extensions.PackDialogDelegate}
    * @constructor
    */
-  function MockDelegate() {}
+  function MockDelegate() {
+    this.mockResponse = null;
+    this.rootPromise;
+    this.keyPromise;
+  }
 
   MockDelegate.prototype = {
     /** @override */
@@ -29,12 +36,22 @@
     },
 
     /** @override */
-    packExtension: function(rootPath, keyPath) {
+    packExtension: function(rootPath, keyPath, flag, callback) {
       this.rootPath = rootPath;
       this.keyPath = keyPath;
+      this.flag = flag;
+
+      if (callback && this.mockResponse) {
+        callback(this.mockResponse);
+      }
     },
   };
 
+  var isElementVisible = function(element) {
+    var rect = element.getBoundingClientRect();
+    return rect.width * rect.height > 0;
+  };
+
   function registerTests() {
     suite('ExtensionPackDialogTests', function() {
       /** @type {extensions.PackDialog} */
@@ -53,14 +70,10 @@
 
       test(assert(TestNames.Interaction), function() {
         var dialogElement = packDialog.$$('dialog');
-        var isDialogVisible = function() {
-          var rect = dialogElement.getBoundingClientRect();
-          return rect.width * rect.height > 0;
-        };
 
-        expectFalse(isDialogVisible());
+        expectFalse(isElementVisible(dialogElement));
         packDialog.show();
-        expectTrue(isDialogVisible());
+        expectTrue(isElementVisible(dialogElement));
         expectEquals('', packDialog.$$('#root-dir').value);
         MockInteractions.tap(packDialog.$$('#root-dir-browse'));
         expectTrue(!!mockDelegate.rootPromise);
@@ -91,9 +104,117 @@
           MockInteractions.tap(packDialog.$$('.action-button'));
           expectEquals(kRootPath, mockDelegate.rootPath);
           expectEquals(kKeyPath, mockDelegate.keyPath);
-          expectFalse(isDialogVisible());
         });
       });
+
+      test(assert(TestNames.PackSuccess), function() {
+        var dialogElement = packDialog.$$('dialog');
+
+        packDialog.show();
+        expectTrue(isElementVisible(dialogElement));
+
+        var kRootPath = 'this/is/a/path';
+        mockDelegate.mockResponse = {
+          status: chrome.developerPrivate.PackStatus.SUCCESS
+        };
+
+        MockInteractions.tap(packDialog.$$('#root-dir-browse'));
+        mockDelegate.rootPromise.resolve(kRootPath);
+
+        return mockDelegate.rootPromise.promise
+            .then(() => {
+              expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+              MockInteractions.tap(packDialog.$$('.action-button'));
+
+              return PolymerTest.flushTasks();
+            })
+            .then(() => {
+              expectFalse(isElementVisible(dialogElement));
+            });
+      });
+
+      test(assert(TestNames.PackError), function() {
+        var dialogElement = packDialog.$$('dialog');
+        var packDialogAlert;
+        var alertElement;
+
+        packDialog.show();
+        expectTrue(isElementVisible(dialogElement));
+
+        var kRootPath = 'this/is/a/path';
+        mockDelegate.mockResponse = {
+          status: chrome.developerPrivate.PackStatus.ERROR
+        };
+
+        MockInteractions.tap(packDialog.$$('#root-dir-browse'));
+        mockDelegate.rootPromise.resolve(kRootPath);
+
+        return mockDelegate.rootPromise.promise.then(() => {
+          expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+          MockInteractions.tap(packDialog.$$('.action-button'));
+          Polymer.dom.flush();
+
+          // Make sure new alert and the appropriate buttons are visible.
+          packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
+          alertElement = packDialogAlert.$.dialog;
+          expectTrue(isElementVisible(alertElement));
+          expectTrue(isElementVisible(dialogElement));
+          expectFalse(packDialogAlert.$$('.cancel-button').hidden);
+          expectTrue(packDialogAlert.$$('.action-button').hidden);
+
+          // After cancel, original dialog is still open and values unchanged.
+          MockInteractions.tap(packDialogAlert.$$('.cancel-button'));
+          expectFalse(isElementVisible(alertElement));
+          expectTrue(isElementVisible(dialogElement));
+          expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+        });
+      });
+
+      test(assert(TestNames.PackWarning), function() {
+        var dialogElement = packDialog.$$('dialog');
+        var packDialogAlert;
+        var alertElement;
+
+        packDialog.show();
+        expectTrue(isElementVisible(dialogElement));
+
+        var kRootPath = 'this/is/a/path';
+        mockDelegate.mockResponse = {
+          status: chrome.developerPrivate.PackStatus.WARNING,
+          item_path: 'item_path',
+          pem_path: 'pem_path',
+          override_flags: 1,
+        };
+
+        MockInteractions.tap(packDialog.$$('#root-dir-browse'));
+        mockDelegate.rootPromise.resolve(kRootPath);
+
+        return mockDelegate.rootPromise.promise
+            .then(() => {
+              expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+              MockInteractions.tap(packDialog.$$('.action-button'));
+              Polymer.dom.flush();
+
+              // Make sure new alert and the appropriate buttons are visible.
+              packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
+              alertElement = packDialogAlert.$.dialog;
+              expectTrue(isElementVisible(alertElement));
+              expectTrue(isElementVisible(dialogElement));
+              expectFalse(packDialogAlert.$$('.cancel-button').hidden);
+              expectFalse(packDialogAlert.$$('.action-button').hidden);
+
+              // Make sure "proceed anyway" try to pack extension again.
+              MockInteractions.tap(packDialogAlert.$$('.action-button'));
+
+              return PolymerTest.flushTasks();
+            })
+            .then(() => {
+              // Make sure packExtension is called again with the right params.
+              expectFalse(isElementVisible(alertElement));
+              expectEquals(
+                  mockDelegate.flag, mockDelegate.mockResponse.override_flags);
+            });
+      });
     });
   }
 
diff --git a/chrome/test/data/webui/md_user_manager/test_profile_browser_proxy.js b/chrome/test/data/webui/md_user_manager/test_profile_browser_proxy.js
index aa78559..37f91c4 100644
--- a/chrome/test/data/webui/md_user_manager/test_profile_browser_proxy.js
+++ b/chrome/test/data/webui/md_user_manager/test_profile_browser_proxy.js
@@ -4,105 +4,106 @@
 
 /**
  * The mock signin.ProfileBrowserProxy.
- *
- * @constructor
  * @implements {signin.ProfileBrowserProxy}
- * @extends {TestBrowserProxy}
  */
-var TestProfileBrowserProxy = function() {
-  TestBrowserProxy.call(this, [
-    'getAvailableIcons',
-    'getSignedInUsers',
-    'launchGuestUser',
-    'createProfile',
-    'cancelCreateProfile',
-    'initializeUserManager',
-    'launchUser',
-    'getExistingSupervisedUsers',
-    'areAllProfilesLocked',
-  ]);
+class TestProfileBrowserProxy extends TestBrowserProxy {
+  constructor() {
+    super([
+      'getAvailableIcons',
+      'getSignedInUsers',
+      'launchGuestUser',
+      'createProfile',
+      'cancelCreateProfile',
+      'initializeUserManager',
+      'launchUser',
+      'getExistingSupervisedUsers',
+      'areAllProfilesLocked',
+    ]);
 
-  /** @private {!Array<!AvatarIcon>} */
-  this.icons_ = [];
+    /** @private {!Array<!AvatarIcon>} */
+    this.icons_ = [];
 
-  /** @private {!Array<SignedInUser>} */
-  this.signedInUsers_ = [];
+    /** @private {!Array<SignedInUser>} */
+    this.signedInUsers_ = [];
 
-  /** @private {!ProfileInfo} */
-  this.defaultProfileInfo_ = {};
+    /** @private {!ProfileInfo} */
+    this.defaultProfileInfo_ = {};
 
-  /** @private {!Array<SupervisedUser>} */
-  this.existingSupervisedUsers_ = [];
+    /** @private {!Array<SupervisedUser>} */
+    this.existingSupervisedUsers_ = [];
 
-  /** @private {boolean} */
-  this.allProfilesLocked_ = false;
-};
-
-TestProfileBrowserProxy.prototype = {
-  __proto__: TestBrowserProxy.prototype,
+    /** @private {boolean} */
+    this.allProfilesLocked_ = false;
+  }
 
   /**
    * @param {!Array<!AvatarIcon>} icons
    */
-  setIcons: function(icons) {
+  setIcons(icons) {
     this.icons_ = icons;
-  },
+  }
 
   /**
    * @param {!Array<SignedInUser>} signedInUsers
    */
-  setSignedInUsers: function(signedInUsers) {
+  setSignedInUsers(signedInUsers) {
     this.signedInUsers_ = signedInUsers;
-  },
+  }
 
   /**
    * @param {!ProfileInfo} profileInfo
    */
-  setDefaultProfileInfo: function(profileInfo) {
+  setDefaultProfileInfo(profileInfo) {
     this.defaultProfileInfo_ = profileInfo;
-  },
+  }
 
   /**
    * @param {!Array<SupervisedUser>} supervisedUsers
    */
-  setExistingSupervisedUsers: function(supervisedUsers) {
+  setExistingSupervisedUsers(supervisedUsers) {
     this.existingSupervisedUsers_ = supervisedUsers;
-  },
+  }
 
   /**
    * @param {boolean} allProfilesLocked
    */
-  setAllProfilesLocked: function(allProfilesLocked) {
+  setAllProfilesLocked(allProfilesLocked) {
     this.allProfilesLocked_ = allProfilesLocked;
-  },
+  }
 
   /** @override */
-  getAvailableIcons: function() {
+  getAvailableIcons() {
     this.methodCalled('getAvailableIcons');
     cr.webUIListenerCallback('profile-icons-received', this.icons_);
     cr.webUIListenerCallback('profile-defaults-received',
                              this.defaultProfileInfo_);
-  },
+  }
 
   /** @override */
-  getSignedInUsers: function() {
+  getSignedInUsers() {
     this.methodCalled('getSignedInUsers');
     cr.webUIListenerCallback('signedin-users-received', this.signedInUsers_);
-  },
+  }
 
   /** @override */
-  cancelCreateProfile: function() {
+  cancelCreateProfile() {
     /**
      * Flag used to test whether this method was not called.
      * @type {boolean}
      */
     this.cancelCreateProfileCalled = true;
     this.methodCalled('cancelCreateProfile');
-  },
+  }
 
   /** @override */
-  createProfile: function(profileName, profileIconUrl, createShortcut,
-        isSupervised, supervisedUserId, custodianProfilePath) {
+  createProfile(
+    profileName,
+    profileIconUrl,
+    createShortcut,
+    isSupervised,
+    supervisedUserId,
+    custodianProfilePath
+  ) {
     this.methodCalled('createProfile',
                       {profileName: profileName,
                        profileIconUrl: profileIconUrl,
@@ -110,22 +111,22 @@
                        isSupervised: isSupervised,
                        supervisedUserId: supervisedUserId,
                        custodianProfilePath: custodianProfilePath});
-  },
+  }
 
   /** @override */
-  launchGuestUser: function() {
+  launchGuestUser() {
     this.methodCalled('launchGuestUser');
-  },
+  }
 
   /** @override */
-  getExistingSupervisedUsers: function() {
+  getExistingSupervisedUsers() {
     this.methodCalled('getExistingSupervisedUsers');
     return Promise.resolve(this.existingSupervisedUsers_);
-  },
+  }
 
   /** @override */
-  areAllProfilesLocked: function() {
+  areAllProfilesLocked() {
     this.methodCalled('areAllProfilesLocked');
     return Promise.resolve(this.allProfilesLocked_);
-  },
-};
+  }
+}
diff --git a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
index ea5218d..6a2a3e4 100644
--- a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
@@ -135,6 +135,20 @@
   }
 
   /**
+   * Helper method used to create a password list item.
+   * @param {!chrome.passwordsPrivate.PasswordUiEntry} passwordItem
+   * @return {!Object}
+   * @private
+   */
+  function createPasswordListItem(passwordItem) {
+    var passwordListItem = document.createElement('password-list-item');
+    passwordListItem.item = passwordItem;
+    document.body.appendChild(passwordListItem);
+    Polymer.dom.flush();
+    return passwordListItem;
+  }
+
+  /**
    * Helper method used to create a password editing dialog.
    * @param {!chrome.passwordsPrivate.PasswordUiEntry} passwordItem
    * @return {!Object}
@@ -461,7 +475,7 @@
       assertTrue(passwordDialog.$.showPasswordButton.hidden);
     });
 
-    test('showSavedPassword', function() {
+    test('showSavedPasswordEditDialog', function() {
       var PASSWORD = 'bAn@n@5';
       var item = FakeDataMaker.passwordEntry('goo.gl', 'bart', PASSWORD.length);
       var passwordDialog = createPasswordDialog(item);
@@ -469,8 +483,6 @@
       assertFalse(passwordDialog.$.showPasswordButton.hidden);
 
       passwordDialog.password = PASSWORD;
-      passwordDialog.showPassword = true;
-
       Polymer.dom.flush();
 
       assertEquals(PASSWORD,
@@ -481,19 +493,57 @@
       assertFalse(passwordDialog.$.showPasswordButton.hidden);
     });
 
+    test('showSavedPasswordListItem', function() {
+      var PASSWORD = 'bAn@n@5';
+      var item = FakeDataMaker.passwordEntry('goo.gl', 'bart', PASSWORD.length);
+      var passwordListItem = createPasswordListItem(item);
+
+      passwordListItem.password = PASSWORD;
+      Polymer.dom.flush();
+
+      assertEquals(PASSWORD, passwordListItem.$$('#password').value);
+      // Password should be visible.
+      assertEquals('text', passwordListItem.$$('#password').type);
+
+      // Hide Password Button should be shown.
+      assertTrue(passwordListItem.$$('#showPasswordButton')
+                     .classList.contains('icon-visibility-off'));
+    });
+
     // Test will timeout if event is not received.
-    test('onShowSavedPassword', function(done) {
-      var item = FakeDataMaker.passwordEntry('goo.gl', 'bart', 1);
-      var passwordDialog = createPasswordDialog(item);
+    test('onShowSavedPasswordEditDialog', function(done) {
+      var expectedItem = FakeDataMaker.passwordEntry('goo.gl', 'bart', 1);
+      var passwordDialog = createPasswordDialog(expectedItem);
 
       passwordDialog.addEventListener('show-password', function(event) {
-        assertEquals(item.loginPair.urls.origin, event.detail.urls.origin);
-        assertEquals(item.loginPair.username, event.detail.username);
+        var actualItem = event.detail.item;
+        assertEquals(
+            expectedItem.loginPair.urls.origin,
+            actualItem.loginPair.urls.origin);
+        assertEquals(
+            expectedItem.loginPair.username, actualItem.loginPair.username);
         done();
       });
 
       MockInteractions.tap(passwordDialog.$.showPasswordButton);
     });
+
+    test('onShowSavedPasswordListItem', function(done) {
+      var expectedItem = FakeDataMaker.passwordEntry('goo.gl', 'bart', 1);
+      var passwordListItem = createPasswordListItem(expectedItem);
+
+      passwordListItem.addEventListener('show-password', function(event) {
+        var actualItem = event.detail.item;
+        assertEquals(
+            expectedItem.loginPair.urls.origin,
+            actualItem.loginPair.urls.origin);
+        assertEquals(
+            expectedItem.loginPair.username, actualItem.loginPair.username);
+        done();
+      });
+
+      MockInteractions.tap(passwordListItem.$$('#showPasswordButton'));
+    });
   });
 
   mocha.run();
diff --git a/chrome/test/data/webui/test_browser_proxy.js b/chrome/test/data/webui/test_browser_proxy.js
index 9d124ea..a6b020e 100644
--- a/chrome/test/data/webui/test_browser_proxy.js
+++ b/chrome/test/data/webui/test_browser_proxy.js
@@ -10,15 +10,14 @@
  * called, which will trigger callers of |whenCalled| to get notified.
  * For example:
  * --------------------------------------------------------------------------
- * var MyTestBrowserProxy = function() {
- *   TestBrowserProxy.call(this, ['myMethod']);
- * };
- * MyTestBrowserProxy.prototype = function() {
- *   __proto__: TestBrowserProxy.prototype,
+ * class MyTestBrowserProxy extends TestBrowserProxy {
+ *   constructor() {
+ *     super(['myMethod']);
+ *   }
  *
- *   myMethod: function(someId) {
+ *   myMethod(someId) {
  *     this.methodCalled('myMethod', someId);
- *   },
+ *   }
  * };
  *
  * // Test code sample
@@ -30,18 +29,18 @@
  *   assertEquals(EXPECTED_ID, id);
  * });
  * --------------------------------------------------------------------------
- *
- * @constructor
- * @param {!Array<string>} methodNames Names of all methods whose calls
- *     need to be tracked.
  */
-var TestBrowserProxy = function(methodNames) {
-  /** @private {!Map<string, !PromiseResolver>} */
-  this.resolverMap_ = new Map();
-  methodNames.forEach(this.resetResolver, this);
-};
+class TestBrowserProxy {
+  /**
+   * @param {!Array<string>} methodNames Names of all methods whose calls
+   *     need to be tracked.
+   */
+  constructor(methodNames) {
+    /** @private {!Map<string, !PromiseResolver>} */
+    this.resolverMap_ = new Map();
+    methodNames.forEach(this.resetResolver, this);
+  }
 
-TestBrowserProxy.prototype = {
   /**
    * Called by subclasses when a tracked method is called from the code that
    * is being tested.
@@ -51,33 +50,33 @@
    *     the expected arguments.
    * @protected
    */
-  methodCalled: function(methodName, opt_arg) {
+  methodCalled(methodName, opt_arg) {
     this.resolverMap_.get(methodName).resolve(opt_arg);
-  },
+  }
 
   /**
    * @param {string} methodName
    * @return {!Promise} A promise that is resolved when the given method
    *     is called.
    */
-  whenCalled: function(methodName) {
+  whenCalled(methodName) {
     return this.resolverMap_.get(methodName).promise;
-  },
+  }
 
   /**
    * Resets the PromiseResolver associated with the given method.
    * @param {string} methodName
    */
-  resetResolver: function(methodName) {
+  resetResolver(methodName) {
     this.resolverMap_.set(methodName, new PromiseResolver());
-  },
+  }
 
   /**
    * Resets all PromiseResolvers.
    */
-  reset: function() {
+  reset() {
     this.resolverMap_.forEach(function(value, methodName) {
       this.resolverMap_.set(methodName, new PromiseResolver());
     }.bind(this));
-  },
-};
+  }
+}
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 2b0c673..4b2a453 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9757.0.0
\ No newline at end of file
+9800.0.0
\ No newline at end of file
diff --git a/components/cast_channel/cast_socket.cc b/components/cast_channel/cast_socket.cc
index 6c5046a..676ece01 100644
--- a/components/cast_channel/cast_socket.cc
+++ b/components/cast_channel/cast_socket.cc
@@ -115,8 +115,9 @@
   // would result in re-entrancy.
   CloseInternal();
 
+  error_state_ = ChannelError::UNKNOWN;
   for (auto& connect_callback : connect_callbacks_)
-    std::move(connect_callback).Run(channel_id_, ChannelError::UNKNOWN);
+    std::move(connect_callback).Run(this);
   connect_callbacks_.clear();
 }
 
@@ -230,10 +231,12 @@
       connect_callbacks_.push_back(std::move(callback));
       break;
     case ReadyState::OPEN:
-      std::move(callback).Run(channel_id_, ChannelError::NONE);
+      error_state_ = ChannelError::NONE;
+      std::move(callback).Run(this);
       break;
     case ReadyState::CLOSED:
-      std::move(callback).Run(channel_id_, ChannelError::CONNECT_ERROR);
+      error_state_ = ChannelError::CONNECT_ERROR;
+      std::move(callback).Run(this);
       break;
     default:
       NOTREACHED() << "Unknown ReadyState: "
@@ -552,7 +555,7 @@
   }
 
   for (auto& connect_callback : connect_callbacks_)
-    std::move(connect_callback).Run(channel_id_, error_state_);
+    std::move(connect_callback).Run(this);
   connect_callbacks_.clear();
 }
 
diff --git a/components/cast_channel/cast_socket.h b/components/cast_channel/cast_socket.h
index 1bc643c..3b3721e7 100644
--- a/components/cast_channel/cast_socket.h
+++ b/components/cast_channel/cast_socket.h
@@ -56,8 +56,10 @@
 // Public interface of the CastSocket class.
 class CastSocket {
  public:
-  using OnOpenCallback =
-      base::OnceCallback<void(int channel_id, ChannelError error_state)>;
+  // Invoked when CastSocket opens.
+  // |socket|: raw pointer of opened socket (this pointer). Guaranteed to be
+  // valid in callback function. Do not pass |socket| around.
+  using OnOpenCallback = base::OnceCallback<void(CastSocket* socket)>;
 
   class Observer {
    public:
diff --git a/components/cast_channel/cast_socket_service_unittest.cc b/components/cast_channel/cast_socket_service_unittest.cc
index f2c0ce02..c888a61 100644
--- a/components/cast_channel/cast_socket_service_unittest.cc
+++ b/components/cast_channel/cast_socket_service_unittest.cc
@@ -83,9 +83,9 @@
   EXPECT_CALL(*mock_socket, ConnectInternal(_))
       .WillOnce(WithArgs<0>(
           Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
-            callback.Run(mock_socket->id(), ChannelError::NONE);
+            callback.Run(mock_socket);
           })));
-  EXPECT_CALL(mock_on_open_callback_, Run(_, ChannelError::NONE));
+  EXPECT_CALL(mock_on_open_callback_, Run(mock_socket));
   EXPECT_CALL(*mock_socket, AddObserver(_));
 
   cast_socket_service_->OpenSocket(ip_endpoint, nullptr /* net_log */,
diff --git a/components/cast_channel/cast_socket_unittest.cc b/components/cast_channel/cast_socket_unittest.cc
index 7f07d21..b4f2adbfa 100644
--- a/components/cast_channel/cast_socket_unittest.cc
+++ b/components/cast_channel/cast_socket_unittest.cc
@@ -166,8 +166,7 @@
  public:
   CompleteHandler() {}
   MOCK_METHOD1(OnCloseComplete, void(int result));
-  MOCK_METHOD2(OnConnectComplete,
-               void(int channel_id, ChannelError error_state));
+  MOCK_METHOD1(OnConnectComplete, void(CastSocket* socket));
   MOCK_METHOD1(OnWriteComplete, void(int result));
   MOCK_METHOD1(OnReadComplete, void(int result));
 
@@ -403,7 +402,7 @@
                 SendMessage(EqualsProto(challenge_proto), _))
         .WillOnce(PostCompletionCallbackTask<1>(net::OK));
     EXPECT_CALL(*socket_->GetMockTransport(), Start());
-    EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+    EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
     socket_->AddObserver(observer_.get());
     socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                                 base::Unretained(&handler_)));
@@ -618,7 +617,7 @@
               SendMessage(EqualsProto(challenge_proto), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   EXPECT_CALL(*socket_->GetMockTransport(), Start());
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::TRANSPORT_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -643,7 +642,7 @@
 
   socket_->SetupTcpConnect(net::ASYNC, net::ERR_FAILED);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -658,7 +657,7 @@
 
   socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_FAILED);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -671,7 +670,7 @@
 TEST_F(MockCastSocketTest, TestConnectTcpTimeoutError) {
   CreateCastSocketSecure();
   socket_->SetupTcpConnectUnresponsive();
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   EXPECT_CALL(*observer_, OnError(_, ChannelError::CONNECT_TIMEOUT));
   socket_->AddObserver(observer_.get());
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -691,7 +690,7 @@
 TEST_F(MockCastSocketTest, TestConnectTcpSocketTimeoutError) {
   CreateCastSocketSecure();
   socket_->SetupTcpConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT);
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   EXPECT_CALL(*observer_, OnError(_, ChannelError::CONNECT_TIMEOUT));
   socket_->AddObserver(observer_.get());
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -711,8 +710,7 @@
   socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
   socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED);
 
-  EXPECT_CALL(handler_,
-              OnConnectComplete(_, ChannelError::AUTHENTICATION_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -728,8 +726,7 @@
   socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
   socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_FAILED);
 
-  EXPECT_CALL(handler_,
-              OnConnectComplete(_, ChannelError::AUTHENTICATION_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -747,7 +744,7 @@
   socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
   socket_->SetupSslConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_TIMED_OUT);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -765,7 +762,7 @@
   socket_->SetupTcpConnect(net::ASYNC, net::OK);
   socket_->SetupSslConnect(net::ASYNC, net::ERR_CONNECTION_TIMED_OUT);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -785,7 +782,7 @@
               SendMessage(EqualsProto(CreateAuthChallenge()), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CAST_SOCKET_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -822,7 +819,7 @@
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
   socket_->AddReadResult(net::SYNCHRONOUS, net::ERR_FAILED);
   EXPECT_CALL(*observer_, OnError(_, ChannelError::CAST_SOCKET_ERROR));
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CAST_SOCKET_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   EXPECT_CALL(*socket_->GetMockTransport(), Start());
   socket_->AddObserver(observer_.get());
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -848,8 +845,7 @@
   EXPECT_CALL(*socket_->GetMockTransport(),
               SendMessage(EqualsProto(challenge_proto), _))
       .WillOnce(PostCompletionCallbackTask<1>(net::OK));
-  EXPECT_CALL(handler_,
-              OnConnectComplete(_, ChannelError::AUTHENTICATION_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   EXPECT_CALL(*socket_->GetMockTransport(), Start());
   socket_->AddObserver(observer_.get());
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
@@ -887,7 +883,7 @@
   EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str));
   socket_->AddWriteResultForData(net::ASYNC, test_message_str);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -929,7 +925,7 @@
   EXPECT_TRUE(MessageFramer::Serialize(test_message, &test_message_str));
   socket_->AddWriteResultForData(net::SYNCHRONOUS, test_message_str);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
@@ -971,8 +967,7 @@
                               base::Unretained(&handler_)));
   RunPendingTasks();
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_TIMEOUT))
-      .Times(2);
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get())).Times(2);
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   socket_->TriggerTimeout();
@@ -986,7 +981,7 @@
 
   HandleAuthHandshake();
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
 }
@@ -995,12 +990,12 @@
   CreateCastSocketSecure();
   socket_->SetupTcpConnect(net::ASYNC, net::ERR_FAILED);
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
   RunPendingTasks();
 
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::CONNECT_ERROR));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   socket_->Connect(base::Bind(&CompleteHandler::OnConnectComplete,
                               base::Unretained(&handler_)));
 }
@@ -1037,7 +1032,7 @@
                                  server_socket_.get());
 
   EXPECT_EQ(reply_buffer->size(), written);
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   RunPendingTasks();
 
   EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
@@ -1077,7 +1072,7 @@
                                  server_socket_.get());
 
   EXPECT_EQ(reply_buffer->size(), written);
-  EXPECT_CALL(handler_, OnConnectComplete(_, ChannelError::NONE));
+  EXPECT_CALL(handler_, OnConnectComplete(socket_.get()));
   RunPendingTasks();
 
   EXPECT_EQ(ReadyState::OPEN, socket_->ready_state());
diff --git a/components/cast_channel/cast_test_util.h b/components/cast_channel/cast_test_util.h
index fbf0cc7..fb0cffd5 100644
--- a/components/cast_channel/cast_test_util.h
+++ b/components/cast_channel/cast_test_util.h
@@ -84,15 +84,14 @@
   MOCK_METHOD4(OpenSocketInternal,
                int(const net::IPEndPoint& ip_endpoint,
                    net::NetLog* net_log,
-                   const base::Callback<void(int, ChannelError)>& open_cb,
+                   const base::Callback<void(CastSocket*)>& open_cb,
                    CastSocket::Observer* observer));
   MOCK_CONST_METHOD1(GetSocket, CastSocket*(int channel_id));
 };
 
 class MockCastSocket : public CastSocket {
  public:
-  using MockOnOpenCallback =
-      base::Callback<void(int channel_id, ChannelError error_state)>;
+  using MockOnOpenCallback = base::Callback<void(CastSocket* socket)>;
 
   MockCastSocket();
   ~MockCastSocket() override;
diff --git a/components/cronet/android/test/javaperftests/run.py b/components/cronet/android/test/javaperftests/run.py
index 1e815e2..afb63e68 100755
--- a/components/cronet/android/test/javaperftests/run.py
+++ b/components/cronet/android/test/javaperftests/run.py
@@ -54,8 +54,8 @@
     os.path.dirname(__file__), '..', '..', '..', '..', '..'))
 
 sys.path.append(os.path.join(REPOSITORY_ROOT, 'tools', 'perf'))
-from chrome_telemetry_build import chromium_config
-sys.path.append(chromium_config.GetTelemetryDir())
+from core import path_util
+sys.path.append(path_util.GetTelemetryDir())
 sys.path.append(os.path.join(REPOSITORY_ROOT, 'build', 'android'))
 sys.path.append(os.path.join(
     REPOSITORY_ROOT, 'third_party', 'catapult', 'devil'))
diff --git a/components/cronet/tools/cr_cronet.py b/components/cronet/tools/cr_cronet.py
index 380bf823..fab5841 100755
--- a/components/cronet/tools/cr_cronet.py
+++ b/components/cronet/tools/cr_cronet.py
@@ -22,11 +22,10 @@
              extra_options)
 
 
-def install(out_dir, release_arg):
-  cmd = 'BUILDTYPE={0} build/android/adb_install_apk.py {1} --apk={2}'
-  build_dir = out_dir.split('/', 1)[1] # the 'Foo' part of 'out/Foo'
-  return run(cmd.format(build_dir, release_arg, 'CronetTest.apk')) or \
-    run(cmd.format(build_dir, release_arg, 'ChromiumNetTestSupport.apk'))
+def install(out_dir):
+  cmd = 'build/android/adb_install_apk.py ' + out_dir + '/apks/{0}'
+  return run(cmd.format('CronetTest.apk')) or \
+    run(cmd.format('ChromiumNetTestSupport.apk'))
 
 
 def test(out_dir, extra_options):
@@ -114,11 +113,9 @@
 
   if options.release:
     out_dir = 'out/Release' + out_dir_suffix
-    release_arg = ' --release'
     gn_args += ' is_debug=false is_official_build=true '
   else:
     out_dir = 'out/Debug' + out_dir_suffix
-    release_arg = ''
 
   if options.out_dir:
     out_dir = options.out_dir
@@ -131,20 +128,20 @@
     return build(out_dir, test_target, extra_options)
   if (not is_os):
     if (options.command=='install'):
-      return install(out_dir, release_arg)
+      return install(out_dir)
     if (options.command=='proguard'):
       return run ('ninja -C ' + out_dir + ' cronet_sample_proguard_apk')
     if (options.command=='test'):
-      return install(out_dir, release_arg) or test(out_dir, extra_options)
+      return install(out_dir) or test(out_dir, extra_options)
     if (options.command=='build-test'):
-      return build(out_dir, test_target) or install(out_dir, release_arg) or \
+      return build(out_dir, test_target) or install(out_dir) or \
           test(out_dir, extra_options)
     if (options.command=='stack'):
       return stack(out_dir)
     if (options.command=='debug'):
-      return install(out_dir, release_arg) or debug(extra_options)
+      return install(out_dir) or debug(extra_options)
     if (options.command=='build-debug'):
-      return build(out_dir, test_target) or install(out_dir, release_arg) or \
+      return build(out_dir, test_target) or install(out_dir) or \
           debug(extra_options)
   else:
     if (options.command=='test'):
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 58411e0e..fe7a3098 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -664,9 +664,12 @@
   render_pass->damage_rect.Union(damage_rect);
   cc::SharedQuadState* quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  quad_state->quad_layer_rect = gfx::Rect(content_size_);
-  quad_state->visible_quad_layer_rect = quad_rect;
-  quad_state->opacity = state_.alpha;
+  quad_state->SetAll(
+      gfx::Transform() /* quad_to_target_transform */,
+      gfx::Rect(content_size_) /* quad_layer_rect */,
+      quad_rect /* visible_quad_layer_rect */, gfx::Rect() /* clip_rect */,
+      false /* is_clipped */, state_.alpha /* opacity */,
+      SkBlendMode::kSrcOver /* blend_mode */, 0 /* sorting_context_id */);
 
   if (current_resource_.id) {
     gfx::PointF uv_top_left(0.f, 0.f);
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 5adf79f..74b280f 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -778,9 +778,9 @@
   syncable_service_->InjectStartSyncFlare(flare);
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-  reuse_detector_ = base::MakeUnique<PasswordReuseDetector>();
+  reuse_detector_ = new PasswordReuseDetector;
   GetAutofillableLoginsImpl(
-      base::MakeUnique<GetLoginsRequest>(reuse_detector_.get()));
+      base::MakeUnique<GetLoginsRequest>(reuse_detector_));
 #endif
 }
 
@@ -789,7 +789,8 @@
   syncable_service_.reset();
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-  reuse_detector_.reset();
+  delete reuse_detector_;
+  reuse_detector_ = nullptr;
 #endif
 }
 
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 5616935..a781f56e 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -16,6 +16,7 @@
 #include "base/observer_list_threadsafe.h"
 #include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "components/keyed_service/core/refcounted_keyed_service.h"
 #include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/browser/password_store_change.h"
@@ -583,7 +584,8 @@
   void InitOnBackgroundThread(
       const syncer::SyncableService::StartSyncFlare& flare);
 
-  // Deletes objest that should be destroyed on the background thread.
+  // Deletes object that should be destroyed on the background thread.
+  // WARNING: this method can be skipped on shutdown.
   void DestroyOnBackgroundThread();
 
   // The observers.
@@ -593,7 +595,10 @@
   std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper_;
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-  std::unique_ptr<PasswordReuseDetector> reuse_detector_;
+  // PasswordReuseDetector can be only destroyed on the background thread. It
+  // can't be owned by PasswordStore because PasswordStore can be destroyed on
+  // UI thread and DestroyOnBackgroundThread isn't guaranteed to be called.
+  PasswordReuseDetector* reuse_detector_ = nullptr;
 #endif
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
   std::unique_ptr<PasswordStoreSigninNotifier> notifier_;
diff --git a/components/password_manager/core/browser/password_syncable_service.cc b/components/password_manager/core/browser/password_syncable_service.cc
index 093f886..a1c2dd6 100644
--- a/components/password_manager/core/browser/password_syncable_service.cc
+++ b/components/password_manager/core/browser/password_syncable_service.cc
@@ -340,9 +340,7 @@
       clock_(new base::DefaultClock),
       is_processing_sync_changes_(false) {}
 
-PasswordSyncableService::~PasswordSyncableService() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
+PasswordSyncableService::~PasswordSyncableService() = default;
 
 syncer::SyncMergeResult PasswordSyncableService::MergeDataAndStartSyncing(
     syncer::ModelType type,
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index f27e5da6..5e0ef59 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -379,9 +379,13 @@
 
   auto* shared_quad_state =
       color_conversion_pass->CreateAndAppendSharedQuadState();
-  shared_quad_state->quad_layer_rect = output_rect;
-  shared_quad_state->visible_quad_layer_rect = output_rect;
-  shared_quad_state->opacity = 1.f;
+  shared_quad_state->SetAll(
+      /*quad_to_target_transform=*/gfx::Transform(),
+      /*quad_layer_rect=*/output_rect,
+      /*visible_quad_layer_rect=*/output_rect,
+      /*clip_rect=*/gfx::Rect(),
+      /*is_clipped=*/false, /*opacity=*/1.f,
+      /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
 
   auto* quad =
       color_conversion_pass->CreateAndAppendDrawQuad<cc::RenderPassDrawQuad>();
@@ -398,21 +402,23 @@
     cc::RenderPass* dest_render_pass) {
   auto* copy_shared_quad_state =
       dest_render_pass->CreateAndAppendSharedQuadState();
-  *copy_shared_quad_state = *source_sqs;
   // target_transform contains any transformation that may exist
   // between the context that these quads are being copied from (i.e. the
   // surface's draw transform when aggregated from within a surface) to the
   // target space of the pass. This will be identity except when copying the
   // root draw pass from a surface into a pass when the surface draw quad's
   // transform is not identity.
-  copy_shared_quad_state->quad_to_target_transform.ConcatTransform(
-      target_transform);
-
+  gfx::Transform new_transform = source_sqs->quad_to_target_transform;
+  new_transform.ConcatTransform(target_transform);
   ClipData new_clip_rect = CalculateClipRect(
       clip_rect, ClipData(source_sqs->is_clipped, source_sqs->clip_rect),
       target_transform);
-  copy_shared_quad_state->is_clipped = new_clip_rect.is_clipped;
-  copy_shared_quad_state->clip_rect = new_clip_rect.rect;
+  copy_shared_quad_state->SetAll(new_transform, source_sqs->quad_layer_rect,
+                                 source_sqs->visible_quad_layer_rect,
+                                 new_clip_rect.rect, new_clip_rect.is_clipped,
+                                 source_sqs->opacity, source_sqs->blend_mode,
+                                 source_sqs->sorting_context_id);
+
   return copy_shared_quad_state;
 }
 
diff --git a/content/app/strings/content_strings.grd b/content/app/strings/content_strings.grd
index ec77506a..0158c2b 100644
--- a/content/app/strings/content_strings.grd
+++ b/content/app/strings/content_strings.grd
@@ -686,7 +686,7 @@
       <message name="IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_INVALID_LOCAL" desc="Heading or short sentence shown when there is an email field in a form and a user specified an invalid value like 'us,er@example.com'.">
         A part followed by '<ph name="ATSIGN">$1<ex>@</ex></ph>' should not contain the symbol '<ph name="INVALIDCHARACTER">$2<ex>,</ex></ph>'.
       </message>
-      <message name="IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_NO_AT_SIGN" desc="Heading or short sentence shown when there is an email field in a form and a user specified an invalid value liek 'user'.">
+      <message name="IDS_FORM_VALIDATION_TYPE_MISMATCH_EMAIL_NO_AT_SIGN" desc="Heading or short sentence shown when there is an email field in a form and a user specified an invalid value like 'user'.">
         Please include an '<ph name="ATSIGN">$1<ex>@</ex></ph>' in the email address. '<ph name="INVALIDADDRESS">$2<ex>user</ex></ph>' is missing an '<ph name="ATSIGN">$1<ex>@</ex></ph>'.
       </message>
       <message name="IDS_FORM_VALIDATION_TYPE_MISMATCH_MULTIPLE_EMAIL" desc="Heading or short sentence shown there is a field which accepts multiple e-mail addresses and a user specified a value which is not a comma-separated e-mail addresses.">
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index cd82c94a..92bd304 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -372,21 +372,22 @@
   // done in a single pass that must complete before the next step starts.
   // The first step moves win_attributes_ to old_win_attributes_ and then
   // recomputes all of win_attributes_ other than IAccessibleText.
-  for (size_t i = 0; i < changes.size(); ++i) {
-    const ui::AXNode* changed_node = changes[i].node;
+  for (const auto& change : changes) {
+    const ui::AXNode* changed_node = change.node;
     DCHECK(changed_node);
     BrowserAccessibility* obj = GetFromAXNode(changed_node);
-    if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
+    if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) {
       ToBrowserAccessibilityWin(obj)
           ->GetCOM()
           ->UpdateStep1ComputeWinAttributes();
+    }
   }
 
   // The next step updates the hypertext of each node, which is a
   // concatenation of all of its child text nodes, so it can't run until
   // the text of all of the nodes was computed in the previous step.
-  for (size_t i = 0; i < changes.size(); ++i) {
-    const ui::AXNode* changed_node = changes[i].node;
+  for (const auto& change : changes) {
+    const ui::AXNode* changed_node = change.node;
     DCHECK(changed_node);
     BrowserAccessibility* obj = GetFromAXNode(changed_node);
     if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf())
@@ -401,13 +402,13 @@
   // client may walk the tree when it receives any of these events.
   // At the end, it deletes old_win_attributes_ since they're not needed
   // anymore.
-  for (size_t i = 0; i < changes.size(); ++i) {
-    const ui::AXNode* changed_node = changes[i].node;
+  for (const auto& change : changes) {
+    const ui::AXNode* changed_node = change.node;
     DCHECK(changed_node);
     BrowserAccessibility* obj = GetFromAXNode(changed_node);
     if (obj && obj->IsNative() && !obj->PlatformIsChildOfLeaf()) {
       ToBrowserAccessibilityWin(obj)->GetCOM()->UpdateStep3FireEvents(
-          changes[i].type == AXTreeDelegate::SUBTREE_CREATED);
+          change.type == AXTreeDelegate::SUBTREE_CREATED);
     }
   }
 }
diff --git a/content/browser/media/android/media_player_renderer.cc b/content/browser/media/android/media_player_renderer.cc
index a98c609..426217d3 100644
--- a/content/browser/media/android/media_player_renderer.cc
+++ b/content/browser/media/android/media_player_renderer.cc
@@ -79,7 +79,7 @@
   // Force the initialization of |media_resource_getter_| first. If it fails,
   // the RenderFrameHost may have been destroyed already.
   if (!GetMediaResourceGetter()) {
-    DLOG(ERROR) << "Unable to retreive MediaResourceGetter";
+    DLOG(ERROR) << "Unable to retrieve MediaResourceGetter";
     init_cb.Run(media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
   }
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 124f533d..a22df9c1 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -266,17 +266,17 @@
   controller_->StopSession(200);  // Session 200 does not exist anymore
   // Clients in controller: [B/2]
   ASSERT_EQ(1, controller_->GetClientCount())
-      << "Stopping non-existant session 200 should be a no-op.";
+      << "Stopping non-existent session 200 should be a no-op.";
   controller_->StopSession(256);  // Session 256 never existed.
   // Clients in controller: [B/2]
   ASSERT_EQ(1, controller_->GetClientCount())
-      << "Stopping non-existant session 256 should be a no-op.";
+      << "Stopping non-existent session 256 should be a no-op.";
   ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
             controller_->RemoveClient(client_a_route_1, client_a_.get()))
       << "Removing already-removed client A/1 should fail.";
   // Clients in controller: [B/2]
   ASSERT_EQ(1, controller_->GetClientCount())
-      << "Removing non-existant session 200 should be a no-op.";
+      << "Removing non-existent session 200 should be a no-op.";
   ASSERT_EQ(400, controller_->RemoveClient(client_b_route_2, client_b_.get()))
       << "Removing client B/2 should return its session_id.";
   // Clients in controller: []
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 5f5ebb7..1cb8bee7 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -18,6 +18,7 @@
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/browser/child_process_launcher.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/service_manager/common_browser_interfaces.h"
@@ -293,6 +294,14 @@
   pid_receiver->SetPID(base::GetCurrentProcId());
 
   service_manager::EmbeddedServiceInfo device_info;
+
+  // This task runner may be used by some device service implementation bits to
+  // interface with dbus client code, which in turn imposes some subtle thread
+  // affinity on the clients. We therefore require a single-thread runner.
+  scoped_refptr<base::SingleThreadTaskRunner> device_blocking_task_runner =
+      base::CreateSingleThreadTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BACKGROUND});
+
 #if defined(OS_ANDROID)
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaGlobalRef<jobject> java_nfc_delegate;
@@ -302,15 +311,13 @@
   // See the comments on wake_lock_context_host.h and ContentNfcDelegate.java
   // respectively for comments on those parameters.
   device_info.factory =
-      base::Bind(&device::CreateDeviceService,
-                 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+      base::Bind(&device::CreateDeviceService, device_blocking_task_runner,
                  BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
                  base::Bind(&WakeLockContextHost::GetNativeViewForContext),
                  std::move(java_nfc_delegate));
 #else
   device_info.factory =
-      base::Bind(&device::CreateDeviceService,
-                 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+      base::Bind(&device::CreateDeviceService, device_blocking_task_runner,
                  BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
 #endif
   device_info.task_runner = base::ThreadTaskRunnerHandle::Get();
diff --git a/content/common/font_list.cc b/content/common/font_list.cc
index 0f2ca9d65..6160a2e 100644
--- a/content/common/font_list.cc
+++ b/content/common/font_list.cc
@@ -4,26 +4,20 @@
 
 #include "content/common/font_list.h"
 
-#include "base/lazy_instance.h"
-#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/lazy_task_runner.h"
 
 namespace content {
 
 namespace {
 
-struct FontListTaskRunner {
-  const scoped_refptr<base::SequencedTaskRunner> task_runner =
-      base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
-};
-
-base::LazyInstance<FontListTaskRunner>::Leaky g_font_list_task_runner =
-    LAZY_INSTANCE_INITIALIZER;
+base::LazySequencedTaskRunner g_font_list_task_runner =
+    LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER(
+        base::TaskTraits(base::MayBlock(), base::TaskPriority::USER_VISIBLE));
 
 }  // namespace
 
 scoped_refptr<base::SequencedTaskRunner> GetFontListTaskRunner() {
-  return g_font_list_task_runner.Get().task_runner;
+  return g_font_list_task_runner.Get();
 }
 
 }  // content
diff --git a/content/common/service_worker/service_worker_status_code.cc b/content/common/service_worker/service_worker_status_code.cc
index 726f9bb..c0df9c6 100644
--- a/content/common/service_worker/service_worker_status_code.cc
+++ b/content/common/service_worker/service_worker_status_code.cc
@@ -29,7 +29,7 @@
     case SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED:
       return "ServiceWorker failed to activate";
     case SERVICE_WORKER_ERROR_IPC_FAILED:
-      return "IPC connection was closed or IPC error has occured";
+      return "IPC connection was closed or IPC error has occurred";
     case SERVICE_WORKER_ERROR_NETWORK:
       return "Operation failed by network issue";
     case SERVICE_WORKER_ERROR_SECURITY:
diff --git a/content/gpu/in_process_gpu_thread.cc b/content/gpu/in_process_gpu_thread.cc
index b6e46519..291a524c 100644
--- a/content/gpu/in_process_gpu_thread.cc
+++ b/content/gpu/in_process_gpu_thread.cc
@@ -4,10 +4,12 @@
 
 #include "content/gpu/in_process_gpu_thread.h"
 
+#include "base/command_line.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/gpu/gpu_child_thread.h"
 #include "content/gpu/gpu_process.h"
+#include "content/public/common/content_switches.h"
 #include "gpu/config/gpu_info_collector.h"
 #include "gpu/config/gpu_util.h"
 #include "ui/gl/init/gl_factory.h"
@@ -53,10 +55,13 @@
 #endif
 
   gpu::GPUInfo gpu_info;
-  if (!gl::init::InitializeGLOneOff())
+  if (!gl::init::InitializeGLOneOff()) {
     VLOG(1) << "gl::init::InitializeGLOneOff failed";
-  else
-    gpu::CollectContextGraphicsInfo(&gpu_info);
+  } else {
+    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kSkipGpuDataLoading))
+      gpu::CollectContextGraphicsInfo(&gpu_info);
+  }
 
   gpu::GpuFeatureInfo gpu_feature_info =
       gpu::GetGpuFeatureInfo(gpu_info, *base::CommandLine::ForCurrentProcess());
diff --git a/content/network/DEPS b/content/network/DEPS
index d93e90f4..228301c 100644
--- a/content/network/DEPS
+++ b/content/network/DEPS
@@ -23,6 +23,7 @@
 specific_include_rules = {
   '.*_[a-z]*test.*': [
     "+content/public/common/content_paths.h",
+    "+content/public/common/service_names.mojom.h",
     "+content/public/test/test_url_loader_client.h",
   ],
 }
diff --git a/content/network/network_service_impl.cc b/content/network/network_service_impl.cc
index 9152e397..9b4b9b7c 100644
--- a/content/network/network_service_impl.cc
+++ b/content/network/network_service_impl.cc
@@ -57,7 +57,7 @@
 NetworkServiceImpl::NetworkServiceImpl(
     std::unique_ptr<service_manager::BinderRegistry> registry)
     : net_log_(new MojoNetLog), registry_(std::move(registry)), binding_(this) {
-  // |registry_| is nullptr in tests and when an in-process NetworkService is
+  // |registry_| is nullptr when an in-process NetworkService is
   // created directly. The latter is done in concert with using
   // CreateNetworkContextWithBuilder to ease the transition to using the network
   // service.
@@ -94,7 +94,8 @@
 }
 
 std::unique_ptr<NetworkServiceImpl> NetworkServiceImpl::CreateForTesting() {
-  return base::WrapUnique(new NetworkServiceImpl(nullptr));
+  return base::WrapUnique(new NetworkServiceImpl(
+      base::MakeUnique<service_manager::BinderRegistry>()));
 }
 
 void NetworkServiceImpl::RegisterNetworkContext(
diff --git a/content/network/network_service_unittest.cc b/content/network/network_service_unittest.cc
index 5a31c8e..d06aae1 100644
--- a/content/network/network_service_unittest.cc
+++ b/content/network/network_service_unittest.cc
@@ -10,6 +10,13 @@
 #include "content/network/network_context.h"
 #include "content/network/network_service_impl.h"
 #include "content/public/common/network_service.mojom.h"
+#include "content/public/common/service_names.mojom.h"
+#include "content/public/test/test_url_loader_client.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "services/service_manager/public/interfaces/service_factory.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -66,6 +73,110 @@
   run_loop.Run();
 }
 
+namespace {
+
+class ServiceTestClient : public service_manager::test::ServiceTestClient,
+                          public service_manager::mojom::ServiceFactory {
+ public:
+  explicit ServiceTestClient(service_manager::test::ServiceTest* test)
+      : service_manager::test::ServiceTestClient(test) {
+    registry_.AddInterface<service_manager::mojom::ServiceFactory>(base::Bind(
+        &ServiceTestClient::BindServiceFactoryRequest, base::Unretained(this)));
+  }
+  ~ServiceTestClient() override {}
+
+ protected:
+  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(interface_name, std::move(interface_pipe));
+  }
+
+  void CreateService(service_manager::mojom::ServiceRequest request,
+                     const std::string& name) override {
+    if (name == mojom::kNetworkServiceName) {
+      service_context_.reset(new service_manager::ServiceContext(
+          NetworkServiceImpl::CreateForTesting(), std::move(request)));
+    }
+  }
+
+  void BindServiceFactoryRequest(
+      service_manager::mojom::ServiceFactoryRequest request) {
+    service_factory_bindings_.AddBinding(this, std::move(request));
+  }
+
+ private:
+  service_manager::BinderRegistry registry_;
+  mojo::BindingSet<service_manager::mojom::ServiceFactory>
+      service_factory_bindings_;
+  std::unique_ptr<service_manager::ServiceContext> service_context_;
+};
+
+}  // namespace
+
+class NetworkServiceTestWithService
+    : public service_manager::test::ServiceTest {
+ public:
+  NetworkServiceTestWithService()
+      : ServiceTest("content_unittests",
+                    false,
+                    base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+  ~NetworkServiceTestWithService() override {}
+
+  void LoadURL(const GURL& url) {
+    mojom::NetworkServicePtr network_service;
+    connector()->BindInterface(mojom::kNetworkServiceName, &network_service);
+
+    mojom::NetworkContextPtr network_context;
+    mojom::NetworkContextParamsPtr context_params =
+        mojom::NetworkContextParams::New();
+    network_service->CreateNetworkContext(mojo::MakeRequest(&network_context),
+                                          std::move(context_params));
+
+    mojom::URLLoaderFactoryPtr loader_factory;
+    network_context->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
+                                            0);
+
+    mojom::URLLoaderPtr loader;
+    ResourceRequest request;
+    request.url = url;
+    request.method = "GET";
+    request.request_initiator = url::Origin();
+    loader_factory->CreateLoaderAndStart(
+        mojo::MakeRequest(&loader), 1, 1, mojom::kURLLoadOptionNone, request,
+        client_.CreateInterfacePtr(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+    client_.RunUntilComplete();
+  }
+
+  net::EmbeddedTestServer* test_server() { return &test_server_; }
+  TestURLLoaderClient* client() { return &client_; }
+
+ private:
+  std::unique_ptr<service_manager::Service> CreateService() override {
+    return base::MakeUnique<ServiceTestClient>(this);
+  }
+
+  void SetUp() override {
+    base::FilePath content_test_data(FILE_PATH_LITERAL("content/test/data"));
+    test_server_.AddDefaultHandlers(content_test_data);
+    ASSERT_TRUE(test_server_.Start());
+    service_manager::test::ServiceTest::SetUp();
+  }
+
+  net::EmbeddedTestServer test_server_;
+  TestURLLoaderClient client_;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkServiceTestWithService);
+};
+
+// Verifies that loading a URL through the network service's mojo interface
+// works.
+TEST_F(NetworkServiceTestWithService, Basic) {
+  LoadURL(test_server()->GetURL("/echo"));
+  EXPECT_EQ(net::OK, client()->completion_status().error_code);
+}
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java
index 2398c37..72a9a025 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java
@@ -60,7 +60,7 @@
     public void testAtomicWrite() {
         // Try writing a file that can't be created.
         byte[] data1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        Assert.assertFalse("Writing bad file succeded",
+        Assert.assertFalse("Writing bad file succeeded",
                 ImportantFileWriterAndroid.writeFileAtomically("/junk/junk", data1));
         File dir = InstrumentationRegistry.getInstrumentation().getTargetContext().getFilesDir();
         File testFile = new File(dir, "ImportantFileTest");
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index a5543a02..238a1a64 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -177,7 +177,7 @@
 
   // Returns whether the process is ready. The process is ready once both
   // conditions (which can happen in arbitrary order) are true:
-  // 1- the launcher reported a succesful launch
+  // 1- the launcher reported a successful launch
   // 2- the channel is connected.
   //
   // After that point, GetHandle() is valid, and deferred messages have been
diff --git a/content/public/browser/web_ui_message_handler.h b/content/public/browser/web_ui_message_handler.h
index 0582651..966992cb 100644
--- a/content/public/browser/web_ui_message_handler.h
+++ b/content/public/browser/web_ui_message_handler.h
@@ -47,8 +47,17 @@
   FRIEND_TEST_ALL_PREFIXES(WebUIMessageHandlerTest, ExtractDoubleValue);
   FRIEND_TEST_ALL_PREFIXES(WebUIMessageHandlerTest, ExtractStringValue);
 
-  // Subclasses must call this once the page is ready for JavaScript calls
-  // from this handler.
+  // This method must be called once the handler's corresponding JavaScript
+  // component is initialized. In practice, it should be called from a WebUI
+  // message handler similar to: 'initializeFooPage' or 'getInitialState'.
+  //
+  // There should be ideally one or two calls to this per handler, as JavaScript
+  // components should have a specific message that signals that it's initalized
+  // and ready to receive events from the C++ handler.
+  //
+  // This should never be called from a function that is not a message handler.
+  // This should never be called from a C++ callback used as a reply for a
+  // posted task or asynchronous operation.
   void AllowJavascript();
 
   // Helper methods:
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 475b6c4d..5c1277ed 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -59,7 +59,6 @@
 CONTENT_EXPORT extern const base::Feature kPassiveDocumentEventListeners;
 CONTENT_EXPORT extern const base::Feature kPassiveEventListenersDueToFling;
 CONTENT_EXPORT extern const base::Feature kPepper3DImageChromium;
-CONTENT_EXPORT extern const base::Feature kPointerEvents;
 CONTENT_EXPORT extern const base::Feature kPurgeAndSuspend;
 CONTENT_EXPORT extern const base::Feature kRafAlignedMouseInputEvents;
 CONTENT_EXPORT extern const base::Feature kRafAlignedTouchInputEvents;
diff --git a/content/renderer/media/audio_renderer_sink_cache_impl.cc b/content/renderer/media/audio_renderer_sink_cache_impl.cc
index 157fd88460..b563cbc2 100644
--- a/content/renderer/media/audio_renderer_sink_cache_impl.cc
+++ b/content/renderer/media/audio_renderer_sink_cache_impl.cc
@@ -201,7 +201,7 @@
     // When |force_delete_used| is set, it's expected that we are deleting a
     // used sink.
     DCHECK((!force_delete_used) || (force_delete_used && cache_iter->used))
-        << "Attempt to delete a non-aquired sink.";
+        << "Attempt to delete a non-acquired sink.";
 
     if (!force_delete_used && cache_iter->used)
       return;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 255f982..ab0ac6e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1888,7 +1888,10 @@
 service_manifest("content_unittests_manifest") {
   name = "content_unittests"
   source = "unittests_manifest.json"
-  packaged_services = [ "//services/file:manifest" ]
+  packaged_services = [
+    "//content/network:manifest",
+    "//services/file:manifest",
+  ]
 }
 
 catalog("content_unittests_catalog") {
diff --git a/content/test/data/data_url_navigations.html b/content/test/data/data_url_navigations.html
index 9f0e167..7f8df7b 100644
--- a/content/test/data/data_url_navigations.html
+++ b/content/test/data/data_url_navigations.html
@@ -99,7 +99,7 @@
 </button>
 <form method="post" action="data:unknown/mimetype,test">
   <input type=submit id='form-post-to-unknown-mimetype'
-         value='Submit form to data URL unkown mimetype'>
+         value='Submit form to data URL unknown mimetype'>
 </form>
 
 </html>
diff --git a/content/test/data/gpu/pixel_offscreenCanvas_2d_resize_on_worker.html b/content/test/data/gpu/pixel_offscreenCanvas_2d_resize_on_worker.html
index 02974877..a2ee770a3 100644
--- a/content/test/data/gpu/pixel_offscreenCanvas_2d_resize_on_worker.html
+++ b/content/test/data/gpu/pixel_offscreenCanvas_2d_resize_on_worker.html
@@ -16,17 +16,17 @@
 </style>
 <script id="myWorker" type="text/worker">
 self.onmessage = function(e) {
-  var transfered = e.data;
+  var transferred = e.data;
 
   // Resize offscreenCanvas from 200X200 to 40X50.
-  transfered.width = 40;
-  transfered.height = 50;
-  var ctx2d = transfered.getContext('2d');
+  transferred.width = 40;
+  transferred.height = 50;
+  var ctx2d = transferred.getContext('2d');
 
   // The resultant image should be 100X80 red-color rectangle in the middle
   // of green background.
   ctx2d.fillStyle = "green";
-  ctx2d.fillRect(0, 0, transfered.width, transfered.height);
+  ctx2d.fillRect(0, 0, transferred.width, transferred.height);
   ctx2d.fillStyle = "red";
   ctx2d.fillRect(10, 10, 20, 20);
   ctx2d.commit().then(function() {
diff --git a/content/test/data/gpu/pixel_offscreenCanvas_webgl_resize_on_worker.html b/content/test/data/gpu/pixel_offscreenCanvas_webgl_resize_on_worker.html
index 66a401cf..a2501a0 100644
--- a/content/test/data/gpu/pixel_offscreenCanvas_webgl_resize_on_worker.html
+++ b/content/test/data/gpu/pixel_offscreenCanvas_webgl_resize_on_worker.html
@@ -60,13 +60,13 @@
 }
 
 self.onmessage = function(e) {
-  var transfered = e.data;
+  var transferred = e.data;
   // Resize the canvas from 200X200 to 40X50
   // The triangle should scale proportionately with edge softened
-  transfered.width = 40;
-  transfered.height = 50;
+  transferred.width = 40;
+  transferred.height = 50;
 
-  var gl = transfered.getContext('webgl');
+  var gl = transferred.getContext('webgl');
   drawTriangle(gl);
   gl.commit();
 
diff --git a/content/test/unittests_manifest.json b/content/test/unittests_manifest.json
index 94cb81e..7246822 100644
--- a/content/test/unittests_manifest.json
+++ b/content/test/unittests_manifest.json
@@ -9,7 +9,8 @@
          ]
       },
       "requires": {
-        "file": [ "file:filesystem", "file:leveldb" ]
+        "file": [ "file:filesystem", "file:leveldb" ],
+        "network": [ "network_service" ]
       }
     }
   }
diff --git a/docs/code_reviews.md b/docs/code_reviews.md
index af8e91e2..340380a4 100644
--- a/docs/code_reviews.md
+++ b/docs/code_reviews.md
@@ -192,8 +192,10 @@
 ```
 
 The text `set noparent` will stop owner propagation from parent directories.
-This is used for specialized code. In this example, only the two listed people
-are owners:
+This should be rarely used. If you want to use `set noparent` except for IPC
+related files, please first reach out to chrome-eng-review@google.com.
+
+In this example, only the two listed people are owners:
 ```
 set noparent
 a@chromium.org
diff --git a/docs/testing/layout_test_expectations.md b/docs/testing/layout_test_expectations.md
index c283864..5dff49de 100644
--- a/docs/testing/layout_test_expectations.md
+++ b/docs/testing/layout_test_expectations.md
@@ -236,7 +236,7 @@
 * `WontFix` implies `Skip` and also indicates that we don't have any plans to
   make the test pass.
 * `WontFix` lines always go in the
-  [NeverFixTests file]((../../third_party/WebKit/LayoutTests/NeverFixTests) as
+  [NeverFixTests file](../../third_party/WebKit/LayoutTests/NeverFixTests) as
   we never intend to fix them. These are just for tests that only apply to some
   subset of the platforms we support.
 * `WontFix` and `Skip` must be used by themselves and cannot be specified
diff --git a/docs/testing/layout_tests.md b/docs/testing/layout_tests.md
index c8c8d25..9040fb3ad 100644
--- a/docs/testing/layout_tests.md
+++ b/docs/testing/layout_tests.md
@@ -220,7 +220,7 @@
   ```
 
   This will create new "virtual" tests of the form
-  `virtual/blocking_repaint/fast/repaint/...`` which correspond to the files
+  `virtual/blocking_repaint/fast/repaint/...` which correspond to the files
   under `LayoutTests/fast/repaint` and pass `--blocking-repaint` to
   content_shell when they are run.
 
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc
index e0362f6c..e6bad46b 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -300,19 +300,18 @@
       observer);
 }
 
-void CastChannelOpenFunction::OnOpen(int channel_id, ChannelError result) {
+void CastChannelOpenFunction::OnOpen(CastSocket* socket) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   VLOG(1) << "Connect finished, OnOpen invoked.";
+  DCHECK(socket);
   // TODO: If we failed to open the CastSocket, we may want to clean up here,
   // rather than relying on the extension to call close(). This can be done by
   // calling RemoveSocket() and api_->GetLogger()->ClearLastError(channel_id).
-  if (result != ChannelError::UNKNOWN) {
-    CastSocket* socket = cast_socket_service_->GetSocket(channel_id);
-    CHECK(socket);
+  if (socket->error_state() != ChannelError::UNKNOWN) {
     SetResultFromSocket(*socket);
   } else {
     // The socket is being destroyed.
-    SetResultFromError(channel_id, api::cast_channel::CHANNEL_ERROR_UNKNOWN);
+    SetResultFromError(socket->id(), api::cast_channel::CHANNEL_ERROR_UNKNOWN);
   }
 
   AsyncWorkCompleted();
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.h b/extensions/browser/api/cast_channel/cast_channel_api.h
index 69c2a74..949f9b5 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.h
+++ b/extensions/browser/api/cast_channel/cast_channel_api.h
@@ -167,7 +167,9 @@
   static net::IPEndPoint* ParseConnectInfo(
       const api::cast_channel::ConnectInfo& connect_info);
 
-  void OnOpen(int channel_id, cast_channel::ChannelError result);
+  // |socket|: raw pointer of newly created cast channel. Does not take
+  // ownership of |socket|.
+  void OnOpen(cast_channel::CastSocket* socket);
 
   std::unique_ptr<api::cast_channel::Open::Params> params_;
   CastChannelAPI* api_;
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
index ab3cb769..b2d7f3c 100644
--- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -111,7 +111,7 @@
       EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
           .WillOnce(WithArgs<0>(
               Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
-                callback.Run(mock_cast_socket_->id(), ChannelError::NONE);
+                callback.Run(mock_cast_socket_);
               })));
       EXPECT_CALL(*mock_cast_socket_, ready_state())
           .WillOnce(Return(ReadyState::OPEN));
@@ -138,7 +138,7 @@
       EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
           .WillOnce(WithArgs<0>(
               Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
-                callback.Run(mock_cast_socket_->id(), ChannelError::NONE);
+                callback.Run(mock_cast_socket_);
               })));
       EXPECT_CALL(*mock_cast_socket_, ready_state())
           .WillOnce(Return(ReadyState::OPEN))
@@ -306,7 +306,7 @@
     EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
         .WillOnce(WithArgs<0>(
             Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
-              callback.Run(mock_cast_socket_->id(), ChannelError::NONE);
+              callback.Run(mock_cast_socket_);
             })));
     EXPECT_CALL(*mock_cast_socket_, ready_state())
         .Times(3)
@@ -343,7 +343,7 @@
   EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
       .WillOnce(WithArgs<0>(
           Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
-            callback.Run(mock_cast_socket_->id(), ChannelError::CONNECT_ERROR);
+            callback.Run(mock_cast_socket_);
           })));
   mock_cast_socket_->SetErrorState(ChannelError::CONNECT_ERROR);
   EXPECT_CALL(*mock_cast_socket_, ready_state())
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index cb2cc2e..ebe19a2 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -292,11 +292,6 @@
     command_line->AppendSwitch(switches::kDisableBookmarkReordering);
   }
 
-  // Populate command line flag for the request mobile site experiment from the
-  // configuration plist.
-  if ([defaults boolForKey:@"RequestMobileSiteDisabled"])
-    command_line->AppendSwitch(switches::kDisableRequestMobileSite);
-
   // Populate command line flag for 3rd party keyboard omnibox workaround.
   NSString* enableThirdPartyKeyboardWorkaround =
       [defaults stringForKey:@"EnableThirdPartyKeyboardWorkaround"];
diff --git a/ios/chrome/browser/chrome_switches.cc b/ios/chrome/browser/chrome_switches.cc
index 6360310..4d196a63 100644
--- a/ios/chrome/browser/chrome_switches.cc
+++ b/ios/chrome/browser/chrome_switches.cc
@@ -44,9 +44,6 @@
 // Disables Physical Web scanning for nearby URLs.
 const char kDisableIOSPhysicalWeb[] = "disable-ios-physical-web";
 
-// Disables Request Mobile Site.
-const char kDisableRequestMobileSite[] = "disable-request-mobile-site";
-
 // Disables the Suggestions UI
 const char kDisableSuggestionsUI[] = "disable-suggestions-ui";
 
diff --git a/ios/chrome/browser/chrome_switches.h b/ios/chrome/browser/chrome_switches.h
index 885b6e6..28c5600 100644
--- a/ios/chrome/browser/chrome_switches.h
+++ b/ios/chrome/browser/chrome_switches.h
@@ -19,7 +19,6 @@
 extern const char kDisableOfflineAutoReload[];
 extern const char kDisableTabStripAutoScrollNewTabs[];
 extern const char kDisableIOSPhysicalWeb[];
-extern const char kDisableRequestMobileSite[];
 extern const char kDisableSuggestionsUI[];
 extern const char kDisableBookmarkReordering[];
 extern const char kDisableSlimNavigationManager[];
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h
index e029230..ad9cbc7 100644
--- a/ios/chrome/browser/experimental_flags.h
+++ b/ios/chrome/browser/experimental_flags.h
@@ -69,9 +69,6 @@
 // Whether reader mode is enabled.
 bool IsReaderModeEnabled();
 
-// Whether request mobile site is enabled.
-bool IsRequestMobileSiteEnabled();
-
 // Whether the Sign In Flow via SFSafariViewController is enabled.
 bool IsSafariVCSignInEnabled();
 
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index b4ab53f..58a761b 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -189,11 +189,6 @@
       switches::kEnableReaderModeToolbarIcon);
 }
 
-bool IsRequestMobileSiteEnabled() {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  return !command_line->HasSwitch(switches::kDisableRequestMobileSite);
-}
-
 bool IsSafariVCSignInEnabled() {
   return ![[NSUserDefaults standardUserDefaults]
       boolForKey:kSafariVCSignInDisabled];
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index 2ec3ef82..d4f16ce5 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -686,12 +686,8 @@
   form->signon_realm = form->origin.ReplaceComponents(remove_path).spec();
 
   std::string action;
-  // Not checking the return value, as empty action is valid.
   dictionary->GetString("action", &action);
-  GURL actionUrl = action.empty() ? originUrl : originUrl.Resolve(action);
-  if (!actionUrl.is_valid())
-    return NO;
-  form->action = stripURL(actionUrl);
+  form->action = GURL(action);
 
   if (!dictionary->GetString("usernameElement", &form->username_element) ||
       !dictionary->GetString("usernameValue", &form->username_value) ||
diff --git a/ios/chrome/browser/passwords/password_controller_js_unittest.mm b/ios/chrome/browser/passwords/password_controller_js_unittest.mm
index 77f0e1d8..671bf85 100644
--- a/ios/chrome/browser/passwords/password_controller_js_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_js_unittest.mm
@@ -209,7 +209,7 @@
   const std::string base_url = BaseUrl();
   NSString* result = [NSString
       stringWithFormat:
-          @"[{\"action\":\"/generic_submit\","
+          @"[{\"action\":\"https://chromium.test/generic_submit\","
            "\"method\":\"post\","
            "\"name\":\"login_form\","
            "\"origin\":\"%s\","
@@ -244,7 +244,7 @@
   const std::string base_url = BaseUrl();
   NSString* result = [NSString
       stringWithFormat:
-          @"[{\"action\":\"/generic_submit\","
+          @"[{\"action\":\"https://chromium.test/generic_submit\","
            "\"method\":\"post\","
            "\"name\":\"login_form1\","
            "\"origin\":\"%s\","
@@ -254,7 +254,7 @@
            "\"usernameElement\":\"name\","
            "\"usernameValue\":\"\","
            "\"passwords\":[{\"element\":\"password\",\"value\":\"\"}]},"
-           "{\"action\":\"/generic_s2\","
+           "{\"action\":\"https://chromium.test/generic_s2\","
            "\"method\":\"post\","
            "\"name\":\"login_form2\","
            "\"origin\":\"%s\","
@@ -284,7 +284,7 @@
   NSString* parameter = @"window.document.getElementsByTagName('form')[0]";
   NSString* result = [NSString
       stringWithFormat:
-          @"{\"action\":\"/generic_submit\","
+          @"{\"action\":\"https://chromium.test/generic_submit\","
            "\"method\":\"post\","
            "\"name\":\"np\","
            "\"origin\":\"%s\","
@@ -301,4 +301,34 @@
           @"__gCrWeb.stringify(__gCrWeb.getPasswordFormData(%@))", parameter));
 };
 
+// Check that if a form action is not set then the action is parsed to the
+// current url.
+TEST_F(PasswordControllerJsTest, FormActionIsNotSet) {
+  LoadHtmlAndInject(
+      @"<html><body>"
+       "<form name='login_form'>"
+       "  Name: <input type='text' name='name'>"
+       "  Password: <input type='password' name='password'>"
+       "  <input type='submit' value='Submit'>"
+       "</form>"
+       "</body></html>");
+
+  const std::string base_url = BaseUrl();
+  NSString* result = [NSString
+      stringWithFormat:
+          @"[{\"action\":\"https://chromium.test/\","
+           "\"method\":null,"
+           "\"name\":\"login_form\","
+           "\"origin\":\"%s\","
+           "\"fields\":[{\"element\":\"name\",\"type\":\"text\"},"
+           "{\"element\":\"password\",\"type\":\"password\"},"
+           "{\"element\":\"\",\"type\":\"submit\"}],"
+           "\"usernameElement\":\"name\","
+           "\"usernameValue\":\"\","
+           "\"passwords\":[{\"element\":\"password\",\"value\":\"\"}]}]",
+          base_url.c_str()];
+  EXPECT_NSEQ(result,
+              ExecuteJavaScriptWithFormat(@"__gCrWeb.findPasswordForms()"));
+};
+
 }  // namespace
diff --git a/ios/chrome/browser/passwords/password_controller_unittest.mm b/ios/chrome/browser/passwords/password_controller_unittest.mm
index e8782aa..9f99187 100644
--- a/ios/chrome/browser/passwords/password_controller_unittest.mm
+++ b/ios/chrome/browser/passwords/password_controller_unittest.mm
@@ -268,7 +268,7 @@
     // to be stripped off. The password is recognized as an old password.
     {
       "http://john:doe@fakedomain.com/foo/bar?baz=quz#foobar",
-      "{ \"action\": \"some/action?to=be&or=not#tobe\","
+      "{ \"action\": \"http://fakedomain.com/foo/some/action\","
           "\"usernameElement\": \"account\","
           "\"usernameValue\": \"fakeaccount\","
           "\"name\": \"signup\","
@@ -289,7 +289,7 @@
     // due to an origin mismatch.
     {
       "http://john:doe@fakedomain.com/foo/bar?baz=quz#foobar",
-      "{ \"action\": \"some/action?to=be&or=not#tobe\","
+      "{ \"action\": \"\","
           "\"usernameElement\": \"account\","
           "\"usernameValue\": \"fakeaccount\","
           "\"name\": \"signup\","
@@ -334,7 +334,7 @@
     // to enter the old password and new password.
     {
       "http://fakedomain.com/foo",
-      "{ \"action\": \"\","
+      "{ \"action\": \"http://fakedomain.com/foo\","
           "\"usernameElement\": \"account\","
           "\"usernameValue\": \"fakeaccount\","
           "\"name\": \"signup\","
@@ -357,7 +357,7 @@
     // does not make sense.
     {
       "http://fakedomain.com",
-      "{ \"action\": \"\","
+      "{ \"action\": \"http://fakedomain.com/\","
           "\"usernameElement\": \"account\","
           "\"usernameValue\": \"fakeaccount\","
           "\"name\": \"signup\","
@@ -381,7 +381,7 @@
     // password is the old one.
     {
       "http://fakedomain.com",
-      "{ \"action\": \"\","
+      "{ \"action\": \"http://fakedomain.com/\","
           "\"usernameElement\": \"account\","
           "\"usernameValue\": \"fakeaccount\","
           "\"name\": \"signup\","
@@ -405,7 +405,7 @@
     // password is the new one.
     {
       "http://fakedomain.com",
-      "{ \"action\": \"\","
+      "{ \"action\": \"http://fakedomain.com/\","
           "\"usernameElement\": \"account\","
           "\"usernameValue\": \"fakeaccount\","
           "\"name\": \"signup\","
diff --git a/ios/chrome/browser/passwords/resources/password_controller.js b/ios/chrome/browser/passwords/resources/password_controller.js
index 994e0172..ea091656 100644
--- a/ios/chrome/browser/passwords/resources/password_controller.js
+++ b/ios/chrome/browser/passwords/resources/password_controller.js
@@ -80,6 +80,19 @@
   };
 
   /**
+   * Returns a canonical action for |formElement|. It works the same as upstream
+   * function GetCanonicalActionForForm.
+   * @param {Form} formElement.
+   * @return {string} Canonical action.
+   */
+  var getCanonicalActionForForm_ = function(formElement) {
+    var raw_action = formElement.getAttribute('action') || "";
+    var absolute_url = __gCrWeb.common.absoluteURL(
+          formElement.ownerDocument, raw_action);
+    return __gCrWeb.common.removeQueryAndReferenceFromURL(absolute_url);
+  };
+
+  /**
    * Returns the password form with the given |name| as a JSON string.
    * @param {string} name The name of the form to extract.
    * @return {string} The password form.
@@ -111,8 +124,7 @@
     for (var i = 0; i < forms.length; i++) {
       var form = forms[i];
       var normalizedFormAction = opt_normalizedAction ||
-          __gCrWeb.common.removeQueryAndReferenceFromURL(
-              __gCrWeb.common.absoluteURL(doc, form.action));
+          getCanonicalActionForForm_(form);
       if (formData.action != normalizedFormAction) {
         continue;
       }
@@ -455,7 +467,7 @@
         formElement.ownerDocument.location.href);
 
     return {
-      'action': formElement.getAttribute('action'),
+      'action': getCanonicalActionForForm_(formElement),
       'method': formElement.getAttribute('method'),
       'name': __gCrWeb.common.getFormIdentifier(formElement),
       'origin': origin,
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
index 9b32fbb..0125c83 100644
--- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
+++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -30,22 +30,6 @@
 			<key>Type</key>
 			<string>PSGroupSpecifier</string>
 			<key>Title</key>
-			<string>Request Mobile Site</string>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSToggleSwitchSpecifier</string>
-			<key>Title</key>
-			<string>Disable Request Mobile Site</string>
-			<key>Key</key>
-			<string>RequestMobileSiteDisabled</string>
-			<key>DefaultValue</key>
-			<false/>
-		</dict>
-		<dict>
-			<key>Type</key>
-			<string>PSGroupSpecifier</string>
-			<key>Title</key>
 			<string>iPad Tab Strip</string>
 		</dict>
 		<dict>
diff --git a/ios/chrome/browser/ui/print/print_controller_egtest.mm b/ios/chrome/browser/ui/print/print_controller_egtest.mm
index 25b993e3..425e1b6 100644
--- a/ios/chrome/browser/ui/print/print_controller_egtest.mm
+++ b/ios/chrome/browser/ui/print/print_controller_egtest.mm
@@ -9,6 +9,7 @@
 #include "base/ios/ios_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
+#import "ios/chrome/test/app/chrome_test_util.h"
 #include "ios/chrome/test/app/navigation_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
@@ -46,12 +47,6 @@
 // Tests that the AirPrint menu successfully loads when a normal web page is
 // loaded.
 - (void)testPrintNormalPage {
-  // TODO(crbug.com/747622): re-enable this test on iOS 11 once earl grey can
-  // interact with the share menu.
-  if (base::ios::IsRunningOnIOS11OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 11.");
-  }
-
   GURL url = web::test::HttpServer::MakeUrl(kHTMLURL);
   std::map<GURL, std::string> responses;
   std::string response = "Test";
@@ -66,12 +61,6 @@
 
 // Tests that the AirPrint menu successfully loads when a PDF is loaded.
 - (void)testPrintPDF {
-  // TODO(crbug.com/747622): re-enable this test on iOS 11 once earl grey can
-  // interact with the share menu.
-  if (base::ios::IsRunningOnIOS11OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 11.");
-  }
-
   web::test::SetUpFileBasedHttpServer();
   GURL url = web::test::HttpServer::MakeUrl(kPDFURL);
   chrome_test_util::LoadUrl(url);
@@ -80,15 +69,20 @@
 }
 
 - (void)printCurrentPage {
-  [ChromeEarlGreyUI openShareMenu];
-
-  id<GREYMatcher> printButton =
-      grey_allOf(grey_accessibilityLabel(@"Print"),
-                 grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
-  [[EarlGrey selectElementWithMatcher:printButton] performAction:grey_tap()];
+  // EarlGrey does not have the ability to interact with the share menu in
+  // iOS11, so use the dispatcher to trigger the print view controller instead.
+  if (base::ios::IsRunningOnIOS11OrLater()) {
+    [chrome_test_util::DispatcherForActiveViewController() printTab];
+  } else {
+    [ChromeEarlGreyUI openShareMenu];
+    id<GREYMatcher> printButton =
+        grey_allOf(grey_accessibilityLabel(@"Print"),
+                   grey_accessibilityTrait(UIAccessibilityTraitButton), nil);
+    [[EarlGrey selectElementWithMatcher:printButton] performAction:grey_tap()];
+  }
 
   id<GREYMatcher> printerOptionButton = grey_allOf(
-      grey_accessibilityLabel(@"Printer Options"),
+      grey_accessibilityID(@"Printer Options"),
       grey_not(grey_accessibilityTrait(UIAccessibilityTraitHeader)), nil);
   [[EarlGrey selectElementWithMatcher:printerOptionButton]
       assertWithMatcher:grey_sufficientlyVisible()];
diff --git a/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm b/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm
index 2c6b5a8..4df8100 100644
--- a/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm
+++ b/ios/chrome/browser/ui/tools_menu/request_desktop_mobile_site_egtest.mm
@@ -155,10 +155,6 @@
 // Tests that requesting mobile site of a page works and the user agent
 // propagates to the next navigations in the same tab.
 - (void)testRequestMobileSitePropagatesToNextNavigations {
-  if (!experimental_flags::IsRequestMobileSiteEnabled()) {
-    EARL_GREY_TEST_SKIPPED(@"Only enabled Request Mobile Site.");
-  }
-
   std::unique_ptr<web::DataResponseProvider> provider(
       new UserAgentResponseProvider());
   web::test::SetUpHttpServer(std::move(provider));
@@ -187,10 +183,6 @@
 // Tests that requesting mobile site of a page works and going back re-opens
 // desktop version of the page.
 - (void)testRequestMobileSiteGoBackToDesktop {
-  if (!experimental_flags::IsRequestMobileSiteEnabled()) {
-    EARL_GREY_TEST_SKIPPED(@"Only enabled Request Mobile Site.");
-  }
-
   std::unique_ptr<web::DataResponseProvider> provider(
       new UserAgentResponseProvider());
   web::test::SetUpHttpServer(std::move(provider));
@@ -257,10 +249,6 @@
 // Tests that navigator.appVersion JavaScript API returns correct string for
 // mobile User Agent.
 - (void)testAppVersionJSAPIWithMobileUserAgent {
-  if (!experimental_flags::IsRequestMobileSiteEnabled()) {
-    EARL_GREY_TEST_SKIPPED(@"Only enabled Request Mobile Site.");
-  }
-
   web::test::SetUpFileBasedHttpServer();
   [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kUserAgentTestURL)];
   // Verify initial reception of the mobile site.
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
index eb2094f..7c4bc08 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_model.mm
@@ -113,15 +113,9 @@
           ->GetUserFeedbackProvider()
           ->IsUserFeedbackEnabled();
     case IDS_IOS_TOOLS_MENU_REQUEST_DESKTOP_SITE:
-      if (experimental_flags::IsRequestMobileSiteEnabled())
-        return (configuration.userAgentType != web::UserAgentType::DESKTOP);
-      else
-        return true;
+      return (configuration.userAgentType != web::UserAgentType::DESKTOP);
     case IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE:
-      if (experimental_flags::IsRequestMobileSiteEnabled())
-        return (configuration.userAgentType == web::UserAgentType::DESKTOP);
-      else
-        return false;
+      return (configuration.userAgentType == web::UserAgentType::DESKTOP);
     default:
       return true;
   }
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
index 6eb4385..1e3dc67 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -294,12 +294,6 @@
       break;
     case web::UserAgentType::DESKTOP:
       [self setItemEnabled:YES withTag:IDC_REQUEST_MOBILE_SITE];
-      if (!experimental_flags::IsRequestMobileSiteEnabled()) {
-        // When Request Mobile Site is disabled, the enabled state of Request
-        // Desktop Site button needs to be set to NO because it is visible even
-        // though the current UserAgentType is DESKTOP.
-        [self setItemEnabled:NO withTag:IDC_REQUEST_DESKTOP_SITE];
-      }
       break;
   }
 
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
index bbf5ae4..0923da1a 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller_unittest.mm
@@ -84,13 +84,7 @@
   ToolsMenuViewItem* mobile_item =
       GetToolsMenuViewItemWithTag(IDC_REQUEST_MOBILE_SITE);
 
-  if (experimental_flags::IsRequestMobileSiteEnabled()) {
-    EXPECT_FALSE(desktop_item);
-    ASSERT_TRUE(mobile_item);
-    EXPECT_TRUE(mobile_item.active);
-  } else {
-    ASSERT_TRUE(desktop_item);
-    EXPECT_FALSE(desktop_item.active);
-    EXPECT_FALSE(mobile_item);
-  }
+  EXPECT_FALSE(desktop_item);
+  ASSERT_TRUE(mobile_item);
+  EXPECT_TRUE(mobile_item.active);
 }
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index dba1acb4..6eccc90 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -8,13 +8,15 @@
 // Used by IPC_BEGIN_MESSAGES so that each message class starts from a unique
 // base.  Messages have unique IDs across channels in order for the IPC logging
 // code to figure out the message class from its ID.
+//
+// You should no longer be adding any new message classes. Instead, use mojo
+// for all new work.
 enum IPCMessageStart {
   AutomationMsgStart = 0,
   FrameMsgStart,
   PageMsgStart,
   ViewMsgStart,
   InputMsgStart,
-  ProfileImportMsgStart,
   TestMsgStart,
   DevToolsMsgStart,
   WorkerMsgStart,
@@ -43,17 +45,12 @@
   PrintMsgStart,
   SpellCheckMsgStart,
   ExtensionMsgStart,
-  VideoCaptureMsgStart,
   QuotaMsgStart,
   TextInputClientMsgStart,
-  ChromeUtilityMsgStart,
   MediaStreamMsgStart,
-  ChromeBenchmarkingMsgStart,
   JavaBridgeMsgStart,
-  GamepadMsgStart,
   ShellMsgStart,
   AccessibilityMsgStart,
-  PrefetchMsgStart,
   PrerenderMsgStart,
   ChromotingMsgStart,
   BrowserPluginMsgStart,
@@ -63,37 +60,27 @@
   MediaPlayerMsgStart,
   TracingMsgStart,
   PeerConnectionTrackerMsgStart,
-  VisitedLinkMsgStart,
   AppShimMsgStart,
   WebRtcLoggingMsgStart,
   TtsMsgStart,
-  WebSocketMsgStart,
   NaClHostMsgStart,
-  WebRTCIdentityMsgStart,
-  PowerMonitorMsgStart,
   EncryptedMediaMsgStart,
   CacheStorageMsgStart,
   ServiceWorkerMsgStart,
-  MessagePortMsgStart,
   EmbeddedWorkerMsgStart,
   EmbeddedWorkerContextMsgStart,
   CastMsgStart,
-  CdmMsgStart,
   MediaStreamTrackMetricsHostMsgStart,
   ChromeExtensionMsgStart,
-  PushMessagingMsgStart,
   GinJavaBridgeMsgStart,
   ChromeUtilityPrintingMsgStart,
   AecDumpMsgStart,
   OzoneGpuMsgStart,
   ChromeUtilityExtensionsMsgStart,
   PlatformNotificationMsgStart,
-  PDFMsgStart,
   LayoutTestMsgStart,
   NetworkHintsMsgStart,
-  BluetoothMsgStart,
   CastMediaMsgStart,
-  AwMessagePortMsgStart,
   SyncCompositorMsgStart,
   ExtensionsGuestViewMsgStart,
   GuestViewMsgStart,
@@ -101,16 +88,8 @@
   // internal code. Contact gunsch@ before changing/removing.
   CastCryptoMsgStart,
   CastChannelMsgStart,
-  DataReductionProxyStart,
-  ChromeAppBannerMsgStart,
-  AttachmentBrokerMsgStart,
   RenderProcessMsgStart,
-  PageLoadMetricsMsgStart,
   IPCTestMsgStart,
-  ArcInstanceMsgStart,
-  ArcInstanceHostMsgStart,
-  DistillerMsgStart,
-  ArcCameraMsgStart,
   DWriteFontProxyMsgStart,
   MediaPlayerDelegateMsgStart,
   SurfaceViewManagerMsgStart,
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 476298d..d9076b1 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -3998,6 +3998,24 @@
             simple_cache_impl_->index()->init_method());
 }
 
+TEST_F(DiskCacheBackendTest, SimpleCacheNegMaxSize) {
+  SetMaxSize(-1);
+  SetSimpleCacheMode();
+  InitCache();
+  // We don't know what it will pick, but it's limited to what
+  // disk_cache::PreferredCacheSize would return, scaled by the size experiment,
+  // which only goes as much as 2x. It definitely should not be MAX_UINT64.
+  EXPECT_NE(simple_cache_impl_->index()->max_size(),
+            std::numeric_limits<uint64_t>::max());
+
+  int max_default_size =
+      2 * disk_cache::PreferredCacheSize(std::numeric_limits<int32_t>::max());
+
+  ASSERT_GE(max_default_size, 0);
+  EXPECT_LT(simple_cache_impl_->index()->max_size(),
+            static_cast<unsigned>(max_default_size));
+}
+
 TEST_F(DiskCacheBackendTest, SimpleLastModified) {
   // Simple cache used to incorrectly set LastModified on entries based on
   // timestamp of the cache directory, and not the entries' file
diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc
index 8db204b..da9fbb9 100644
--- a/net/disk_cache/simple/simple_backend_impl.cc
+++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -263,6 +263,10 @@
                                  ? SimpleEntryImpl::OPTIMISTIC_OPERATIONS
                                  : SimpleEntryImpl::NON_OPTIMISTIC_OPERATIONS),
       net_log_(net_log) {
+  // Treat negative passed-in sizes same as SetMaxSize would here and in other
+  // backends, as default (if first call).
+  if (orig_max_size_ < 0)
+    orig_max_size_ = 0;
   MaybeHistogramFdLimit(cache_type_);
 }
 
diff --git a/remoting/ios/display/gl_display_handler.mm b/remoting/ios/display/gl_display_handler.mm
index e50a3d24..0365a4d 100644
--- a/remoting/ios/display/gl_display_handler.mm
+++ b/remoting/ios/display/gl_display_handler.mm
@@ -61,6 +61,8 @@
   void SurfaceChanged(int width, int height);
 
   std::unique_ptr<protocol::FrameConsumer> GrabFrameConsumer();
+
+  // Returns a weak pointer to be used on the display thread.
   base::WeakPtr<Core> GetWeakPtr();
 
  private:
@@ -93,9 +95,6 @@
 
   weak_ptr_ = weak_factory_.GetWeakPtr();
 
-  runtime_->display_task_runner()->PostTask(
-      FROM_HERE, base::Bind(&Core::Initialize, base::Unretained(this)));
-
   // Do not bind GlRenderer::OnFrameReceived. |renderer_| is not ready yet.
   owned_frame_consumer_.reset(new remoting::DualBufferFrameConsumer(
       base::Bind(&Core::OnFrameReceived, weak_ptr_),
@@ -106,6 +105,9 @@
   owned_renderer_proxy_.reset(
       new RendererProxy(runtime_->display_task_runner()));
   renderer_proxy_ = owned_renderer_proxy_->GetWeakPtr();
+
+  runtime_->display_task_runner()->PostTask(
+      FROM_HERE, base::Bind(&Core::Initialize, GetWeakPtr()));
 }
 
 Core::~Core() {
diff --git a/services/service_manager/public/cpp/service_test.cc b/services/service_manager/public/cpp/service_test.cc
index 3c0175c..9419d24 100644
--- a/services/service_manager/public/cpp/service_test.cc
+++ b/services/service_manager/public/cpp/service_test.cc
@@ -34,9 +34,10 @@
 
 ServiceTest::ServiceTest() : ServiceTest(std::string(), true) {}
 
-ServiceTest::ServiceTest(const std::string& test_name, bool init_edk)
-    : scoped_task_environment_(
-          base::test::ScopedTaskEnvironment::MainThreadType::UI),
+ServiceTest::ServiceTest(const std::string& test_name,
+                         bool init_edk,
+                         base::test::ScopedTaskEnvironment::MainThreadType type)
+    : scoped_task_environment_(type),
       test_name_(test_name),
       init_edk_(init_edk) {}
 
diff --git a/services/service_manager/public/cpp/service_test.h b/services/service_manager/public/cpp/service_test.h
index ca20fdd..3014409 100644
--- a/services/service_manager/public/cpp/service_test.h
+++ b/services/service_manager/public/cpp/service_test.h
@@ -60,7 +60,10 @@
   // Once set via this constructor, it cannot be changed later by calling
   // InitTestName(). The test executable must provide a manifest in the
   // appropriate location that specifies this name also.
-  explicit ServiceTest(const std::string& test_name, bool init_edk = false);
+  ServiceTest(const std::string& test_name,
+              bool init_edk = false,
+              base::test::ScopedTaskEnvironment::MainThreadType type =
+                  base::test::ScopedTaskEnvironment::MainThreadType::UI);
   ~ServiceTest() override;
 
  protected:
diff --git a/third_party/WebKit/LayoutTests/fast/table/backgr_fixed-bg-table-expected.txt b/third_party/WebKit/LayoutTests/fast/table/backgr_fixed-bg-table-expected.txt
deleted file mode 100644
index 63245c7..0000000
--- a/third_party/WebKit/LayoutTests/fast/table/backgr_fixed-bg-table-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x162
-  LayoutBlockFlow {HTML} at (0,0) size 800x162
-    LayoutBlockFlow {BODY} at (8,16) size 784x138
-      LayoutBlockFlow {P} at (0,0) size 784x20
-        LayoutText {#text} at (0,0) size 508x19
-          text run at (0,0) width 508: "crbug.com/35697: The coloured bands show flow seamlessly in the background."
-      LayoutTable {TABLE} at (0,36) size 228x102
-        LayoutTableSection {THEAD} at (0,0) size 228x102
-          LayoutTableRow {TR} at (0,2) size 228x98
-            LayoutTableCell {TH} at (2,50) size 111x2 [r=0 c=0 rs=1 cs=1]
-            LayoutTableCell {TH} at (115,50) size 111x2 [r=0 c=1 rs=1 cs=1]
diff --git a/third_party/WebKit/LayoutTests/fast/table/backgr_fixed-bg-table.html b/third_party/WebKit/LayoutTests/fast/table/backgr_fixed-bg-table.html
deleted file mode 100644
index 7a5e83cd0..0000000
--- a/third_party/WebKit/LayoutTests/fast/table/backgr_fixed-bg-table.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<style>
-.d {width: 109px}
-.d {height: 96px}
-thead{background:url(resources/rainbowh.gif) fixed;}
-</style>
-<p>crbug.com/35697: The coloured bands show flow seamlessly in the background.</p>
-<table>
-  <thead>
-    <tr class="th-row-1">
-      <th class="d"></th>
-      <th class="d"></th>
-    </tr>
-  </thead>
-</table>
-
diff --git a/third_party/WebKit/LayoutTests/gamepad/gamepad-api-expected.txt b/third_party/WebKit/LayoutTests/gamepad/gamepad-api-expected.txt
index ec0fc1ef..586795c1 100644
--- a/third_party/WebKit/LayoutTests/gamepad/gamepad-api-expected.txt
+++ b/third_party/WebKit/LayoutTests/gamepad/gamepad-api-expected.txt
@@ -22,6 +22,8 @@
 PASS gamepad.buttons[0].pressed.__proto__ is Boolean.prototype
 PASS gamepad.buttons[0].value.__proto__ is Number.prototype
 PASS gamepad.mapping.__proto__ is String.prototype
+PASS Object.isFrozen(gamepad.axes) is true
+PASS Object.isFrozen(gamepad.buttons) is true
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/gamepad/gamepad-api.html b/third_party/WebKit/LayoutTests/gamepad/gamepad-api.html
index 43dbb6a..281d327 100644
--- a/third_party/WebKit/LayoutTests/gamepad/gamepad-api.html
+++ b/third_party/WebKit/LayoutTests/gamepad/gamepad-api.html
@@ -34,6 +34,8 @@
         shouldBe("gamepad.buttons[0].pressed.__proto__", "Boolean.prototype");
         shouldBe("gamepad.buttons[0].value.__proto__", "Number.prototype");
         shouldBe("gamepad.mapping.__proto__", "String.prototype");
+        shouldBeTrue("Object.isFrozen(gamepad.axes)");
+        shouldBeTrue("Object.isFrozen(gamepad.buttons)");
     }
     else
     {
diff --git a/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic-expected.txt b/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic-expected.txt
index 39ab31b..a468cbb 100644
--- a/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic-expected.txt
@@ -19,6 +19,8 @@
 PASS event.gamepad.axes[0] is 0.5
 PASS event.gamepad.axes[1] is -1.0
 PASS event.gamepad.axes[2] is 0.333333
+PASS axes[0] is 0.5
+PASS buttons.hasOwnProperty('foo') is false
 Gamepad disconnected
 PASS event.__proto__ is GamepadEvent.prototype
 PASS event.__proto__.__proto__ is Event.prototype
diff --git a/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic.html b/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic.html
index 869f991..0b40773 100644
--- a/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic.html
+++ b/third_party/WebKit/LayoutTests/gamepad/gamepad-events-basic.html
@@ -25,6 +25,14 @@
             shouldBe("event.gamepad.axes[0]", "0.5");
             shouldBe("event.gamepad.axes[1]", "-1.0");
             shouldBe("event.gamepad.axes[2]", "0.333333");
+            // |axes| and |buttons| are FrozenArrays, changing them has no
+            // effect.
+            axes = event.gamepad.axes;
+            axes[0] = 42;
+            shouldBe("axes[0]", "0.5");
+            buttons = event.gamepad.buttons;
+            buttons.foo = "bar";
+            shouldBeFalse("buttons.hasOwnProperty('foo')");
             gamepadController.disconnect(0);
         }
 
diff --git a/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access-expected.txt b/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access-expected.txt
index af354fb..d8530a4a 100644
--- a/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access-expected.txt
+++ b/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access-expected.txt
@@ -20,6 +20,18 @@
 PASS navigator.getGamepads()[0].axes.length is 2
 PASS navigator.getGamepads()[0].axes[0] is 0.5
 PASS navigator.getGamepads()[0].axes[1] is -1.0
+PASS navigator.getGamepads()[0].axes === navigator.getGamepads()[0].axes is true
+PASS navigator.getGamepads()[0].buttons === navigator.getGamepads()[0].buttons is true
+PASS navigator.getGamepads()[0].axes === oldAxes is true
+PASS navigator.getGamepads()[0].buttons === oldButtons is true
+PASS navigator.getGamepads()[0].axes === oldAxes is true
+PASS navigator.getGamepads()[0].buttons === oldButtons is true
+PASS navigator.getGamepads()[0].axes === oldAxes is false
+PASS navigator.getGamepads()[0].buttons === oldButtons is false
+PASS navigator.getGamepads()[0].axes === oldAxes is true
+PASS navigator.getGamepads()[0].buttons === oldButtons is true
+PASS navigator.getGamepads()[0].axes === oldAxes is false
+PASS navigator.getGamepads()[0].buttons === oldButtons is false
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access.html b/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access.html
index d7128cc..36c6b4af 100644
--- a/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access.html
+++ b/third_party/WebKit/LayoutTests/gamepad/gamepad-polling-access.html
@@ -45,6 +45,35 @@
         shouldBe("navigator.getGamepads()[0].axes.length", "2");
         shouldBe("navigator.getGamepads()[0].axes[0]", "0.5");
         shouldBe("navigator.getGamepads()[0].axes[1]", "-1.0");
+
+        // check that accessing the |axes| and |buttons| attributes fetches the
+        // same objects until their values change.
+        shouldBeTrue("navigator.getGamepads()[0].axes === navigator.getGamepads()[0].axes");
+        shouldBeTrue("navigator.getGamepads()[0].buttons === navigator.getGamepads()[0].buttons");
+        oldAxes = navigator.getGamepads()[0].axes;
+        oldButtons = navigator.getGamepads()[0].buttons;
+        // updates with the same values are skipped.
+        gamepadController.setAxisCount(0, 2);
+        gamepadController.setButtonCount(0, 2);
+        shouldBeTrue("navigator.getGamepads()[0].axes === oldAxes");
+        shouldBeTrue("navigator.getGamepads()[0].buttons === oldButtons");
+        gamepadController.setAxisData(0, 0, .5);
+        gamepadController.setButtonData(0, 1, 0);
+        shouldBeTrue("navigator.getGamepads()[0].axes === oldAxes");
+        shouldBeTrue("navigator.getGamepads()[0].buttons === oldButtons");
+        // updates with different values are not skipped.
+        gamepadController.setAxisCount(0, 1);
+        gamepadController.setButtonCount(0, 1);
+        shouldBeFalse("navigator.getGamepads()[0].axes === oldAxes");
+        shouldBeFalse("navigator.getGamepads()[0].buttons === oldButtons");
+        oldAxes = navigator.getGamepads()[0].axes;
+        oldButtons = navigator.getGamepads()[0].buttons;
+        shouldBeTrue("navigator.getGamepads()[0].axes === oldAxes");
+        shouldBeTrue("navigator.getGamepads()[0].buttons === oldButtons");
+        gamepadController.setAxisData(0, 0, .9);
+        gamepadController.setButtonData(0, 0, .3);
+        shouldBeFalse("navigator.getGamepads()[0].axes === oldAxes");
+        shouldBeFalse("navigator.getGamepads()[0].buttons === oldButtons");
     }
     else
     {
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_fixed-bg-table-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_fixed-bg-table-expected.png
deleted file mode 100644
index 2a64b9c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_fixed-bg-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index f1013426..0f1ffde9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png
deleted file mode 100644
index 2a64b9c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index bdaed8e3..413c4cb9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index c7184cb..e5ba809 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index 71f84e7d..53b04934 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index c7184cb..e5ba809 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_fixed-bg-table-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_fixed-bg-table-expected.png
deleted file mode 100644
index b4b0eb0..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_fixed-bg-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index 188fe28d..ab523a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png
deleted file mode 100644
index b4b0eb0..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_fixed-bg-table-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_fixed-bg-table-expected.png
deleted file mode 100644
index de7b12a..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_fixed-bg-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index fdb3af9a..251d2e0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png
deleted file mode 100644
index de7b12a..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/fast/table/backgr_fixed-bg-table-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png b/third_party/WebKit/LayoutTests/platform/win7/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
index 70765b0..c1f4c6c 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/tables/mozilla_expected_failures/marvin/backgr_fixed-bg-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 445ccde..20069410 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -541,6 +541,7 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPILetterAndWordSpacing.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPILineHeight.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPILineHeightStep.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPILogicalWidthOrHeight.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIMargin.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIMarker.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIMaskSourceType.h",
@@ -600,7 +601,6 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitFontSizeDelta.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitHighlight.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitLineClamp.h",
-    "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitLogicalWidthOrHeight.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitMargin.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitMaskComposite.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIWebkitMaskRepeat.h",
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn
index 850f2460..39a86c592 100644
--- a/third_party/WebKit/Source/core/css/BUILD.gn
+++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -439,6 +439,7 @@
     "properties/CSSPropertyAPILetterAndWordSpacing.cpp",
     "properties/CSSPropertyAPILineHeight.cpp",
     "properties/CSSPropertyAPILineHeightStep.cpp",
+    "properties/CSSPropertyAPILogicalWidthOrHeight.cpp",
     "properties/CSSPropertyAPIMargin.cpp",
     "properties/CSSPropertyAPIMarker.cpp",
     "properties/CSSPropertyAPIMaskSourceType.cpp",
@@ -498,7 +499,6 @@
     "properties/CSSPropertyAPIWebkitFontSizeDelta.cpp",
     "properties/CSSPropertyAPIWebkitHighlight.cpp",
     "properties/CSSPropertyAPIWebkitLineClamp.cpp",
-    "properties/CSSPropertyAPIWebkitLogicalWidthOrHeight.cpp",
     "properties/CSSPropertyAPIWebkitMargin.cpp",
     "properties/CSSPropertyAPIWebkitMaskComposite.cpp",
     "properties/CSSPropertyAPIWebkitMaskRepeat.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 02aa490..f8578fea 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -3491,18 +3491,26 @@
     // CSS logical props
     {
       name: "inline-size",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
+      api_methods: ["parseSingleValue"],
       direction_aware: true,
     },
     {
       name: "block-size",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
+      api_methods: ["parseSingleValue"],
       direction_aware: true,
     },
     {
       name: "min-inline-size",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
+      api_methods: ["parseSingleValue"],
       direction_aware: true,
     },
     {
       name: "min-block-size",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
+      api_methods: ["parseSingleValue"],
       direction_aware: true,
     },
     {
@@ -3634,22 +3642,22 @@
     },
     {
       name: "-webkit-logical-width",
-      api_class: "CSSPropertyAPIWebkitLogicalWidthOrHeight",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
       direction_aware: true,
     },
     {
       name: "-webkit-logical-height",
-      api_class: "CSSPropertyAPIWebkitLogicalWidthOrHeight",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
       direction_aware: true,
     },
     {
       name: "-webkit-min-logical-width",
-      api_class: "CSSPropertyAPIWebkitLogicalWidthOrHeight",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
       direction_aware: true,
     },
     {
       name: "-webkit-min-logical-height",
-      api_class: "CSSPropertyAPIWebkitLogicalWidthOrHeight",
+      api_class: "CSSPropertyAPILogicalWidthOrHeight",
       direction_aware: true,
     },
     {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 1bdd8c9..86433e1 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -658,15 +658,6 @@
     case CSSPropertyHeight:
       return CSSPropertyLengthUtils::ConsumeWidthOrHeight(
           range_, *context_, UnitlessQuirk::kAllow);
-    case CSSPropertyInlineSize:
-    case CSSPropertyBlockSize:
-    case CSSPropertyMinInlineSize:
-    case CSSPropertyMinBlockSize:
-    case CSSPropertyWebkitMinLogicalWidth:
-    case CSSPropertyWebkitMinLogicalHeight:
-    case CSSPropertyWebkitLogicalWidth:
-    case CSSPropertyWebkitLogicalHeight:
-      return CSSPropertyLengthUtils::ConsumeWidthOrHeight(range_, *context_);
     case CSSPropertyTextDecoration:
       DCHECK(!RuntimeEnabledFeatures::CSS3TextDecorationsEnabled());
       return CSSPropertyTextDecorationLineUtils::ConsumeTextDecorationLine(
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILogicalWidthOrHeight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILogicalWidthOrHeight.cpp
new file mode 100644
index 0000000..1c703f1
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILogicalWidthOrHeight.cpp
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/css/properties/CSSPropertyAPILogicalWidthOrHeight.h"
+
+#include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/CSSPropertyLengthUtils.h"
+
+namespace blink {
+class CSSParserLocalContext;
+
+const CSSValue* CSSPropertyAPILogicalWidthOrHeight::parseSingleValue(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&) {
+  return CSSPropertyLengthUtils::ConsumeWidthOrHeight(range, context);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLogicalWidthOrHeight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLogicalWidthOrHeight.cpp
deleted file mode 100644
index 5a310e7..0000000
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLogicalWidthOrHeight.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "core/css/properties/CSSPropertyAPIWebkitLogicalWidthOrHeight.h"
-
-namespace blink {}  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/AXObjectCache.cpp b/third_party/WebKit/Source/core/dom/AXObjectCache.cpp
index 08def9f..47c3e00 100644
--- a/third_party/WebKit/Source/core/dom/AXObjectCache.cpp
+++ b/third_party/WebKit/Source/core/dom/AXObjectCache.cpp
@@ -217,6 +217,4 @@
 STATIC_ASSERT_ENUM(kWebAXEventTextRemoved, AXObjectCache::kAXTextRemoved);
 STATIC_ASSERT_ENUM(kWebAXEventValueChanged, AXObjectCache::kAXValueChanged);
 
-#undef STATIC_ASSERT_ENUM
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 2bf67fc..aaac743 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -189,14 +189,6 @@
 
 const int kTouchPointPadding = 32;
 
-#define EXPECT_RECT_EQ(expected, actual)           \
-  do {                                             \
-    EXPECT_EQ(expected.X(), actual.X());           \
-    EXPECT_EQ(expected.Y(), actual.Y());           \
-    EXPECT_EQ(expected.Width(), actual.Width());   \
-    EXPECT_EQ(expected.Height(), actual.Height()); \
-  } while (false)
-
 class WebFrameTest : public ::testing::Test {
  protected:
   WebFrameTest()
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
index dc918c4..090a9064 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
@@ -915,15 +915,6 @@
   EXPECT_FALSE(plugin_container_impl->IsRectTopmost(rect));
 }
 
-#define EXPECT_RECT_EQ(expected, actual)                \
-  do {                                                  \
-    const IntRect& actual_rect = actual;                \
-    EXPECT_EQ(expected.X(), actual_rect.X());           \
-    EXPECT_EQ(expected.Y(), actual_rect.Y());           \
-    EXPECT_EQ(expected.Width(), actual_rect.Width());   \
-    EXPECT_EQ(expected.Height(), actual_rect.Height()); \
-  } while (false)
-
 TEST_F(WebPluginContainerTest, ClippedRectsForIframedElement) {
   RegisterMockedURL("plugin_container.html");
   RegisterMockedURL("plugin_containing_page.html");
diff --git a/third_party/WebKit/Source/core/frame/FrameTestHelpers.h b/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
index 5654904..024b9b8 100644
--- a/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
+++ b/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
@@ -97,6 +97,15 @@
     EXPECT_FLOAT_EQ((expected).Height(), (actual).Height()); \
   } while (false)
 
+#define EXPECT_RECT_EQ(expected, actual)                \
+  do {                                                  \
+    const IntRect& actual_rect = actual;                \
+    EXPECT_EQ(expected.X(), actual_rect.X());           \
+    EXPECT_EQ(expected.Y(), actual_rect.Y());           \
+    EXPECT_EQ(expected.Width(), actual_rect.Width());   \
+    EXPECT_EQ(expected.Height(), actual_rect.Height()); \
+  } while (false)
+
 namespace blink {
 
 class WebFrame;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
index a41a748..30848c5 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
@@ -524,12 +524,13 @@
 }
 
 // 2nd Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script
-void HTMLParserScriptRunner::RequestParsingBlockingScript(Element* element) {
+void HTMLParserScriptRunner::RequestParsingBlockingScript(
+    ScriptLoader* script_loader) {
   // "The element is the pending parsing-blocking script of the Document of
   //  the parser that created the element.
   //  (There can only be one such script per Document at a time.)"
   CHECK(!ParserBlockingScript());
-  parser_blocking_script_ = RequestPendingScript(element);
+  parser_blocking_script_ = script_loader->CreatePendingScript();
   if (!ParserBlockingScript())
     return;
 
@@ -546,8 +547,9 @@
 }
 
 // 1st Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script
-void HTMLParserScriptRunner::RequestDeferredScript(Element* element) {
-  PendingScript* pending_script = RequestPendingScript(element);
+void HTMLParserScriptRunner::RequestDeferredScript(
+    ScriptLoader* script_loader) {
+  PendingScript* pending_script = script_loader->CreatePendingScript();
   if (!pending_script)
     return;
 
@@ -565,13 +567,6 @@
       TraceWrapperMember<PendingScript>(this, pending_script));
 }
 
-PendingScript* HTMLParserScriptRunner::RequestPendingScript(
-    Element* element) const {
-  ScriptElementBase* script_element =
-      ScriptElementBase::FromElementIfPossible(element);
-  return script_element->Loader()->CreatePendingScript();
-}
-
 // The initial steps for 'An end tag whose tag name is "script"'
 // https://html.spec.whatwg.org/#scriptEndTag
 void HTMLParserScriptRunner::ProcessScriptElementInternal(
@@ -616,7 +611,7 @@
 
     if (script_loader->WillExecuteWhenDocumentFinishedParsing()) {
       // 1st Clause of Step 23.
-      RequestDeferredScript(script);
+      RequestDeferredScript(script_loader);
     } else if (script_loader->ReadyToBeParserExecuted()) {
       // 5th Clause of Step 23.
       // "If ... it's an HTML parser
@@ -643,7 +638,7 @@
       }
     } else {
       // 2nd Clause of Step 23.
-      RequestParsingBlockingScript(script);
+      RequestParsingBlockingScript(script_loader);
     }
 
     // "Decrement the parser's script nesting level by one.
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h
index 52b8f39b..bae24093 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.h
@@ -42,6 +42,7 @@
 class Document;
 class Element;
 class HTMLParserScriptRunnerHost;
+class ScriptLoader;
 
 // HTMLParserScriptRunner is responsible for for arranging the execution of
 // script elements inserted by the parser, according to the rules for
@@ -111,9 +112,8 @@
                                             ScriptStreamer::Type);
   void ExecuteParsingBlockingScripts();
 
-  void RequestParsingBlockingScript(Element*);
-  void RequestDeferredScript(Element*);
-  PendingScript* RequestPendingScript(Element*) const;
+  void RequestParsingBlockingScript(ScriptLoader*);
+  void RequestDeferredScript(ScriptLoader*);
 
   // Processes the provided script element, but does not execute any
   // parsing-blocking scripts that may remain after execution.
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
index b3c3607..d8ced6c 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -226,7 +226,7 @@
   }
 
   ProcessCaptureAndPositionOfPointerEvent(dummy_pointer_event, entered_node,
-                                          canvas_region_id, mouse_event, true);
+                                          canvas_region_id, &mouse_event);
 }
 
 void PointerEventManager::SendBoundaryEvents(EventTarget* exited_target,
@@ -540,7 +540,7 @@
   }
 
   EventTarget* pointer_event_target = ProcessCaptureAndPositionOfPointerEvent(
-      pointer_event, target, canvas_region_id, mouse_event, true);
+      pointer_event, target, canvas_region_id, &mouse_event);
 
   EventTarget* effective_target = GetEffectiveTargetForPointerEvent(
       pointer_event_target, pointer_event->pointerId());
@@ -631,8 +631,7 @@
     PointerEvent* pointer_event,
     EventTarget* hit_test_target,
     const String& canvas_region_id,
-    const WebMouseEvent& mouse_event,
-    bool send_mouse_event) {
+    const WebMouseEvent* mouse_event) {
   ProcessPendingPointerCapture(pointer_event);
 
   PointerCapturingMap::const_iterator it =
@@ -642,10 +641,10 @@
     hit_test_target = pointercapture_target;
 
   SetNodeUnderPointer(pointer_event, hit_test_target);
-  if (send_mouse_event) {
+  if (mouse_event) {
     mouse_event_manager_->SetNodeUnderMouse(
         hit_test_target ? hit_test_target->ToNode() : nullptr, canvas_region_id,
-        mouse_event);
+        *mouse_event);
   }
   return hit_test_target;
 }
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.h b/third_party/WebKit/Source/core/input/PointerEventManager.h
index a8ae050c..28a112de 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.h
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.h
@@ -184,8 +184,7 @@
       PointerEvent*,
       EventTarget* hit_test_target,
       const String& canvas_region_id = String(),
-      const WebMouseEvent& = WebMouseEvent(),
-      bool send_mouse_event = false);
+      const WebMouseEvent* = nullptr);
 
   void RemoveTargetFromPointerCapturingMapping(PointerCapturingMap&,
                                                const EventTarget*);
diff --git a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
index 9081f7a7..fdf9b07a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
@@ -776,8 +776,8 @@
   if (!frame)
     return;
 
-  VisibleSelection selection =
-      frame->Selection().ComputeVisibleSelectionInDOMTreeDeprecated();
+  const VisibleSelection& selection =
+      frame->Selection().ComputeVisibleSelectionInDOMTree();
   if (selection.IsCaret()) {
     ts << "caret: position " << selection.Start().ComputeEditingOffset()
        << " of " << NodePosition(selection.Start().AnchorNode());
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
index e796813..21d90f67 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
@@ -4,6 +4,7 @@
 
 #include "core/layout/compositing/CompositedLayerMapping.h"
 
+#include "core/frame/FrameTestHelpers.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/layout/LayoutBoxModelObject.h"
 #include "core/layout/LayoutTestHelper.h"
@@ -63,15 +64,6 @@
   void TearDown() override { RenderingTest::TearDown(); }
 };
 
-#define EXPECT_RECT_EQ(expected, actual)                \
-  do {                                                  \
-    const IntRect& actual_rect = actual;                \
-    EXPECT_EQ(expected.X(), actual_rect.X());           \
-    EXPECT_EQ(expected.Y(), actual_rect.Y());           \
-    EXPECT_EQ(expected.Width(), actual_rect.Width());   \
-    EXPECT_EQ(expected.Height(), actual_rect.Height()); \
-  } while (false)
-
 INSTANTIATE_TEST_CASE_P(All, CompositedLayerMappingTest, ::testing::Bool());
 
 TEST_P(CompositedLayerMappingTest, SubpixelAccumulationChange) {
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index 043ff16..d50de163 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -518,7 +518,6 @@
     }
   } else {
     SetHasNonLocalGeometry();
-    offset_in_background_ = LayoutPoint();
     positioning_area = FixedAttachmentPositioningArea(box_, container, flags);
     SetDestRect(positioning_area);
   }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 3ddd4de..fe0ac34 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -1589,9 +1589,11 @@
 void PaintLayer::UpdateScrollableArea() {
   if (RequiresScrollableArea() && !scrollable_area_) {
     scrollable_area_ = PaintLayerScrollableArea::Create(*this);
+    Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
   } else if (!RequiresScrollableArea() && scrollable_area_) {
     scrollable_area_->Dispose();
     scrollable_area_.Clear();
+    Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp
index 9291afe8..6e23fb7 100644
--- a/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp
@@ -440,11 +440,9 @@
 
   pending_script->StopWatchingForLoad();
 
-  Element* e = script_element_;
+  ScriptLoader* script_loader = script_element_->Loader();
   script_element_ = nullptr;
 
-  ScriptLoader* script_loader =
-      ScriptElementBase::FromElementIfPossible(e)->Loader();
   DCHECK(script_loader);
   CHECK_EQ(script_loader->GetScriptType(), ScriptType::kClassic);
 
@@ -1131,7 +1129,7 @@
       // https://html.spec.whatwg.org/#prepare-a-script
       pending_script_ = script_loader->CreatePendingScript();
       pending_script_->MarkParserBlockingLoadStartTime();
-      script_element_ = element;
+      script_element_ = script_element_base;
       pending_script_->WatchForLoad(this);
       // pending_script_ will be null if script was already ready.
       if (pending_script_)
diff --git a/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.h b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.h
index 15e5f61..428224b 100644
--- a/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.h
+++ b/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.h
@@ -49,6 +49,7 @@
 class DocumentFragment;
 class Element;
 class LocalFrameView;
+class ScriptElementBase;
 class Text;
 
 class XMLParserContext : public RefCounted<XMLParserContext> {
@@ -209,7 +210,7 @@
   XMLErrors xml_errors_;
 
   Member<PendingScript> pending_script_;
-  Member<Element> script_element_;
+  Member<ScriptElementBase> script_element_;
   TextPosition script_start_position_;
 
   bool parsing_fragment_;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp b/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp
index fc9f3c4..600264d 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXEnums.cpp
@@ -229,5 +229,4 @@
                    AXObjectAttribute::kAriaDetails);
 STATIC_ASSERT_ENUM(WebAXObjectVectorAttribute::kAriaFlowTo,
                    AXObjectVectorAttribute::kAriaFlowTo);
-#undef STATIC_ASSERT_ENUM
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/gamepad/Gamepad.cpp b/third_party/WebKit/Source/modules/gamepad/Gamepad.cpp
index 813a93b..5b1cfc5 100644
--- a/third_party/WebKit/Source/modules/gamepad/Gamepad.cpp
+++ b/third_party/WebKit/Source/modules/gamepad/Gamepad.cpp
@@ -25,30 +25,60 @@
 
 #include "modules/gamepad/Gamepad.h"
 
+#include <algorithm>
+
 namespace blink {
 
-Gamepad::Gamepad() : index_(0), timestamp_(0), display_id_(0) {}
+Gamepad::Gamepad()
+    : index_(0),
+      timestamp_(0),
+      display_id_(0),
+      is_axis_data_dirty_(true),
+      is_button_data_dirty_(true) {}
 
 Gamepad::~Gamepad() {}
 
+const Gamepad::DoubleVector& Gamepad::axes() {
+  is_axis_data_dirty_ = false;
+  return axes_;
+}
+
 void Gamepad::SetAxes(unsigned count, const double* data) {
+  bool skip_update =
+      axes_.size() == count && std::equal(data, data + count, axes_.begin());
+  if (skip_update)
+    return;
+
   axes_.resize(count);
   if (count)
     std::copy(data, data + count, axes_.begin());
+  is_axis_data_dirty_ = true;
+}
+
+const GamepadButtonVector& Gamepad::buttons() {
+  is_button_data_dirty_ = false;
+  return buttons_;
 }
 
 void Gamepad::SetButtons(unsigned count, const device::GamepadButton* data) {
+  bool skip_update =
+      buttons_.size() == count &&
+      std::equal(data, data + count, buttons_.begin(),
+                 [](const device::GamepadButton& device_gamepad_button,
+                    const Member<GamepadButton>& gamepad_button) {
+                   return gamepad_button->IsEqual(device_gamepad_button);
+                 });
+  if (skip_update)
+    return;
+
   if (buttons_.size() != count) {
     buttons_.resize(count);
     for (unsigned i = 0; i < count; ++i)
       buttons_[i] = GamepadButton::Create();
   }
-  for (unsigned i = 0; i < count; ++i) {
-    buttons_[i]->SetValue(data[i].value);
-    buttons_[i]->SetPressed(data[i].pressed);
-    buttons_[i]->SetTouched(data[i].touched || data[i].pressed ||
-                            (data[i].value > 0.0f));
-  }
+  for (unsigned i = 0; i < count; ++i)
+    buttons_[i]->UpdateValuesFrom(data[i]);
+  is_button_data_dirty_ = true;
 }
 
 void Gamepad::SetPose(const device::GamepadPose& pose) {
diff --git a/third_party/WebKit/Source/modules/gamepad/Gamepad.h b/third_party/WebKit/Source/modules/gamepad/Gamepad.h
index b168134..d2199e8 100644
--- a/third_party/WebKit/Source/modules/gamepad/Gamepad.h
+++ b/third_party/WebKit/Source/modules/gamepad/Gamepad.h
@@ -61,11 +61,13 @@
   const String& mapping() const { return mapping_; }
   void SetMapping(const String& val) { mapping_ = val; }
 
-  const DoubleVector& axes() const { return axes_; }
+  const DoubleVector& axes();
   void SetAxes(unsigned count, const double* data);
+  bool isAxisDataDirty() const { return is_axis_data_dirty_; }
 
-  const GamepadButtonVector& buttons() const { return buttons_; }
+  const GamepadButtonVector& buttons();
   void SetButtons(unsigned count, const device::GamepadButton* data);
+  bool isButtonDataDirty() const { return is_button_data_dirty_; }
 
   GamepadPose* pose() const { return pose_; }
   void SetPose(const device::GamepadPose&);
@@ -91,6 +93,8 @@
   Member<GamepadPose> pose_;
   String hand_;
   unsigned display_id_;
+  bool is_axis_data_dirty_;
+  bool is_button_data_dirty_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/gamepad/Gamepad.idl b/third_party/WebKit/Source/modules/gamepad/Gamepad.idl
index 927bb17e..73e64de1 100644
--- a/third_party/WebKit/Source/modules/gamepad/Gamepad.idl
+++ b/third_party/WebKit/Source/modules/gamepad/Gamepad.idl
@@ -36,9 +36,8 @@
     readonly attribute boolean connected;
     readonly attribute unsigned long long timestamp;
     readonly attribute DOMString mapping;
-    // https://github.com/w3c/gamepad/issues/28
-    [MeasureAs=GamepadAxes] readonly attribute double[] axes;
-    [MeasureAs=GamepadButtons] readonly attribute GamepadButton[] buttons;
+    [CachedAttribute=isAxisDataDirty, MeasureAs=GamepadAxes] readonly attribute FrozenArray<double> axes;
+    [CachedAttribute=isButtonDataDirty, MeasureAs=GamepadButtons] readonly attribute FrozenArray<GamepadButton> buttons;
 
     [OriginTrialEnabled=GamepadExtensions, MeasureAs=GamepadPose] readonly attribute GamepadPose? pose;
     [OriginTrialEnabled=GamepadExtensions, MeasureAs=GamepadHand] readonly attribute GamepadHand hand;
diff --git a/third_party/WebKit/Source/modules/gamepad/GamepadButton.cpp b/third_party/WebKit/Source/modules/gamepad/GamepadButton.cpp
index 37387899..9463a283 100644
--- a/third_party/WebKit/Source/modules/gamepad/GamepadButton.cpp
+++ b/third_party/WebKit/Source/modules/gamepad/GamepadButton.cpp
@@ -12,4 +12,18 @@
 
 GamepadButton::GamepadButton() : value_(0.), pressed_(false), touched_(false) {}
 
+bool GamepadButton::IsEqual(const device::GamepadButton& device_button) const {
+  return value_ == device_button.value && pressed_ == device_button.pressed &&
+         touched_ == (device_button.touched || device_button.pressed ||
+                      (device_button.value > 0.0f));
+}
+
+void GamepadButton::UpdateValuesFrom(
+    const device::GamepadButton& device_button) {
+  value_ = device_button.value;
+  pressed_ = device_button.pressed;
+  touched_ = (device_button.touched || device_button.pressed ||
+              (device_button.value > 0.0f));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/gamepad/GamepadButton.h b/third_party/WebKit/Source/modules/gamepad/GamepadButton.h
index 05d07e21..4e53044 100644
--- a/third_party/WebKit/Source/modules/gamepad/GamepadButton.h
+++ b/third_party/WebKit/Source/modules/gamepad/GamepadButton.h
@@ -5,6 +5,7 @@
 #ifndef GamepadButton_h
 #define GamepadButton_h
 
+#include "device/gamepad/public/cpp/gamepad.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Vector.h"
@@ -27,6 +28,9 @@
   bool touched() const { return touched_; }
   void SetTouched(bool val) { touched_ = val; }
 
+  bool IsEqual(const device::GamepadButton&) const;
+  void UpdateValuesFrom(const device::GamepadButton&);
+
   DEFINE_INLINE_TRACE() {}
 
  private:
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index 2417cf7..7ded9f48 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -45,7 +45,7 @@
 // which main thread compositing can be considered fast.
 const double kFastCompositingIdleTimeThreshold = .2;
 constexpr base::TimeDelta kThreadLoadTrackerReportingInterval =
-    base::TimeDelta::FromMinutes(1);
+    base::TimeDelta::FromSeconds(1);
 // We do not throttle anything while audio is played and shortly after that.
 constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed =
     base::TimeDelta::FromSeconds(5);
@@ -165,6 +165,7 @@
 
 #define TASK_DURATION_METRIC_NAME "RendererScheduler.TaskDurationPerQueueType2"
 #define TASK_COUNT_METRIC_NAME "RendererScheduler.TaskCountPerQueueType"
+#define MAIN_THREAD_LOAD_METRIC_NAME "RendererScheduler.RendererMainThreadLoad4"
 
 RendererSchedulerImpl::MainThreadOnly::MainThreadOnly(
     RendererSchedulerImpl* renderer_scheduler_impl,
@@ -2150,8 +2151,7 @@
   int load_percentage = static_cast<int>(load * 100);
   DCHECK_LE(load_percentage, 100);
 
-  UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.RendererMainThreadLoad3",
-                           load_percentage);
+  UMA_HISTOGRAM_PERCENTAGE(MAIN_THREAD_LOAD_METRIC_NAME, load_percentage);
   TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
                  "RendererScheduler.RendererMainThreadLoad", load_percentage);
 }
@@ -2162,14 +2162,14 @@
   int load_percentage = static_cast<int>(load * 100);
   DCHECK_LE(load_percentage, 100);
 
-  UMA_HISTOGRAM_PERCENTAGE(
-      "RendererScheduler.RendererMainThreadLoad3.Foreground", load_percentage);
+  UMA_HISTOGRAM_PERCENTAGE(MAIN_THREAD_LOAD_METRIC_NAME ".Foreground",
+                           load_percentage);
 
   if (time - main_thread_only().background_status_changed_at >
       base::TimeDelta::FromMinutes(1)) {
-    UMA_HISTOGRAM_PERCENTAGE(
-        "RendererScheduler.RendererMainThreadLoad3.Foreground.AfterFirstMinute",
-        load_percentage);
+    UMA_HISTOGRAM_PERCENTAGE(MAIN_THREAD_LOAD_METRIC_NAME
+                             ".Foreground.AfterFirstMinute",
+                             load_percentage);
   }
 
   TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
@@ -2183,14 +2183,14 @@
   int load_percentage = static_cast<int>(load * 100);
   DCHECK_LE(load_percentage, 100);
 
-  UMA_HISTOGRAM_PERCENTAGE(
-      "RendererScheduler.RendererMainThreadLoad3.Background", load_percentage);
+  UMA_HISTOGRAM_PERCENTAGE(MAIN_THREAD_LOAD_METRIC_NAME ".Background",
+                           load_percentage);
 
   if (time - main_thread_only().background_status_changed_at >
       base::TimeDelta::FromMinutes(1)) {
-    UMA_HISTOGRAM_PERCENTAGE(
-        "RendererScheduler.RendererMainThreadLoad3.Background.AfterFirstMinute",
-        load_percentage);
+    UMA_HISTOGRAM_PERCENTAGE(MAIN_THREAD_LOAD_METRIC_NAME
+                             ".Background.AfterFirstMinute",
+                             load_percentage);
   }
 
   TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"),
diff --git a/third_party/libxslt/README.chromium b/third_party/libxslt/README.chromium
index 7a15a43..46254044 100644
--- a/third_party/libxslt/README.chromium
+++ b/third_party/libxslt/README.chromium
@@ -3,7 +3,7 @@
 Version: ac341cbd792ee572941cc9a66e73800219a1a386
 Security Critical: yes
 License: MIT
-License File: Copyright
+License File: src/Copyright
 
 Description:
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 17cdf19..dd73292d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -14917,16 +14917,6 @@
   <summary>Time taken to create a single download in the history DB.</summary>
 </histogram>
 
-<histogram name="Download.Database.IsAvailable" enum="BooleanAvailable">
-  <owner>xingliu@chromium.org</owner>
-  <summary>
-    Records whether the download database is available when database startup
-    completes, before starting any pending downloads.  If the database is
-    available, it will provide the next download id. Or no download history will
-    be persisted.
-  </summary>
-</histogram>
-
 <histogram name="Download.Database.QueryDownloadDuration" units="ms">
   <owner>asanka@chromium.org</owner>
   <summary>Time taken to query all downloads from history DB.</summary>
@@ -63344,6 +63334,24 @@
 </histogram>
 
 <histogram name="RendererScheduler.RendererMainThreadLoad3" units="%">
+  <obsolete>
+    This metric still used 1-minute reporting chunks. Replaced with
+    RendererMainThreadLoad4 as of July 2017.
+  </obsolete>
+  <owner>altimin@chromium.org</owner>
+  <summary>
+    Renderer main thread load (percentage of time spent in tasks), reported in
+    one minute chunks.
+
+    See http://bit.ly/chromium-renderer-main-thread-load-metric for details.
+
+    This metric is emitted when the renderer main thread task is completed or
+    renderer is backgrounded or foregrounded, at most once per second per
+    renderer amortized.
+  </summary>
+</histogram>
+
+<histogram name="RendererScheduler.RendererMainThreadLoad4" units="%">
   <owner>altimin@chromium.org</owner>
   <summary>
     Renderer main thread load (percentage of time spent in tasks), reported in
@@ -98075,7 +98083,7 @@
       label="Main thread load when the renderer is foregrounded for longer
              than one minute. Most of loading tasks are expected to complete
              by then."/>
-  <affected-histogram name="RendererScheduler.RendererMainThreadLoad3"/>
+  <affected-histogram name="RendererScheduler.RendererMainThreadLoad4"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="RendererScheduler.TaskCountPerTaskLength"
diff --git a/tools/perf/convert_legacy_wpr_archive b/tools/perf/convert_legacy_wpr_archive
index a36dd67..31c96fd5 100755
--- a/tools/perf/convert_legacy_wpr_archive
+++ b/tools/perf/convert_legacy_wpr_archive
@@ -95,7 +95,10 @@
         count += 1
     print "successfully upload %d wprgo files in %s to buckets: %s\n" % (count,
         page_sets_json_file, bucket)
-    print "remember to run \"git add *.wprgo.sha1\" to include them in your CL\n"
+    print ('Also run \"git add *.wprgo.sha1\" to include them in your CL? '
+           '(Press Enter to continue or ctrl+C to skip this step)\n')
+    raw_input()
+    subprocess.check_call(['git', 'add', '*.wprgo.sha1'])
 
 def GetStorySet(benchmark):
   # Create a dummy options object which hold default values that are expected
diff --git a/tools/perf/page_sets/data/dromaeo.domcoreattr.json b/tools/perf/page_sets/data/dromaeo.domcoreattr.json
index ea39340..83a021b2 100644
--- a/tools/perf/page_sets/data/dromaeo.domcoreattr.json
+++ b/tools/perf/page_sets/data/dromaeo.domcoreattr.json
@@ -1,7 +1,7 @@
 {
     "archives": {
         "http://dromaeo.com?dom-attr": {
-            "DEFAULT": "dromaeo.domcoreattr_000.wpr"
+            "DEFAULT": "dromaeo.domcoreattr_000.wprgo"
         }
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/dromaeo.domcoreattr_000.wpr.sha1 b/tools/perf/page_sets/data/dromaeo.domcoreattr_000.wpr.sha1
deleted file mode 100644
index 753dca4..0000000
--- a/tools/perf/page_sets/data/dromaeo.domcoreattr_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0580ba037627ec80107c3995fe8c1ef98a22b7c6
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcoreattr_000.wprgo.sha1 b/tools/perf/page_sets/data/dromaeo.domcoreattr_000.wprgo.sha1
new file mode 100644
index 0000000..f591f73
--- /dev/null
+++ b/tools/perf/page_sets/data/dromaeo.domcoreattr_000.wprgo.sha1
@@ -0,0 +1 @@
+9239635b2df78af7b7f990a314993371671fa129
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcoremodify.json b/tools/perf/page_sets/data/dromaeo.domcoremodify.json
index dcc3f1e..0241f81 100644
--- a/tools/perf/page_sets/data/dromaeo.domcoremodify.json
+++ b/tools/perf/page_sets/data/dromaeo.domcoremodify.json
@@ -1,7 +1,7 @@
 {
     "archives": {
         "http://dromaeo.com?dom-modify": {
-            "DEFAULT": "dromaeo.domcoremodify_000.wpr"
+            "DEFAULT": "dromaeo.domcoremodify_000.wprgo"
         }
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/dromaeo.domcoremodify_000.wpr.sha1 b/tools/perf/page_sets/data/dromaeo.domcoremodify_000.wpr.sha1
deleted file mode 100644
index 62cabb9..0000000
--- a/tools/perf/page_sets/data/dromaeo.domcoremodify_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5f941f51212286658b921928112af6fbed889d5a
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcoremodify_000.wprgo.sha1 b/tools/perf/page_sets/data/dromaeo.domcoremodify_000.wprgo.sha1
new file mode 100644
index 0000000..61f1f37d
--- /dev/null
+++ b/tools/perf/page_sets/data/dromaeo.domcoremodify_000.wprgo.sha1
@@ -0,0 +1 @@
+b57d7cb34cb0a95e96c51a294fc0ff62836b12f9
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcorequery.json b/tools/perf/page_sets/data/dromaeo.domcorequery.json
index 6cb065e6..04d2b974 100644
--- a/tools/perf/page_sets/data/dromaeo.domcorequery.json
+++ b/tools/perf/page_sets/data/dromaeo.domcorequery.json
@@ -1,7 +1,7 @@
 {
     "archives": {
         "http://dromaeo.com?dom-query": {
-            "DEFAULT": "dromaeo.domcorequery_000.wpr"
+            "DEFAULT": "dromaeo.domcorequery_000.wprgo"
         }
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/dromaeo.domcorequery_000.wpr.sha1 b/tools/perf/page_sets/data/dromaeo.domcorequery_000.wpr.sha1
deleted file mode 100644
index ae3c1e0..0000000
--- a/tools/perf/page_sets/data/dromaeo.domcorequery_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-eea5aabc93c4aa554b1340dc685b65a6f97a234a
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcorequery_000.wprgo.sha1 b/tools/perf/page_sets/data/dromaeo.domcorequery_000.wprgo.sha1
new file mode 100644
index 0000000..e00bb3b
--- /dev/null
+++ b/tools/perf/page_sets/data/dromaeo.domcorequery_000.wprgo.sha1
@@ -0,0 +1 @@
+43090871af82aff38fcfa71e39c13ce0691f6fc7
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcoretraverse.json b/tools/perf/page_sets/data/dromaeo.domcoretraverse.json
index 532e948..616bb8b 100644
--- a/tools/perf/page_sets/data/dromaeo.domcoretraverse.json
+++ b/tools/perf/page_sets/data/dromaeo.domcoretraverse.json
@@ -1,7 +1,7 @@
 {
     "archives": {
         "http://dromaeo.com?dom-traverse": {
-            "DEFAULT": "dromaeo.domcoretraverse_000.wpr"
+            "DEFAULT": "dromaeo.domcoretraverse_000.wprgo"
         }
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/dromaeo.domcoretraverse_000.wpr.sha1 b/tools/perf/page_sets/data/dromaeo.domcoretraverse_000.wpr.sha1
deleted file mode 100644
index f872fa3..0000000
--- a/tools/perf/page_sets/data/dromaeo.domcoretraverse_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-160f6c326f172d89eeabf88ada5129f36c2230b1
\ No newline at end of file
diff --git a/tools/perf/page_sets/data/dromaeo.domcoretraverse_000.wprgo.sha1 b/tools/perf/page_sets/data/dromaeo.domcoretraverse_000.wprgo.sha1
new file mode 100644
index 0000000..d769032
--- /dev/null
+++ b/tools/perf/page_sets/data/dromaeo.domcoretraverse_000.wprgo.sha1
@@ -0,0 +1 @@
+dbd4dd2d6b354a9a1f689d58df32200e9d294821
\ No newline at end of file
diff --git a/ui/aura/window_tree_host_mac.h b/ui/aura/window_tree_host_mac.h
index 7ae5efd..eab989c 100644
--- a/ui/aura/window_tree_host_mac.h
+++ b/ui/aura/window_tree_host_mac.h
@@ -36,7 +36,6 @@
   void SetCapture() override;
   void ReleaseCapture() override;
   bool ConfineCursorToRootWindow() override;
-  void UnConfineCursor() override;
   void SetCursorNative(gfx::NativeCursor cursor_type) override;
   void MoveCursorToNative(const gfx::Point& location) override;
   void OnCursorVisibilityChangedNative(bool show) override;
diff --git a/ui/aura/window_tree_host_mac.mm b/ui/aura/window_tree_host_mac.mm
index c6748a6..69799d0 100644
--- a/ui/aura/window_tree_host_mac.mm
+++ b/ui/aura/window_tree_host_mac.mm
@@ -77,10 +77,6 @@
   return false;
 }
 
-void WindowTreeHostMac::UnConfineCursor() {
-  NOTIMPLEMENTED();
-}
-
 void WindowTreeHostMac::SetCursorNative(gfx::NativeCursor cursor_type) {
   NOTIMPLEMENTED();
 }
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 5fdd15f9..951c062 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -379,6 +379,7 @@
     sources += [
       "clipboard/clipboard_fuchsia.cc",
       "clipboard/clipboard_fuchsia.h",
+      "idle/idle_fuchsia.cc",
       "resource/resource_bundle_fuchsia.cc",
     ]
   }
@@ -645,6 +646,10 @@
   if (is_android || is_ios) {
     sources -= [ "device_form_factor_desktop.cc" ]
   }
+
+  if (is_fuchsia) {
+    sources += [ "cursor/cursor_loader_fuchsia.cc" ]
+  }
 }
 
 static_library("test_support") {
diff --git a/ui/base/cursor/cursor_loader.h b/ui/base/cursor/cursor_loader.h
index fca5e7d..527b1472 100644
--- a/ui/base/cursor/cursor_loader.h
+++ b/ui/base/cursor/cursor_loader.h
@@ -8,6 +8,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "ui/base/cursor/cursor_type.h"
 #include "ui/base/ui_base_export.h"
 #include "ui/display/display.h"
 #include "ui/gfx/geometry/point.h"
diff --git a/ui/base/cursor/cursor_loader_fuchsia.cc b/ui/base/cursor/cursor_loader_fuchsia.cc
new file mode 100644
index 0000000..a7e4280
--- /dev/null
+++ b/ui/base/cursor/cursor_loader_fuchsia.cc
@@ -0,0 +1,16 @@
+// 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 "ui/base/cursor/cursor_loader.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+CursorLoader* CursorLoader::Create() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+}  // namespace ui
diff --git a/ui/base/idle/idle_fuchsia.cc b/ui/base/idle/idle_fuchsia.cc
new file mode 100644
index 0000000..ed21be8
--- /dev/null
+++ b/ui/base/idle/idle_fuchsia.cc
@@ -0,0 +1,23 @@
+// 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 "ui/base/idle/idle.h"
+
+#include "base/logging.h"
+
+namespace ui {
+
+void CalculateIdleTime(IdleTimeCallback notify) {
+  // TODO(fuchsia): https://crbug.com/743296.
+  NOTIMPLEMENTED();
+  notify.Run(0);
+}
+
+bool CheckIdleStateIsLocked() {
+  // TODO(fuchsia): https://crbug.com/743296.
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace ui
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc
index 9f6797f..82cdb89 100644
--- a/ui/compositor/layer_animation_element.cc
+++ b/ui/compositor/layer_animation_element.cc
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
 #include "cc/animation/animation.h"
 #include "cc/animation/animation_id_provider.h"
 #include "ui/compositor/float_animation_curve_adapter.h"
@@ -39,6 +40,7 @@
   ~Pause() override {}
 
  private:
+  std::string DebugName() const override { return "Pause"; }
   void OnStart(LayerAnimationDelegate* delegate) override {}
   bool OnProgress(double t, LayerAnimationDelegate* delegate) override {
     return false;
@@ -61,6 +63,9 @@
   ~InterpolatedTransformTransition() override {}
 
  protected:
+  std::string DebugName() const override {
+    return "InterpolatedTransformTransition";
+  }
   void OnStart(LayerAnimationDelegate* delegate) override {}
 
   bool OnProgress(double t, LayerAnimationDelegate* delegate) override {
@@ -92,6 +97,7 @@
   ~BoundsTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "BoundsTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetBoundsForAnimation();
   }
@@ -127,6 +133,7 @@
   ~VisibilityTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "VisibilityTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetVisibilityForAnimation();
   }
@@ -161,6 +168,7 @@
   ~BrightnessTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "BrightnessTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetBrightnessForAnimation();
   }
@@ -196,6 +204,7 @@
   ~GrayscaleTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "GrayscaleTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetGrayscaleForAnimation();
   }
@@ -231,6 +240,7 @@
   ~ColorTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "ColorTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetColorForAnimation();
   }
@@ -265,6 +275,7 @@
   ~TemperatureTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "TemperatureTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetTemperatureFromAnimation();
   }
@@ -304,6 +315,9 @@
   explicit ThreadedLayerAnimationElement(const LayerAnimationElement& element)
     : LayerAnimationElement(element) {
   }
+  std::string DebugName() const override {
+    return "ThreadedLayerAnimationElement";
+  }
 
   bool OnProgress(double t, LayerAnimationDelegate* delegate) override {
     if (t < 1.0)
@@ -365,6 +379,7 @@
   ~ThreadedOpacityTransition() override {}
 
  protected:
+  std::string DebugName() const override { return "ThreadedOpacityTransition"; }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetOpacityForAnimation();
   }
@@ -416,6 +431,9 @@
   ~ThreadedTransformTransition() override {}
 
  protected:
+  std::string DebugName() const override {
+    return "ThreadedTransformTransition";
+  }
   void OnStart(LayerAnimationDelegate* delegate) override {
     start_ = delegate->GetTransformForAnimation();
   }
@@ -621,6 +639,21 @@
   effective_start_time_ = requested_start_time_;
 }
 
+std::string LayerAnimationElement::ToString() const {
+  // TODO(wkorman): Add support for subclasses to tack on more info
+  // beyond just their name.
+  return base::StringPrintf(
+      "LayerAnimationElement{name=%s, id=%d, group=%d, "
+      "last_progressed_fraction=%0.2f, "
+      "start_frame_number=%d}",
+      DebugName().c_str(), animation_id_, animation_group_id_,
+      last_progressed_fraction_, start_frame_number_);
+}
+
+std::string LayerAnimationElement::DebugName() const {
+  return "Default";
+}
+
 // static
 LayerAnimationElement::AnimatableProperty
 LayerAnimationElement::ToAnimatableProperty(cc::TargetProperty::Type property) {
@@ -636,6 +669,57 @@
 }
 
 // static
+std::string LayerAnimationElement::AnimatablePropertiesToString(
+    AnimatableProperties properties) {
+  std::string str;
+  int property_count = 0;
+  for (unsigned i = FIRST_PROPERTY; i != SENTINEL; i = i << 1) {
+    if (i & properties) {
+      LayerAnimationElement::AnimatableProperty property =
+          static_cast<LayerAnimationElement::AnimatableProperty>(i);
+      if (property_count > 0)
+        str.append("|");
+      // TODO(wkorman): Consider reworking enum definition to follow
+      // #define pattern that includes easier string output.
+      switch (property) {
+        case UNKNOWN:
+          str.append("UNKNOWN");
+          break;
+        case TRANSFORM:
+          str.append("TRANSFORM");
+          break;
+        case BOUNDS:
+          str.append("BOUNDS");
+          break;
+        case OPACITY:
+          str.append("OPACITY");
+          break;
+        case VISIBILITY:
+          str.append("VISIBILITY");
+          break;
+        case BRIGHTNESS:
+          str.append("BRIGHTNESS");
+          break;
+        case GRAYSCALE:
+          str.append("GRAYSCALE");
+          break;
+        case COLOR:
+          str.append("COLOR");
+          break;
+        case TEMPERATURE:
+          str.append("TEMPERATURE");
+          break;
+        case SENTINEL:
+          NOTREACHED();
+          break;
+      }
+      property_count++;
+    }
+  }
+  return str;
+}
+
+// static
 base::TimeDelta LayerAnimationElement::GetEffectiveDuration(
     const base::TimeDelta& duration) {
   switch (ScopedAnimationDurationScaleMode::duration_scale_mode()) {
diff --git a/ui/compositor/layer_animation_element.h b/ui/compositor/layer_animation_element.h
index 6dc7e30..9a11b97c 100644
--- a/ui/compositor/layer_animation_element.h
+++ b/ui/compositor/layer_animation_element.h
@@ -78,6 +78,9 @@
 
   virtual ~LayerAnimationElement();
 
+  static std::string AnimatablePropertiesToString(
+      AnimatableProperties properties);
+
   // Creates an element that transitions to the given transform. The caller owns
   // the return value.
   static std::unique_ptr<LayerAnimationElement> CreateTransformElement(
@@ -214,7 +217,11 @@
   // call made to {Progress, ProgressToEnd}.
   double last_progressed_fraction() const { return last_progressed_fraction_; }
 
+  std::string ToString() const;
+
  protected:
+  virtual std::string DebugName() const;
+
   // Called once each time the animation element is run before any call to
   // OnProgress.
   virtual void OnStart(LayerAnimationDelegate* delegate) = 0;
diff --git a/ui/compositor/layer_animation_element_unittest.cc b/ui/compositor/layer_animation_element_unittest.cc
index 93714e50..6baad14 100644
--- a/ui/compositor/layer_animation_element_unittest.cc
+++ b/ui/compositor/layer_animation_element_unittest.cc
@@ -400,6 +400,20 @@
                           delegate.GetTransformForAnimation());
 }
 
+TEST(LayerAnimationElementTest, ToString) {
+  float target = 1.0;
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+  std::unique_ptr<LayerAnimationElement> element =
+      LayerAnimationElement::CreateOpacityElement(target, delta);
+  element->set_animation_group_id(42);
+  // TODO(wkorman): Test varying last_progressed_fraction and
+  // start_frame_number.
+  EXPECT_EQ(
+      "LayerAnimationElement{name=ThreadedOpacityTransition, id=1, group=42, "
+      "last_progressed_fraction=0.00, start_frame_number=0}",
+      element->ToString());
+}
+
 } // namespace
 
 } // namespace ui
diff --git a/ui/compositor/layer_animation_sequence.cc b/ui/compositor/layer_animation_sequence.cc
index f13db19..a7a7b1c5 100644
--- a/ui/compositor/layer_animation_sequence.cc
+++ b/ui/compositor/layer_animation_sequence.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <iterator>
 
+#include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/animation/animation_id_provider.h"
 #include "ui/compositor/layer_animation_delegate.h"
@@ -290,4 +291,23 @@
   return elements_[current_index].get();
 }
 
+std::string LayerAnimationSequence::ElementsToString() const {
+  std::string str;
+  for (size_t i = 0; i < elements_.size(); i++) {
+    if (i > 0)
+      str.append(", ");
+    str.append(elements_[i]->ToString());
+  }
+  return str;
+}
+
+std::string LayerAnimationSequence::ToString() const {
+  return base::StringPrintf(
+      "LayerAnimationSequence{size=%zu, properties=%s, "
+      "elements=[%s], is_cyclic=%d, group_id=%d}",
+      size(),
+      LayerAnimationElement::AnimatablePropertiesToString(properties_).c_str(),
+      ElementsToString().c_str(), is_cyclic_, animation_group_id_);
+}
+
 }  // namespace ui
diff --git a/ui/compositor/layer_animation_sequence.h b/ui/compositor/layer_animation_sequence.h
index 379ff54a..cee0500 100644
--- a/ui/compositor/layer_animation_sequence.h
+++ b/ui/compositor/layer_animation_sequence.h
@@ -138,6 +138,8 @@
 
   LayerAnimationElement* FirstElement() const;
 
+  std::string ToString() const;
+
  private:
   friend class LayerAnimatorTestController;
 
@@ -146,6 +148,8 @@
   FRIEND_TEST_ALL_PREFIXES(LayerAnimatorTest,
                            ObserverReleasedBeforeAnimationSequenceEnds);
 
+  std::string ElementsToString() const;
+
   // Notifies the observers that this sequence has been scheduled.
   void NotifyScheduled();
 
diff --git a/ui/compositor/layer_animation_sequence_unittest.cc b/ui/compositor/layer_animation_sequence_unittest.cc
index 9222046f..846066ee 100644
--- a/ui/compositor/layer_animation_sequence_unittest.cc
+++ b/ui/compositor/layer_animation_sequence_unittest.cc
@@ -268,6 +268,36 @@
   }
 }
 
+TEST(LayerAnimationSequenceTest, ToString) {
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+  LayerAnimationSequence sequence;
+  EXPECT_EQ(
+      "LayerAnimationSequence{size=0, properties=, elements=[], is_cyclic=0, "
+      "group_id=0}",
+      sequence.ToString());
+
+  sequence.AddElement(
+      LayerAnimationElement::CreateBrightnessElement(1.0f, delta));
+  EXPECT_EQ(
+      "LayerAnimationSequence{size=1, properties=BRIGHTNESS, "
+      "elements=[LayerAnimationElement{name=BrightnessTransition, id=1, "
+      "group=0, last_progressed_fraction=0.00, start_frame_number=0}], "
+      "is_cyclic=0, group_id=0}",
+      sequence.ToString());
+
+  sequence.AddElement(LayerAnimationElement::CreateOpacityElement(1.0f, delta));
+  sequence.set_is_cyclic(true);
+  sequence.set_animation_group_id(1973);
+  EXPECT_EQ(
+      "LayerAnimationSequence{size=2, properties=OPACITY|BRIGHTNESS, "
+      "elements=[LayerAnimationElement{name=BrightnessTransition, id=1, "
+      "group=0, last_progressed_fraction=0.00, start_frame_number=0}, "
+      "LayerAnimationElement{name=ThreadedOpacityTransition, id=2, group=0, "
+      "last_progressed_fraction=0.00, start_frame_number=0}], is_cyclic=1, "
+      "group_id=1973}",
+      sequence.ToString());
+}
+
 } // namespace
 
 } // namespace ui
diff --git a/ui/display/BUILD.gn b/ui/display/BUILD.gn
index 0d7b80d..02a8a57 100644
--- a/ui/display/BUILD.gn
+++ b/ui/display/BUILD.gn
@@ -76,6 +76,10 @@
       "CoreGraphics.framework",
     ]
   }
+
+  if (is_fuchsia) {
+    sources += [ "screen_fuchsia.cc" ]
+  }
 }
 
 component("display_manager_test_api") {
diff --git a/ui/display/screen_fuchsia.cc b/ui/display/screen_fuchsia.cc
new file mode 100644
index 0000000..e8f2cb87
--- /dev/null
+++ b/ui/display/screen_fuchsia.cc
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/display/screen.h"
+
+#include "base/logging.h"
+
+namespace display {
+
+// static
+gfx::NativeWindow Screen::GetWindowForView(gfx::NativeView view) {
+  // TODO(fuchsia): Stubbed during headless bringup https://crbug.com/743296.
+  NOTREACHED();
+  return nullptr;
+}
+
+}  // namespace display
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index e6cb51a..91bf6ca2 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -254,7 +254,7 @@
   ]
 
   # Text rendering conditions (complicated so separated out).
-  if (use_aura || is_mac || (is_android && enable_vr)) {
+  if (use_aura || is_mac || (is_android && enable_vr) || is_fuchsia) {
     # Mac doesn't use RenderTextHarfBuzz by default yet.
     sources += [
       "harfbuzz_font_skia.cc",
@@ -386,6 +386,14 @@
   if (use_cairo) {
     configs += [ "//build/config/linux/pangocairo" ]
   }
+
+  if (is_fuchsia) {
+    sources += [
+      "font_fallback_fuchsia.cc",
+      "font_render_params_fuchsia.cc",
+      "platform_font_fuchsia.cc",
+    ]
+  }
 }
 
 component("color_space") {
diff --git a/ui/gfx/font_fallback_fuchsia.cc b/ui/gfx/font_fallback_fuchsia.cc
new file mode 100644
index 0000000..bfdc7aa2
--- /dev/null
+++ b/ui/gfx/font_fallback_fuchsia.cc
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/font_fallback.h"
+
+#include <string>
+#include <vector>
+
+namespace gfx {
+
+std::vector<Font> GetFallbackFonts(const Font& font) {
+  // TODO(fuchsia): Stubbed while bringing up headless build, see
+  // https://crbug.com/743296.
+  return std::vector<Font>();
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/font_render_params_fuchsia.cc b/ui/gfx/font_render_params_fuchsia.cc
new file mode 100644
index 0000000..f693f92
--- /dev/null
+++ b/ui/gfx/font_render_params_fuchsia.cc
@@ -0,0 +1,38 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/font_render_params.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+namespace gfx {
+
+namespace {
+
+// Returns the system's default settings.
+FontRenderParams LoadDefaults() {
+  FontRenderParams params;
+  params.antialiasing = true;
+  params.autohinter = true;
+  params.use_bitmaps = true;
+  params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
+  params.subpixel_positioning = true;
+  params.hinting = FontRenderParams::HINTING_SLIGHT;
+
+  return params;
+}
+
+}  // namespace
+
+FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
+                                     std::string* family_out) {
+  if (family_out)
+    NOTIMPLEMENTED();
+  // Customized font rendering settings are not supported, only defaults.
+  CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params, (LoadDefaults()));
+  return params;
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/platform_font_fuchsia.cc b/ui/gfx/platform_font_fuchsia.cc
new file mode 100644
index 0000000..d150066
--- /dev/null
+++ b/ui/gfx/platform_font_fuchsia.cc
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/platform_font.h"
+
+#include "base/logging.h"
+
+namespace gfx {
+
+// static
+PlatformFont* PlatformFont::CreateDefault() {
+  // TODO(fuchsia): Stubbed during headless bringup, https://crbug.com/743296.
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+// static
+PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
+                                                  int font_size) {
+  // TODO(fuchsia): Stubbed during headless bringup, https://crbug.com/743296.
+  NOTIMPLEMENTED();
+  return NULL;
+}
+
+}  // namespace gfx
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js
index 1ab7e51..218466d 100644
--- a/ui/login/account_picker/md_user_pod_row.js
+++ b/ui/login/account_picker/md_user_pod_row.js
@@ -54,6 +54,14 @@
   var POD_ROW_IMAGES_LOAD_TIMEOUT_MS = 3000;
 
   /**
+   * The duration of the animation for switching between main pod and small
+   * pod. It should be synced with CSS.
+   * @type {number}
+   * @const
+   */
+  var POD_SWITCH_ANIMATION_DURATION_MS = 180;
+
+  /**
    * Public session help topic identifier.
    * @type {number}
    * @const
@@ -996,6 +1004,14 @@
     },
 
     /**
+     * Gets animated image element.
+     * @type {!HTMLImageElement}
+     */
+    get smallPodAnimatedImageElement() {
+      return this.querySelector('.user-image.small-pod-image.animated-image');
+    },
+
+    /**
      * Gets name element of the small pod.
      * @type {!HTMLDivElement}
      */
@@ -1250,6 +1266,7 @@
       this.imageElement.src = imageSrc;
       this.animatedImageElement.src = animatedImageSrc;
       this.smallPodImageElement.src = imageSrc;
+      this.smallPodAnimatedImageElement.src = animatedImageSrc;
 
       this.nameElement.textContent = this.user_.displayName;
       this.smallPodNameElement.textContent = this.user_.displayName;
@@ -4025,7 +4042,6 @@
         // to make sure that the styles of all the elements in the pod row are
         // updated before being shown.
         this.handleAfterPodPlacement_();
-        this.clearPodsAnimation_();
       }
     },
 
@@ -4048,16 +4064,19 @@
     },
 
     /**
-     * Clears animation classes that may be added earlier to ensure a clean
-     * state.
+     * Toggles the animation for switching between main pod and small pod.
+     * @param {UserPod} pod Pod that needs to toggle the animation.
+     * @param {boolean} enabled Whether the switch animation is needed.
      * @private
      */
-    clearPodsAnimation_: function() {
-      var pods = this.pods;
-      for (var pod of pods) {
-        pod.imageElement.classList.remove('switch-image-animation');
-        pod.smallPodImageElement.classList.remove('switch-image-animation');
-      }
+    toggleSwitchAnimation_: function(pod, enabled) {
+      pod.imageElement.classList.toggle('switch-image-animation', enabled);
+      pod.animatedImageElement.classList.toggle(
+          'switch-image-animation', enabled);
+      pod.smallPodImageElement.classList.toggle(
+          'switch-image-animation', enabled);
+      pod.smallPodAnimatedImageElement.classList.toggle(
+          'switch-image-animation', enabled);
     },
 
     /**
@@ -4087,9 +4106,13 @@
       this.mainPod_.setPodStyle(pod.getPodStyle());
       pod.setPodStyle(UserPod.Style.LARGE);
       // Add switch animation.
-      this.mainPod_.smallPodImageElement.classList.add(
-          'switch-image-animation');
-      pod.imageElement.classList.add('switch-image-animation');
+      this.toggleSwitchAnimation_(this.mainPod_, true);
+      this.toggleSwitchAnimation_(pod, true);
+      setTimeout(function() {
+        var pods = this.pods;
+        for (var pod of pods)
+          this.toggleSwitchAnimation_(pod, false);
+      }.bind(this), POD_SWITCH_ANIMATION_DURATION_MS);
 
       // Switch parent and position of the two pods.
       var left = pod.left;
@@ -4676,7 +4699,6 @@
       }
 
       this.handleAfterPodPlacement_();
-      this.clearPodsAnimation_();
     },
 
     /**
diff --git a/ui/login/account_picker/md_user_pod_template.html b/ui/login/account_picker/md_user_pod_template.html
index 761b791..71c453ae 100644
--- a/ui/login/account_picker/md_user_pod_template.html
+++ b/ui/login/account_picker/md_user_pod_template.html
@@ -202,6 +202,8 @@
   <div class="small-pod" hidden>
     <div class="small-user-image-container">
       <img class="user-image small-pod-image" alt aria-hidden="true">
+      <img class="user-image small-pod-image animated-image"
+           alt aria-hidden="true">
     </div>
     <div class="small-pod-name" aria-hidden="true"></div>
   </div>
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc
index 315b0468..d38353f 100644
--- a/ui/views/controls/button/md_text_button.cc
+++ b/ui/views/controls/button/md_text_button.cc
@@ -243,6 +243,7 @@
 
 void MdTextButton::UpdateColors() {
   ui::NativeTheme* theme = GetNativeTheme();
+  bool is_disabled = state() == STATE_DISABLED;
   SkColor enabled_text_color = style::GetColor(
       label()->text_context(),
       is_prominent_ ? style::STYLE_DIALOG_BUTTON_DEFAULT : style::STYLE_PRIMARY,
@@ -250,10 +251,15 @@
   if (!explicitly_set_normal_color()) {
     const auto colors = explicitly_set_colors();
     LabelButton::SetEnabledTextColors(enabled_text_color);
-    if (state() == STATE_DISABLED && !is_prominent_)
+    // Non-prominent, disabled buttons need the disabled color explicitly set.
+    // This ensures that label()->enabled_color() returns the correct color as
+    // the basis for calculating the stroke color. enabled_text_color isn't used
+    // since a descendant could have overridden the label enabled color.
+    if (is_disabled && !is_prominent_) {
       LabelButton::SetTextColor(STATE_DISABLED,
                                 style::GetColor(label()->text_context(),
                                                 style::STYLE_DISABLED, theme));
+    }
     set_explicitly_set_colors(colors);
   }
 
@@ -271,9 +277,10 @@
   } else if (is_prominent_) {
     bg_color = theme->GetSystemColor(
         ui::NativeTheme::kColorId_ProminentButtonColor);
-    if (state() == STATE_DISABLED)
+    if (is_disabled) {
       bg_color = color_utils::BlendTowardOppositeLuma(
           bg_color, gfx::kDisabledControlAlpha);
+    }
   }
 
   if (state() == STATE_PRESSED) {
@@ -282,24 +289,27 @@
     bg_color = color_utils::GetResultingPaintColor(shade, bg_color);
   }
 
-  // Specified text color: 5a5a5a @ 1.0 alpha, 757575 @ 1.0 alpha for Harmony
-  // Specified stroke color: 000000 @ 0.2 alpha, Harmony and non-Harmony
-  // 000000 @ 0.2 is very close to 5a5a5a @ 0.308 (== 0x4e) or 757575 @ 0.37
-  // (== 0x5f); both are cccccc @ 1.0, and this way if NativeTheme changes the
-  // button color, the button stroke will also change colors to match.
-  SkColor stroke_color =
-      is_prominent_ ? SK_ColorTRANSPARENT
-                    : SkColorSetA(text_color,
-                                  UseMaterialSecondaryButtons() ? 0x5f : 0x4e);
-
-  // Disabled, non-prominent buttons need their stroke lightened. The Harmony
-  // spec asks for 000000 @ 0.1 alpha or e6e6e6 @ 1.0 alpha. The stroke color
-  // has already been translated above to cccccc @ 1.0 or 000000 @ 0.2.
-  // cccccc @ 0.25 (== 0x41) translates to e6e6e6 @ 1.0. To simplify the code,
-  // 000000 @ 0.1 is being used for both Harmony and non-Harmony. Prominent
-  // buttons need it left at SK_ColorTRANSPARENT from above.
-  if (state() == STATE_DISABLED && !is_prominent_)
-    stroke_color = SkColorSetA(stroke_color, 0x41);
+  SkColor stroke_color;
+  if (is_prominent_) {
+    stroke_color = SK_ColorTRANSPARENT;
+  } else {
+    int stroke_alpha;
+    if (is_disabled) {
+      // Disabled, non-prominent buttons need a lighter stroke. This alpha
+      // value will take the disabled button colors, a1a192 @ 1.0 alpha for
+      // non-Harmony, 9e9e9e @ 1.0 alpha for Harmony and turn it into
+      // e6e6e6 @ 1.0 alpha (or very close to it) or an effective 000000 @ 0.1
+      // alpha for the stroke color. The same alpha value will work with both
+      // Harmony and non-Harmony colors.
+      stroke_alpha = 0x43;
+    } else {
+      // These alpha values will take the enabled button colors, 5a5a5a @ 1.0
+      // alpha for non-Harmony, 757575 @ 1.0 alpha for Harmony and turn it into
+      // an effective cccccc @ 1.0 alpha or 000000 @ 0.2 for the stroke_color.
+      stroke_alpha = UseMaterialSecondaryButtons() ? 0x5f : 0x4e;
+    }
+    stroke_color = SkColorSetA(text_color, stroke_alpha);
+  }
 
   DCHECK_EQ(SK_AlphaOPAQUE, static_cast<int>(SkColorGetA(bg_color)));
   SetBackground(