diff --git a/AUTHORS b/AUTHORS
index 09e3ddf..9ba1a0b0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -62,6 +62,7 @@
 Ankur Verma <ankur1.verma@samsung.com>
 Anne Kao <annekao94@gmail.com>
 Anssi Hannula <anssi.hannula@iki.fi>
+Anthony Halliday <anth.halliday12@gmail.com>
 Anton Obzhirov <a.obzhirov@samsung.com>
 Antonin Hildebrand <antonin.hildebrand@gmail.com>
 Antonio Gomes <a1.gomes@sisa.samsung.com>
diff --git a/DEPS b/DEPS
index be8174d..fe307aa 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c83ada98e2e60be75ae03e228c4d35eb45357add',
+  'skia_revision': '3ae677c8f85fe0a4703d1df0b5941d59282d7ff7',
   # 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': '54be4ccd93a89c4baf4b0696c0ec6e95d8622d7e',
+  'v8_revision': 'f0852831dedf0bbbdf56278c750c23f695dcd5b3',
   # 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.
@@ -95,7 +95,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': '96f25d9aa22bdc48bb9e6fa417585fb150caa0a1',
+  'catapult_revision': 'dd4b5729a8b7c585775b8a3ad340746af67fdd91',
   # 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/BUILD.gn b/ash/BUILD.gn
index fb8d3a4..a907e67 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -354,8 +354,6 @@
     "common/system/tray/ime_info.h",
     "common/system/tray/label_tray_view.cc",
     "common/system/tray/label_tray_view.h",
-    "common/system/tray/size_range_layout.cc",
-    "common/system/tray/size_range_layout.h",
     "common/system/tray/special_popup_row.cc",
     "common/system/tray/special_popup_row.h",
     "common/system/tray/system_menu_button.cc",
@@ -372,8 +370,6 @@
     "common/system/tray/system_tray_item.h",
     "common/system/tray/system_tray_notifier.cc",
     "common/system/tray/system_tray_notifier.h",
-    "common/system/tray/three_view_layout.cc",
-    "common/system/tray/three_view_layout.h",
     "common/system/tray/throbber_view.cc",
     "common/system/tray/throbber_view.h",
     "common/system/tray/tray_background_view.cc",
@@ -404,8 +400,6 @@
     "common/system/tray/tray_popup_label_button.h",
     "common/system/tray/tray_popup_label_button_border.cc",
     "common/system/tray/tray_popup_label_button_border.h",
-    "common/system/tray/tray_popup_layout_factory.cc",
-    "common/system/tray/tray_popup_layout_factory.h",
     "common/system/tray/tray_utils.cc",
     "common/system/tray/tray_utils.h",
     "common/system/tray/view_click_listener.h",
@@ -1047,6 +1041,7 @@
     ":ash",
     ":ash_with_content",
     "//ash/common/strings",
+    "//ash/common/test:test_support",
     "//ash/public/cpp",
     "//ash/resources",
     "//ash/test:test_support_without_content",
@@ -1226,9 +1221,7 @@
     "common/system/chromeos/session/tray_session_length_limit_unittest.cc",
     "common/system/ime/tray_ime_chromeos_unittest.cc",
     "common/system/tiles/tray_tiles_unittest.cc",
-    "common/system/tray/size_range_layout_unittest.cc",
     "common/system/tray/system_tray_unittest.cc",
-    "common/system/tray/three_view_layout_unittest.cc",
     "common/system/tray/tray_details_view_unittest.cc",
     "common/system/user/tray_user_unittest.cc",
 
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index f837b01..06a3490 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/common/system/brightness_control_delegate.h"
 #include "ash/common/system/keyboard_brightness_control_delegate.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/panels/panel_layout_manager.h"
 #include "ash/common/wm/window_positioning_utils.h"
 #include "ash/common/wm/window_state.h"
@@ -25,7 +26,6 @@
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/test_screenshot_delegate.h"
 #include "ash/test/test_session_state_animator.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
@@ -249,12 +249,9 @@
   aura::Window* CreatePanel() {
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         NULL, ui::wm::WINDOW_TYPE_PANEL, 0, gfx::Rect(5, 5, 20, 20));
-    test::TestShelfDelegate* shelf_delegate =
-        test::TestShelfDelegate::instance();
-    shelf_delegate->AddShelfItem(window);
-    PanelLayoutManager* manager =
-        PanelLayoutManager::Get(WmWindowAura::Get(window));
-    manager->Relayout();
+    WmWindow* wm_window = WmWindowAura::Get(window);
+    test::TestShelfDelegate::instance()->AddShelfItem(wm_window);
+    PanelLayoutManager::Get(wm_window)->Relayout();
     return window;
   }
 
diff --git a/ash/common/shelf/shelf_tooltip_manager_unittest.cc b/ash/common/shelf/shelf_tooltip_manager_unittest.cc
index 33c8edf..268626e 100644
--- a/ash/common/shelf/shelf_tooltip_manager_unittest.cc
+++ b/ash/common/shelf/shelf_tooltip_manager_unittest.cc
@@ -8,9 +8,9 @@
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_view.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/common/test/test_shelf_item_delegate.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_item_delegate.h"
 #include "base/memory/ptr_util.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/test/event_generator.h"
diff --git a/ash/common/system/tray/size_range_layout.cc b/ash/common/system/tray/size_range_layout.cc
deleted file mode 100644
index 6eaf8aa86..0000000
--- a/ash/common/system/tray/size_range_layout.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <limits>
-
-#include "ash/common/system/tray/size_range_layout.h"
-
-#include "base/logging.h"
-#include "ui/views/layout/fill_layout.h"
-
-namespace ash {
-
-// static
-
-gfx::Size SizeRangeLayout::AbsoluteMinSize() {
-  const int kMinSize = 0;
-  return gfx::Size(kMinSize, kMinSize);
-}
-
-gfx::Size SizeRangeLayout::AbsoluteMaxSize() {
-  const int kMaxSize = std::numeric_limits<int>::max();
-  return gfx::Size(kMaxSize, kMaxSize);
-}
-
-// Non static
-
-SizeRangeLayout::SizeRangeLayout()
-    : SizeRangeLayout(AbsoluteMinSize(), AbsoluteMaxSize()) {}
-
-SizeRangeLayout::SizeRangeLayout(const gfx::Size& min_size,
-                                 const gfx::Size& max_size)
-    : layout_manager_(new views::FillLayout()),
-      min_size_(AbsoluteMinSize()),
-      max_size_(AbsoluteMaxSize()) {
-  SetMinSize(min_size);
-  SetMaxSize(max_size);
-}
-
-SizeRangeLayout::~SizeRangeLayout() {}
-
-void SizeRangeLayout::SetSize(const gfx::Size& size) {
-  SetMinSize(size);
-  SetMaxSize(size);
-}
-
-void SizeRangeLayout::SetMinSize(const gfx::Size& size) {
-  min_size_ = size;
-  min_size_.SetToMax(gfx::Size());
-  max_size_.SetToMax(min_size_);
-}
-
-void SizeRangeLayout::SetMaxSize(const gfx::Size& size) {
-  max_size_ = size;
-  max_size_.SetToMax(gfx::Size());
-  min_size_.SetToMin(max_size_);
-}
-
-void SizeRangeLayout::SetLayoutManager(
-    std::unique_ptr<LayoutManager> layout_manager) {
-  DCHECK(layout_manager_);
-  layout_manager_ = std::move(layout_manager);
-  layout_manager_->Installed(host_);
-}
-
-void SizeRangeLayout::Installed(views::View* host) {
-  DCHECK(!host_);
-  host_ = host;
-  layout_manager_->Installed(host);
-}
-
-void SizeRangeLayout::Layout(views::View* host) {
-  layout_manager_->Layout(host);
-}
-
-gfx::Size SizeRangeLayout::GetPreferredSize(const views::View* host) const {
-  gfx::Size preferred_size = layout_manager_->GetPreferredSize(host);
-  ClampSizeToRange(&preferred_size);
-  return preferred_size;
-}
-
-int SizeRangeLayout::GetPreferredHeightForWidth(const views::View* host,
-                                                int width) const {
-  const int height = layout_manager_->GetPreferredHeightForWidth(host, width);
-  gfx::Size size(0, height);
-  ClampSizeToRange(&size);
-  return size.height();
-}
-
-void SizeRangeLayout::ViewAdded(views::View* host, views::View* view) {
-  layout_manager_->ViewAdded(host, view);
-}
-
-void SizeRangeLayout::ViewRemoved(views::View* host, views::View* view) {
-  layout_manager_->ViewRemoved(host, view);
-}
-
-void SizeRangeLayout::ClampSizeToRange(gfx::Size* size) const {
-  size->SetToMax(min_size_);
-  size->SetToMin(max_size_);
-}
-
-}  // namespace ash
diff --git a/ash/common/system/tray/size_range_layout.h b/ash/common/system/tray/size_range_layout.h
deleted file mode 100644
index 175960f..0000000
--- a/ash/common/system/tray/size_range_layout.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_COMMON_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_
-#define ASH_COMMON_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "base/macros.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/views/layout/layout_manager.h"
-
-namespace views {
-class View;
-}  // namespace views
-
-namespace ash {
-
-// A LayoutManager adapter that allows clients to specify a minimum and/or a
-// maximum preferred size. The actual layout will be delegated to the
-// LayoutManager owned by this. i.e. |this| can be used to override the
-// preferred size returned by a View.
-//
-// By default the SizeRangeLayout is configured to own a FillLayout but this can
-// be overridden with SetLayoutManager().
-//
-// Example use case :
-//
-//  Suppose you wanted a Label to take up a specific size of (50, 50) even
-//  though the label's preferred size was (25, 25).
-//
-// Example code:
-//
-//  Label* label = new Label(kSomeDummyText);
-//  View* container = new View();
-//  container->AddChildView(label);
-//  SizeRangeLayout* layout = new SizeRangeLayout();
-//  layout->SetSize(gfx::Size(50, 50));
-//  container->SetLayoutManager(layout);
-//
-class ASH_EXPORT SizeRangeLayout : public views::LayoutManager {
- public:
-  // Returns the absolute minimum possible size. Use this with set_min_size() to
-  // effectively unset the minimum preferred size.
-  static gfx::Size AbsoluteMinSize();
-
-  // Returns the absolute maximum possible size. Use this with set_max_size() to
-  // effectively unset the maximum preferred size.
-  static gfx::Size AbsoluteMaxSize();
-
-  // Create a layout with no minimum or maximum preferred size.
-  SizeRangeLayout();
-
-  // Create a layout with the given minimum and maximum preferred sizes. If
-  // |max_size| is smaller than |min_size| then |min_size| will be set to the
-  // smaller |max_size| value.
-  SizeRangeLayout(const gfx::Size& min_size, const gfx::Size& max_size);
-
-  ~SizeRangeLayout() override;
-
-  // Sets both the minimum and maximum preferred size.
-  void SetSize(const gfx::Size& size);
-
-  // Set the minimum preferred size that GetPreferredSize() will round up to. If
-  // |size| is larger than the current |max_size_| then |max_size_| will set to
-  // |size| as well.
-  void SetMinSize(const gfx::Size& size);
-
-  // Set the minimum preferred size that GetPreferredSize() will round down to.
-  // If |size| is smaller than the current |min_size_| then |min_size_| will set
-  // to |size| as well.
-  void SetMaxSize(const gfx::Size& size);
-
-  // Sets the layout manager that actually performs the layout once the bounds
-  // have been defined.
-  void SetLayoutManager(std::unique_ptr<LayoutManager> layout_manager);
-
-  // LayoutManager:
-  void Installed(views::View* host) override;
-  void Layout(views::View* host) override;
-  gfx::Size GetPreferredSize(const views::View* host) const override;
-  int GetPreferredHeightForWidth(const views::View* host,
-                                 int width) const override;
-  void ViewAdded(views::View* host, views::View* view) override;
-  void ViewRemoved(views::View* host, views::View* view) override;
-
- private:
-  friend class SizeRangeLayoutTest;
-
-  // Clamps |size| to be within the minimum and maximum preferred sizes.
-  void ClampSizeToRange(gfx::Size* size) const;
-
-  // The host View that this has been installed on.
-  views::View* host_ = nullptr;
-
-  // The layout manager that actually performs the layout.
-  std::unique_ptr<views::LayoutManager> layout_manager_;
-
-  // The minimum preferred size.
-  gfx::Size min_size_;
-
-  // The maximum preferred size.
-  gfx::Size max_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(SizeRangeLayout);
-};
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_
diff --git a/ash/common/system/tray/size_range_layout_unittest.cc b/ash/common/system/tray/size_range_layout_unittest.cc
deleted file mode 100644
index 4db8c24..0000000
--- a/ash/common/system/tray/size_range_layout_unittest.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/common/system/tray/size_range_layout.h"
-#include "base/memory/ptr_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/views/test/test_layout_manager.h"
-#include "ui/views/view.h"
-
-namespace ash {
-
-class SizeRangeLayoutTest : public testing::Test {
- public:
-  SizeRangeLayoutTest();
-
-  // Wrapper function to access the minimum preferred size of |layout|.
-  gfx::Size GetMinSize(const SizeRangeLayout* layout) const;
-
-  // Wrapper function to access the maximum preferred size of |layout|.
-  gfx::Size GetMaxSize(const SizeRangeLayout* layout) const;
-
- protected:
-  views::View host_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SizeRangeLayoutTest);
-};
-
-SizeRangeLayoutTest::SizeRangeLayoutTest() {}
-
-gfx::Size SizeRangeLayoutTest::GetMinSize(const SizeRangeLayout* layout) const {
-  return layout->min_size_;
-}
-
-gfx::Size SizeRangeLayoutTest::GetMaxSize(const SizeRangeLayout* layout) const {
-  return layout->max_size_;
-}
-
-TEST_F(SizeRangeLayoutTest, SizeRangeForDefaultConstruction) {
-  SizeRangeLayout layout;
-  EXPECT_EQ(SizeRangeLayout::AbsoluteMinSize(), GetMinSize(&layout));
-  EXPECT_EQ(SizeRangeLayout::AbsoluteMaxSize(), GetMaxSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, SizeRangeForExplicitConstruction) {
-  const gfx::Size kSmallSize = gfx::Size(13, 14);
-  const gfx::Size kLargeSize = gfx::Size(25, 26);
-
-  SizeRangeLayout layout(kSmallSize, kLargeSize);
-  EXPECT_EQ(kSmallSize, GetMinSize(&layout));
-  EXPECT_EQ(kLargeSize, GetMaxSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, InvalidMinSizeForExplicitConstruction) {
-  const gfx::Size kInvalidSmallSize(-1, 2);
-  const gfx::Size kExpectedMinSize(0, 2);
-
-  SizeRangeLayout layout(kInvalidSmallSize, SizeRangeLayout::AbsoluteMaxSize());
-  EXPECT_EQ(kExpectedMinSize, GetMinSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, InvalidMaxSizeForExplicitConstruction) {
-  const gfx::Size kInvalidSmallSize(-1, 2);
-  const gfx::Size kExpectedMinSize(0, 2);
-
-  SizeRangeLayout layout(kInvalidSmallSize, SizeRangeLayout::AbsoluteMaxSize());
-  EXPECT_EQ(kExpectedMinSize, GetMinSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, MaxSizeSmallerThanMinSizeConstruction) {
-  const gfx::Size kMinSize(10, 11);
-  const gfx::Size kMaxSize(5, 6);
-
-  SizeRangeLayout layout(kMinSize, kMaxSize);
-  EXPECT_EQ(kMaxSize, GetMinSize(&layout));
-  EXPECT_EQ(kMaxSize, GetMaxSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, SizeRangeForExplicitSetSize) {
-  const gfx::Size kSize = gfx::Size(13, 14);
-
-  SizeRangeLayout layout;
-  EXPECT_NE(kSize, GetMinSize(&layout));
-  EXPECT_NE(kSize, GetMaxSize(&layout));
-
-  layout.SetSize(kSize);
-  EXPECT_EQ(kSize, GetMinSize(&layout));
-  EXPECT_EQ(kSize, GetMaxSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, InvalidSizeRangesForExplicitSetSize) {
-  const gfx::Size kInvalidSize(-7, 8);
-  const gfx::Size kExpectedSize(0, 8);
-
-  SizeRangeLayout layout;
-  layout.SetSize(kInvalidSize);
-  EXPECT_EQ(kExpectedSize, GetMinSize(&layout));
-  EXPECT_EQ(kExpectedSize, GetMaxSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, InternalLayoutManagerPreferredSizeIsUsed) {
-  const gfx::Size kSize(7, 8);
-  std::unique_ptr<views::test::TestLayoutManager> child_layout =
-      base::MakeUnique<views::test::TestLayoutManager>();
-  child_layout->set_preferred_size(kSize);
-
-  SizeRangeLayout layout;
-  EXPECT_NE(kSize, layout.GetPreferredSize(&host_));
-
-  layout.SetLayoutManager(std::move(child_layout));
-  EXPECT_EQ(kSize, layout.GetPreferredSize(&host_));
-}
-
-TEST_F(SizeRangeLayoutTest, SmallPreferredSizeIsClamped) {
-  const gfx::Size kMinSize(10, 10);
-  const gfx::Size kMaxSize(20, 20);
-  const gfx::Size kLayoutPreferredSize(5, 5);
-  std::unique_ptr<views::test::TestLayoutManager> child_layout =
-      base::MakeUnique<views::test::TestLayoutManager>();
-  child_layout->set_preferred_size(kLayoutPreferredSize);
-
-  SizeRangeLayout layout;
-  layout.SetLayoutManager(std::move(child_layout));
-  layout.SetMinSize(kMinSize);
-  layout.SetMaxSize(kMaxSize);
-  EXPECT_EQ(kMinSize, layout.GetPreferredSize(&host_));
-}
-
-TEST_F(SizeRangeLayoutTest, LargePreferredSizeIsClamped) {
-  const gfx::Size kMinSize(10, 10);
-  const gfx::Size kMaxSize(20, 20);
-  const gfx::Size kLayoutPreferredSize(25, 25);
-  std::unique_ptr<views::test::TestLayoutManager> child_layout =
-      base::MakeUnique<views::test::TestLayoutManager>();
-  child_layout->set_preferred_size(kLayoutPreferredSize);
-
-  SizeRangeLayout layout;
-  layout.SetLayoutManager(std::move(child_layout));
-  layout.SetMinSize(kMinSize);
-  layout.SetMaxSize(kMaxSize);
-  EXPECT_EQ(kMaxSize, layout.GetPreferredSize(&host_));
-}
-
-TEST_F(SizeRangeLayoutTest, MaxSizeLargerThanMinSizeUpdatesMinSize) {
-  const gfx::Size kMinSize(10, 10);
-  const gfx::Size kMaxSize(5, 5);
-
-  SizeRangeLayout layout;
-  layout.SetMinSize(kMinSize);
-  EXPECT_EQ(kMinSize, GetMinSize(&layout));
-  layout.SetMaxSize(kMaxSize);
-  EXPECT_EQ(kMaxSize, GetMinSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest, MinSizeSmallerThanMaxSizeUpdatesMaxSize) {
-  const gfx::Size kMinSize(10, 10);
-  const gfx::Size kMaxSize(5, 5);
-
-  SizeRangeLayout layout;
-  layout.SetMaxSize(kMaxSize);
-  EXPECT_EQ(kMaxSize, GetMaxSize(&layout));
-  layout.SetMinSize(kMinSize);
-  EXPECT_EQ(kMinSize, GetMaxSize(&layout));
-}
-
-TEST_F(SizeRangeLayoutTest,
-       InternalLayoutManagerPreferredHeightForWidthIsUsed) {
-  const int kWidth = 5;
-  const int kHeight = 9;
-  std::unique_ptr<views::test::TestLayoutManager> child_layout =
-      base::MakeUnique<views::test::TestLayoutManager>();
-  child_layout->set_preferred_height_for_width(kHeight);
-
-  SizeRangeLayout layout;
-  EXPECT_NE(kHeight, layout.GetPreferredHeightForWidth(&host_, kWidth));
-
-  layout.SetLayoutManager(std::move(child_layout));
-  EXPECT_EQ(kHeight, layout.GetPreferredHeightForWidth(&host_, kWidth));
-}
-
-}  // namespace ash
diff --git a/ash/common/system/tray/three_view_layout.cc b/ash/common/system/tray/three_view_layout.cc
deleted file mode 100644
index d718c7e..0000000
--- a/ash/common/system/tray/three_view_layout.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/common/system/tray/three_view_layout.h"
-
-#include "ash/common/system/tray/size_range_layout.h"
-#include "base/logging.h"
-#include "ui/views/border.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/fill_layout.h"
-
-namespace ash {
-namespace {
-
-// Converts ThreeViewLayout::Orientation values to
-// views::BoxLayout::Orientation values.
-views::BoxLayout::Orientation GetOrientation(
-    ThreeViewLayout::Orientation orientation) {
-  switch (orientation) {
-    case ThreeViewLayout::Orientation::HORIZONTAL:
-      return views::BoxLayout::kHorizontal;
-    case ThreeViewLayout::Orientation::VERTICAL:
-      return views::BoxLayout::kVertical;
-  }
-  // Required for some compilers.
-  NOTREACHED();
-  return views::BoxLayout::kHorizontal;
-}
-
-}  // namespace
-
-ThreeViewLayout::ThreeViewLayout() : ThreeViewLayout(0) {}
-
-ThreeViewLayout::ThreeViewLayout(int padding_between_containers)
-    : ThreeViewLayout(Orientation::HORIZONTAL, padding_between_containers) {}
-
-ThreeViewLayout::ThreeViewLayout(Orientation orientation)
-    : ThreeViewLayout(orientation, 0) {}
-
-ThreeViewLayout::ThreeViewLayout(Orientation orientation,
-                                 int padding_between_containers)
-    : box_layout_(new views::BoxLayout(GetOrientation(orientation),
-                                       0,
-                                       0,
-                                       padding_between_containers)),
-      start_container_(new views::View),
-      start_container_layout_manager_(new SizeRangeLayout),
-      center_container_(new views::View),
-      center_container_layout_manager_(new SizeRangeLayout),
-      end_container_(new views::View),
-      end_container_layout_manager_(new SizeRangeLayout) {
-  start_container_->SetLayoutManager(GetLayoutManager(Container::START));
-  center_container_->SetLayoutManager(GetLayoutManager(Container::CENTER));
-  end_container_->SetLayoutManager(GetLayoutManager(Container::END));
-  GetLayoutManager(Container::START)
-      ->SetLayoutManager(CreateDefaultLayoutManager(orientation));
-  GetLayoutManager(Container::CENTER)
-      ->SetLayoutManager(CreateDefaultLayoutManager(orientation));
-  GetLayoutManager(Container::END)
-      ->SetLayoutManager(CreateDefaultLayoutManager(orientation));
-}
-
-ThreeViewLayout::~ThreeViewLayout() {
-  if (host_) {
-    host_->RemoveChildView(GetContainer(Container::START));
-    host_->RemoveChildView(GetContainer(Container::CENTER));
-    host_->RemoveChildView(GetContainer(Container::END));
-  }
-}
-
-void ThreeViewLayout::SetMinCrossAxisSize(int min_size) {
-  box_layout_->set_minimum_cross_axis_size(min_size);
-}
-
-void ThreeViewLayout::SetMinSize(Container container, const gfx::Size& size) {
-  GetLayoutManager(container)->SetMinSize(size);
-}
-
-void ThreeViewLayout::SetMaxSize(Container container, const gfx::Size& size) {
-  GetLayoutManager(container)->SetMaxSize(size);
-}
-
-void ThreeViewLayout::AddView(Container container, views::View* view) {
-  GetContainer(container)->AddChildView(view);
-}
-
-void ThreeViewLayout::SetView(Container container, views::View* view) {
-  views::View* container_view = GetContainer(container);
-  container_view->RemoveAllChildViews(true);
-  container_view->AddChildView(view);
-}
-
-void ThreeViewLayout::SetInsets(const gfx::Insets& insets) {
-  box_layout_->set_inside_border_insets(insets);
-}
-
-void ThreeViewLayout::SetBorder(Container container,
-                                std::unique_ptr<views::Border> border) {
-  GetContainer(container)->SetBorder(std::move(border));
-}
-
-void ThreeViewLayout::SetContainerVisible(Container container, bool visible) {
-  GetContainer(container)->SetVisible(visible);
-}
-
-void ThreeViewLayout::SetFlexForContainer(Container container, int flex) {
-  box_layout_->SetFlexForView(GetContainer(container), flex);
-}
-
-void ThreeViewLayout::SetLayoutManager(
-    Container container,
-    std::unique_ptr<LayoutManager> layout_manager) {
-  GetLayoutManager(container)->SetLayoutManager(std::move(layout_manager));
-  if (GetLayoutManager(container))
-    GetLayoutManager(container)->Installed(GetContainer(container));
-}
-
-void ThreeViewLayout::Installed(views::View* host) {
-  DCHECK(!host_);
-  host_ = host;
-  if (host_) {
-    host_->AddChildView(GetContainer(Container::START));
-    host_->AddChildView(GetContainer(Container::CENTER));
-    host_->AddChildView(GetContainer(Container::END));
-  }
-  box_layout_->Installed(host_);
-}
-
-void ThreeViewLayout::Layout(views::View* host) {
-  box_layout_->Layout(host);
-}
-
-gfx::Size ThreeViewLayout::GetPreferredSize(const views::View* host) const {
-  return box_layout_->GetPreferredSize(host);
-}
-
-int ThreeViewLayout::GetPreferredHeightForWidth(const views::View* host,
-                                                int width) const {
-  return box_layout_->GetPreferredHeightForWidth(host, width);
-}
-
-void ThreeViewLayout::ViewAdded(views::View* host, views::View* view) {
-  box_layout_->ViewAdded(host, view);
-}
-
-void ThreeViewLayout::ViewRemoved(views::View* host, views::View* view) {
-  box_layout_->ViewRemoved(host, view);
-}
-
-std::unique_ptr<views::LayoutManager>
-ThreeViewLayout::CreateDefaultLayoutManager(Orientation orientation) const {
-  views::BoxLayout* box_layout =
-      new views::BoxLayout(GetOrientation(orientation), 0, 0, 0);
-  box_layout->set_main_axis_alignment(
-      views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
-  box_layout->set_cross_axis_alignment(
-      views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
-  return std::unique_ptr<views::LayoutManager>(box_layout);
-}
-
-views::View* ThreeViewLayout::GetContainer(Container container) const {
-  switch (container) {
-    case Container::START:
-      return start_container_;
-    case Container::CENTER:
-      return center_container_;
-    case Container::END:
-      return end_container_;
-  }
-  // Required for some compilers.
-  NOTREACHED();
-  return nullptr;
-}
-
-SizeRangeLayout* ThreeViewLayout::GetLayoutManager(Container container) const {
-  switch (container) {
-    case Container::START:
-      return start_container_layout_manager_;
-    case Container::CENTER:
-      return center_container_layout_manager_;
-    case Container::END:
-      return end_container_layout_manager_;
-  }
-  // Required for some compilers.
-  NOTREACHED();
-  return nullptr;
-}
-
-}  // namespace ash
diff --git a/ash/common/system/tray/three_view_layout.h b/ash/common/system/tray/three_view_layout.h
deleted file mode 100644
index 7f840f4..0000000
--- a/ash/common/system/tray/three_view_layout.h
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_COMMON_SYSTEM_TRAY_THREE_VIEW_LAYOUT_H_
-#define ASH_COMMON_SYSTEM_TRAY_THREE_VIEW_LAYOUT_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "base/macros.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/views/layout/layout_manager.h"
-
-namespace views {
-class Border;
-class BoxLayout;
-class View;
-}  // namespace views
-
-namespace ash {
-class SizeRangeLayout;
-
-// A layout manager that has 3 child containers (START, CENTER, END) which can
-// be arranged vertically or horizontally. The child containers can have
-// minimum and/or maximum preferred size defined as well as a flex weight that
-// is used to distribute excess space across the main axis, i.e. flexible width
-// for the horizontal orientation. By default all the containers have a flex
-// weight of 0, meaning no flexibility, and no minimum or maximum size.
-//
-// Views are laid out within each container as per the LayoutManager that has
-// been installed on that container. By default a BoxLayout manager is installed
-// on each container with the same orientation as |this| has been created with.
-// The default BoxLayout will use a center alignment for both the main axis and
-// cross axis alignment.
-class ASH_EXPORT ThreeViewLayout : public views::LayoutManager {
- public:
-  enum class Orientation {
-    HORIZONTAL,
-    VERTICAL,
-  };
-
-  // The different containers that child Views can be added to.
-  enum class Container { START, CENTER, END };
-
-  // Constructs a layout with horizontal orientation and 0 padding between
-  // containers.
-  ThreeViewLayout();
-
-  // Constructs a layout with Horizontal orientation and the specified padding
-  // between containers.
-  //
-  // TODO(bruthig): The |padding_between_containers| can only be set on
-  // BoxLayouts during construction. Investigate whether this can be a mutable
-  // property of BoxLayouts and if so consider dropping it as a constructor
-  // parameter here.
-  explicit ThreeViewLayout(int padding_between_containers);
-
-  // Constructs a layout with the specified orientation and 0 padding between
-  // containers.
-  explicit ThreeViewLayout(Orientation orientation);
-
-  // Constructs a layout with the specified orientation and padding between
-  // containers.
-  ThreeViewLayout(Orientation orientation, int padding_between_containers);
-
-  ~ThreeViewLayout() override;
-
-  // Set the minimum cross axis size for the layout, i.e. the minimum height for
-  // a horizontal orientation.
-  void SetMinCrossAxisSize(int min_size);
-
-  // Set the minimum size for the given |container|.
-  void SetMinSize(Container container, const gfx::Size& size);
-
-  // Set the maximum size for the given |container|.
-  void SetMaxSize(Container container, const gfx::Size& size);
-
-  // Adds the child |view| to the specified |container|.
-  void AddView(Container container, views::View* view);
-
-  // Removes all current children from the specified |container| and adds the
-  // child |view| to it.
-  void SetView(Container container, views::View* view);
-
-  // During layout the |insets| are applied to the host views entire space
-  // before allocating the remaining space to the container views.
-  void SetInsets(const gfx::Insets& insets);
-
-  // Sets the border for the given |container|.
-  void SetBorder(Container container, std::unique_ptr<views::Border> border);
-
-  // Sets wither the |container| is visible. During a layout the space will be
-  // allocated to the visible containers only. i.e. non-visible containers will
-  // not be allocated any space.
-  void SetContainerVisible(Container container, bool visible);
-
-  // Sets the flex weight for the given |container|. Using the preferred size as
-  // the basis, free space along the main axis is distributed to views in the
-  // ratio of their flex weights. Similarly, if the views will overflow the
-  // parent, space is subtracted in these ratios.
-  //
-  // A flex of 0 means this view is not resized. Flex values must not be
-  // negative.
-  //
-  // Note that non-zero flex values will take precedence over size constraints.
-  // i.e. even if |container| has a max size set the space allocated during
-  // layout may be larger if |flex| > 0 and similar for min size constraints.
-  void SetFlexForContainer(Container container, int flex);
-
-  // Sets the |layout_manager| used by the given |container|.
-  void SetLayoutManager(Container container,
-                        std::unique_ptr<LayoutManager> layout_manager);
-
-  // LayoutManager:
-  void Installed(views::View* host) override;
-  void Layout(views::View* host) override;
-  gfx::Size GetPreferredSize(const views::View* host) const override;
-  int GetPreferredHeightForWidth(const views::View* host,
-                                 int width) const override;
-  void ViewAdded(views::View* host, views::View* view) override;
-  void ViewRemoved(views::View* host, views::View* view) override;
-
- private:
-  friend class ThreeViewLayoutTest;
-
-  // Creates a default LayoutManager for the given |orientation|.
-  std::unique_ptr<views::LayoutManager> CreateDefaultLayoutManager(
-      Orientation orientation) const;
-
-  // Returns the View for the given |container|.
-  views::View* GetContainer(Container container) const;
-
-  // Returns the layout manager for the given |container|.
-  SizeRangeLayout* GetLayoutManager(Container container) const;
-
-  // The layout manager that lays out the different Container Views.
-  std::unique_ptr<views::BoxLayout> box_layout_;
-
-  // The host View that this layout manager has been installed on.
-  views::View* host_ = nullptr;
-
-  views::View* start_container_ = nullptr;
-  SizeRangeLayout* start_container_layout_manager_ = nullptr;
-
-  views::View* center_container_ = nullptr;
-  SizeRangeLayout* center_container_layout_manager_ = nullptr;
-
-  views::View* end_container_ = nullptr;
-  SizeRangeLayout* end_container_layout_manager_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreeViewLayout);
-};
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_SYSTEM_TRAY_THREE_VIEW_LAYOUT_H_
diff --git a/ash/common/system/tray/three_view_layout_unittest.cc b/ash/common/system/tray/three_view_layout_unittest.cc
deleted file mode 100644
index 3790eef7..0000000
--- a/ash/common/system/tray/three_view_layout_unittest.cc
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/common/system/tray/three_view_layout.h"
-#include "base/memory/ptr_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/views/test/test_layout_manager.h"
-#include "ui/views/test/test_views.h"
-#include "ui/views/view.h"
-
-namespace ash {
-
-class ThreeViewLayoutTest : public testing::Test {
- public:
-  ThreeViewLayoutTest();
-
- protected:
-  // Returns the bounds of |child| in the coordinate space of |host_|.
-  gfx::Rect GetBoundsInHost(const views::View* child) const;
-
-  // Wrapper functions to access the internals of |layout_|.
-  views::View* GetContainer(ThreeViewLayout::Container container) const;
-
-  // The test target.
-  ThreeViewLayout* layout_;
-
-  // The View that the test target is installed on.
-  std::unique_ptr<views::View> host_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ThreeViewLayoutTest);
-};
-
-ThreeViewLayoutTest::ThreeViewLayoutTest()
-    : layout_(new ThreeViewLayout()), host_(new views::View) {
-  host_->SetLayoutManager(layout_);
-}
-
-gfx::Rect ThreeViewLayoutTest::GetBoundsInHost(const views::View* child) const {
-  gfx::RectF rect_f(child->bounds());
-  views::View::ConvertRectToTarget(child, host_.get(), &rect_f);
-  return ToNearestRect(rect_f);
-}
-
-views::View* ThreeViewLayoutTest::GetContainer(
-    ThreeViewLayout::Container container) const {
-  return layout_->GetContainer(container);
-}
-
-// Confirms there are no crashes when destroying the host view before the layout
-// manager.
-TEST_F(ThreeViewLayoutTest, SafeDestruction) {
-  views::View* child_view = new views::View();
-  layout_->AddView(ThreeViewLayout::Container::END, child_view);
-  host_.reset();
-}
-
-TEST_F(ThreeViewLayoutTest, PaddingBetweenContainers) {
-  const int kPaddingBetweenContainers = 3;
-  const int kViewWidth = 10;
-  const int kViewHeight = 10;
-  const gfx::Size kViewSize(kViewWidth, kViewHeight);
-  const int kStartChildExpectedX = 0;
-  const int kCenterChildExpectedX =
-      kStartChildExpectedX + kViewWidth + kPaddingBetweenContainers;
-  const int kEndChildExpectedX =
-      kCenterChildExpectedX + kViewWidth + kPaddingBetweenContainers;
-  layout_ = new ThreeViewLayout(kPaddingBetweenContainers);
-  host_->SetLayoutManager(layout_);
-
-  host_->SetBounds(0, 0, 100, 10);
-  views::View* start_child = new views::StaticSizedView(kViewSize);
-  views::View* center_child = new views::StaticSizedView(kViewSize);
-  views::View* end_child = new views::StaticSizedView(kViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  host_->Layout();
-
-  EXPECT_EQ(kStartChildExpectedX, GetBoundsInHost(start_child).x());
-  EXPECT_EQ(kCenterChildExpectedX, GetBoundsInHost(center_child).x());
-  EXPECT_EQ(kEndChildExpectedX, GetBoundsInHost(end_child).x());
-}
-
-TEST_F(ThreeViewLayoutTest, VerticalOrientation) {
-  const int kViewWidth = 10;
-  const int kViewHeight = 10;
-  const gfx::Size kViewSize(kViewWidth, kViewHeight);
-
-  layout_ = new ThreeViewLayout(ThreeViewLayout::Orientation::VERTICAL);
-  host_->SetLayoutManager(layout_);
-
-  host_->SetBounds(0, 0, 10, 100);
-  views::View* start_child = new views::StaticSizedView(kViewSize);
-  views::View* center_child = new views::StaticSizedView(kViewSize);
-  views::View* end_child = new views::StaticSizedView(kViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  host_->Layout();
-
-  EXPECT_EQ(0, GetBoundsInHost(start_child).y());
-  EXPECT_EQ(kViewWidth, GetBoundsInHost(center_child).y());
-  EXPECT_EQ(kViewWidth * 2, GetBoundsInHost(end_child).y());
-}
-
-TEST_F(ThreeViewLayoutTest, ContainerViewsRemovedFromHost) {
-  EXPECT_NE(0, host_->child_count());
-  host_->SetLayoutManager(nullptr);
-  EXPECT_EQ(0, host_->child_count());
-}
-
-TEST_F(ThreeViewLayoutTest, MinCrossAxisSize) {
-  const int kMinCrossAxisSize = 15;
-  EXPECT_EQ(0, layout_->GetPreferredSize(host_.get()).height());
-  layout_->SetMinCrossAxisSize(kMinCrossAxisSize);
-  EXPECT_EQ(kMinCrossAxisSize, layout_->GetPreferredSize(host_.get()).height());
-  EXPECT_EQ(kMinCrossAxisSize,
-            layout_->GetPreferredHeightForWidth(host_.get(), 0));
-}
-
-TEST_F(ThreeViewLayoutTest, MainAxisMinSize) {
-  host_->SetBounds(0, 0, 100, 10);
-  const gfx::Size kMinSize(15, 10);
-  layout_->SetMinSize(ThreeViewLayout::Container::START, kMinSize);
-  views::View* child = new views::StaticSizedView(gfx::Size(10, 10));
-  layout_->AddView(ThreeViewLayout::Container::CENTER, child);
-  host_->Layout();
-
-  EXPECT_EQ(kMinSize.width(), GetBoundsInHost(child).x());
-}
-
-TEST_F(ThreeViewLayoutTest, MainAxisMaxSize) {
-  host_->SetBounds(0, 0, 100, 10);
-  const gfx::Size kMaxSize(10, 10);
-
-  layout_->SetMaxSize(ThreeViewLayout::Container::START, kMaxSize);
-  views::View* start_child = new views::StaticSizedView(gfx::Size(20, 20));
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-
-  views::View* center_child = new views::StaticSizedView(gfx::Size(10, 10));
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-
-  host_->Layout();
-
-  EXPECT_EQ(kMaxSize.width(), GetBoundsInHost(center_child).x());
-}
-
-TEST_F(ThreeViewLayoutTest, ViewsAddedToCorrectContainers) {
-  views::View* start_child = new views::StaticSizedView();
-  views::View* center_child = new views::StaticSizedView();
-  views::View* end_child = new views::StaticSizedView();
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::START)->Contains(start_child));
-  EXPECT_EQ(1, GetContainer(ThreeViewLayout::Container::START)->child_count());
-
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::CENTER)->Contains(center_child));
-  EXPECT_EQ(1, GetContainer(ThreeViewLayout::Container::CENTER)->child_count());
-
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::END)->Contains(end_child));
-  EXPECT_EQ(1, GetContainer(ThreeViewLayout::Container::END)->child_count());
-}
-
-TEST_F(ThreeViewLayoutTest, MultipleViewsAddedToTheSameContainer) {
-  views::View* child1 = new views::StaticSizedView();
-  views::View* child2 = new views::StaticSizedView();
-
-  layout_->AddView(ThreeViewLayout::Container::START, child1);
-  layout_->AddView(ThreeViewLayout::Container::START, child2);
-
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::START)->Contains(child1));
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::START)->Contains(child2));
-}
-
-TEST_F(ThreeViewLayoutTest, ViewsRemovedOnSetViewToTheSameContainer) {
-  views::View* child1 = new views::StaticSizedView();
-  views::View* child2 = new views::StaticSizedView();
-
-  layout_->AddView(ThreeViewLayout::Container::START, child1);
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::START)->Contains(child1));
-
-  layout_->SetView(ThreeViewLayout::Container::START, child2);
-  EXPECT_TRUE(
-      GetContainer(ThreeViewLayout::Container::START)->Contains(child2));
-  EXPECT_EQ(1, GetContainer(ThreeViewLayout::Container::START)->child_count());
-}
-
-TEST_F(ThreeViewLayoutTest, Insets) {
-  const int kInset = 3;
-  const int kViewHeight = 10;
-  const int kExpectedViewHeight = kViewHeight - 2 * kInset;
-  const gfx::Size kStartViewSize(10, kViewHeight);
-  const gfx::Size kCenterViewSize(100, kViewHeight);
-  const gfx::Size kEndViewSize(10, kViewHeight);
-  const int kHostWidth = 100;
-
-  host_->SetBounds(0, 0, kHostWidth, kViewHeight);
-  layout_->SetInsets(gfx::Insets(kInset));
-  views::View* start_child = new views::StaticSizedView(kStartViewSize);
-  views::View* center_child = new views::StaticSizedView(kCenterViewSize);
-  views::View* end_child = new views::StaticSizedView(kEndViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  layout_->SetFlexForContainer(ThreeViewLayout::Container::CENTER, 1.f);
-  host_->Layout();
-
-  EXPECT_EQ(
-      gfx::Rect(kInset, kInset, kStartViewSize.width(), kExpectedViewHeight),
-      GetBoundsInHost(start_child));
-  EXPECT_EQ(gfx::Rect(kInset + kStartViewSize.width(), kInset,
-                      kHostWidth - kStartViewSize.width() -
-                          kEndViewSize.width() - 2 * kInset,
-                      kExpectedViewHeight),
-            GetBoundsInHost(center_child));
-  EXPECT_EQ(gfx::Rect(kHostWidth - kEndViewSize.width() - kInset, kInset,
-                      kEndViewSize.width(), kExpectedViewHeight),
-            GetBoundsInHost(end_child));
-}
-
-TEST_F(ThreeViewLayoutTest, InvisibleContainerDoesntTakeUpSpace) {
-  const int kViewWidth = 10;
-  const int kViewHeight = 10;
-  const gfx::Size kViewSize(kViewWidth, kViewHeight);
-
-  host_->SetBounds(0, 0, 30, 10);
-  views::View* start_child = new views::StaticSizedView(kViewSize);
-  views::View* center_child = new views::StaticSizedView(kViewSize);
-  views::View* end_child = new views::StaticSizedView(kViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  layout_->SetContainerVisible(ThreeViewLayout::Container::START, false);
-  host_->Layout();
-
-  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), GetBoundsInHost(start_child));
-  EXPECT_EQ(0, GetBoundsInHost(center_child).x());
-  EXPECT_EQ(kViewWidth, GetBoundsInHost(end_child).x());
-
-  layout_->SetContainerVisible(ThreeViewLayout::Container::START, true);
-  host_->Layout();
-
-  EXPECT_EQ(0, GetBoundsInHost(start_child).x());
-  EXPECT_EQ(kViewWidth, GetBoundsInHost(center_child).x());
-  EXPECT_EQ(kViewWidth * 2, GetBoundsInHost(end_child).x());
-}
-
-TEST_F(ThreeViewLayoutTest, NonZeroFlex) {
-  const int kHostWidth = 100;
-  const gfx::Size kDefaultViewSize(10, 10);
-  const gfx::Size kCenterViewSize(100, 10);
-  const gfx::Size kExpectedCenterViewSize(
-      kHostWidth - 2 * kDefaultViewSize.width(), 10);
-  host_->SetBounds(0, 0, kHostWidth, 10);
-  views::View* start_child = new views::StaticSizedView(kDefaultViewSize);
-  views::View* center_child = new views::StaticSizedView(kCenterViewSize);
-  views::View* end_child = new views::StaticSizedView(kDefaultViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  layout_->SetFlexForContainer(ThreeViewLayout::Container::CENTER, 1.f);
-  host_->Layout();
-
-  EXPECT_EQ(kDefaultViewSize, GetBoundsInHost(start_child).size());
-  EXPECT_EQ(kExpectedCenterViewSize, GetBoundsInHost(center_child).size());
-  EXPECT_EQ(kDefaultViewSize, GetBoundsInHost(end_child).size());
-}
-
-TEST_F(ThreeViewLayoutTest, NonZeroFlexTakesPrecedenceOverMinSize) {
-  const int kHostWidth = 25;
-  const gfx::Size kViewSize(10, 10);
-  const gfx::Size kMinCenterSize = kViewSize;
-  const gfx::Size kExpectedCenterSize(kHostWidth - 2 * kViewSize.width(), 10);
-  host_->SetBounds(0, 0, kHostWidth, 10);
-  views::View* start_child = new views::StaticSizedView(kViewSize);
-  views::View* center_child = new views::StaticSizedView(kViewSize);
-  views::View* end_child = new views::StaticSizedView(kViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  layout_->SetFlexForContainer(ThreeViewLayout::Container::CENTER, 1.f);
-  layout_->SetMinSize(ThreeViewLayout::Container::CENTER, kMinCenterSize);
-  host_->Layout();
-
-  EXPECT_EQ(kViewSize, GetBoundsInHost(start_child).size());
-  EXPECT_EQ(
-      kExpectedCenterSize,
-      GetBoundsInHost(GetContainer(ThreeViewLayout::Container::CENTER)).size());
-  EXPECT_EQ(kViewSize, GetBoundsInHost(end_child).size());
-}
-
-TEST_F(ThreeViewLayoutTest, NonZeroFlexTakesPrecedenceOverMaxSize) {
-  const int kHostWidth = 100;
-  const gfx::Size kViewSize(10, 10);
-  const gfx::Size kMaxCenterSize(20, 10);
-  const gfx::Size kExpectedCenterSize(kHostWidth - 2 * kViewSize.width(), 10);
-  host_->SetBounds(0, 0, kHostWidth, 10);
-  views::View* start_child = new views::StaticSizedView(kViewSize);
-  views::View* center_child = new views::StaticSizedView(kViewSize);
-  views::View* end_child = new views::StaticSizedView(kViewSize);
-
-  layout_->AddView(ThreeViewLayout::Container::START, start_child);
-  layout_->AddView(ThreeViewLayout::Container::CENTER, center_child);
-  layout_->AddView(ThreeViewLayout::Container::END, end_child);
-
-  layout_->SetFlexForContainer(ThreeViewLayout::Container::CENTER, 1.f);
-  layout_->SetMaxSize(ThreeViewLayout::Container::CENTER, kMaxCenterSize);
-  host_->Layout();
-
-  EXPECT_EQ(kViewSize, GetBoundsInHost(start_child).size());
-  EXPECT_EQ(
-      kExpectedCenterSize,
-      GetBoundsInHost(GetContainer(ThreeViewLayout::Container::CENTER)).size());
-  EXPECT_EQ(kViewSize, GetBoundsInHost(end_child).size());
-}
-
-}  // namespace ash
diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc
index 489ff1c..c8718cc 100644
--- a/ash/common/system/tray/tray_constants.cc
+++ b/ash/common/system/tray/tray_constants.cc
@@ -97,14 +97,6 @@
   const int kTraySpacing[] = {4, 4, 0};
   const int kTrayPaddingFromEdgeOfShelf[] = {3, 3, 4};
   const int kTrayPopupItemHeight[] = {46, 46, 48};
-  // TODO(bruthig): Use the correct values for non-material design.
-  const int kTrayPopupItemLeftInset[] = {0, 0, 4};
-  // TODO(bruthig): Use the correct values for non-material design.
-  const int kTrayPopupItemRightInset[] = {0, 0, 4};
-  // TODO(bruthig): Use the correct values for non-material design.
-  const int kTrayPopupItemMinStartWidth[] = {48, 48, 48};
-  // TODO(bruthig): Use the correct values for non-material design.
-  const int kTrayPopupItemMinEndWidth[] = {48, 48, 48};
   const int kVirtualKeyboardButtonSize[] = {39, 39, kTrayItemSize};
   const int kTrayImeMenuIcon[] = {40, 40, kTrayItemSize};
   const int kTrayImageItemPadding[] = {1, 1, 3};
@@ -122,14 +114,6 @@
       return kTrayPaddingFromEdgeOfShelf[mode];
     case TRAY_POPUP_ITEM_HEIGHT:
       return kTrayPopupItemHeight[mode];
-    case TRAY_POPUP_ITEM_LEFT_INSET:
-      return kTrayPopupItemLeftInset[mode];
-    case TRAY_POPUP_ITEM_RIGHT_INSET:
-      return kTrayPopupItemRightInset[mode];
-    case TRAY_POPUP_ITEM_MIN_START_WIDTH:
-      return kTrayPopupItemMinStartWidth[mode];
-    case TRAY_POPUP_ITEM_MIN_END_WIDTH:
-      return kTrayPopupItemMinEndWidth[mode];
     case VIRTUAL_KEYBOARD_BUTTON_SIZE:
       return kVirtualKeyboardButtonSize[mode];
     case TRAY_IME_MENU_ICON:
diff --git a/ash/common/system/tray/tray_constants.h b/ash/common/system/tray/tray_constants.h
index b739d6a..3282ba7 100644
--- a/ash/common/system/tray/tray_constants.h
+++ b/ash/common/system/tray/tray_constants.h
@@ -115,18 +115,6 @@
   // The height of the rows in the system tray menu.
   TRAY_POPUP_ITEM_HEIGHT,
 
-  // The left inset for all tray system menu rows.
-  TRAY_POPUP_ITEM_LEFT_INSET,
-
-  // The right inset for all tray system menu rows.
-  TRAY_POPUP_ITEM_RIGHT_INSET,
-
-  // The minimum default width for the left container of the system menu rows.
-  TRAY_POPUP_ITEM_MIN_START_WIDTH,
-
-  // The minimum default width for the right container of the system menu rows.
-  TRAY_POPUP_ITEM_MIN_END_WIDTH,
-
   // The width and height of the virtual keyboard button in the status tray
   // area. For non-MD, adjustments are made to the button dimensions based on
   // the shelf orientation, so this constant does not specify the true
diff --git a/ash/common/system/tray/tray_popup_layout_factory.cc b/ash/common/system/tray/tray_popup_layout_factory.cc
deleted file mode 100644
index 816843e..0000000
--- a/ash/common/system/tray/tray_popup_layout_factory.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/common/system/tray/tray_popup_layout_factory.h"
-
-#include "ash/common/material_design/material_design_controller.h"
-#include "ash/common/system/tray/three_view_layout.h"
-#include "ash/common/system/tray/tray_constants.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/layout/box_layout.h"
-
-namespace ash {
-
-namespace {
-
-// Creates a layout manager that positions Views vertically. The Views will be
-// stretched horizontally and centered vertically.
-std::unique_ptr<views::LayoutManager> CreateDefaultCenterLayoutManager() {
-  // TODO(bruthig): Use constants instead of magic numbers.
-  views::BoxLayout* box_layout =
-      new views::BoxLayout(views::BoxLayout::kVertical, 4, 8, 4);
-  box_layout->set_main_axis_alignment(
-      views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
-  box_layout->set_cross_axis_alignment(
-      views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
-  return std::unique_ptr<views::LayoutManager>(box_layout);
-}
-
-// Creates a layout manager that positions Views horizontally. The Views will be
-// centered along the horizontal and vertical axis.
-std::unique_ptr<views::LayoutManager> CreateDefaultEndsLayoutManager() {
-  views::BoxLayout* box_layout =
-      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
-  box_layout->set_main_axis_alignment(
-      views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
-  box_layout->set_cross_axis_alignment(
-      views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
-  return std::unique_ptr<views::LayoutManager>(box_layout);
-}
-
-}  // namespace
-
-ThreeViewLayout* TrayPopupLayoutFactory::InstallDefaultLayout(
-    views::View* host) {
-  ThreeViewLayout* layout = new ThreeViewLayout(0 /* padding_between_items */);
-
-  // TODO(bruthig): views::BoxLayout::SetFlexForView() fails on a DCHECK() if it
-  // has not yet been installed on a View. Evaluate whether this is necessary or
-  // if it can be removed. This would allow us to drop the |host| parameter from
-  // this function.
-  host->SetLayoutManager(layout);
-
-  layout->SetInsets(gfx::Insets(0, GetTrayConstant(TRAY_POPUP_ITEM_LEFT_INSET),
-                                0,
-                                GetTrayConstant(TRAY_POPUP_ITEM_RIGHT_INSET)));
-  layout->SetMinCrossAxisSize(GetTrayConstant(TRAY_POPUP_ITEM_HEIGHT));
-
-  ConfigureDefaultLayout(layout, ThreeViewLayout::Container::START);
-  ConfigureDefaultLayout(layout, ThreeViewLayout::Container::CENTER);
-  ConfigureDefaultLayout(layout, ThreeViewLayout::Container::END);
-
-  return layout;
-}
-
-void TrayPopupLayoutFactory::ConfigureDefaultLayout(
-    ThreeViewLayout* layout,
-    ThreeViewLayout::Container container) {
-  switch (container) {
-    case ThreeViewLayout::Container::START:
-      layout->SetLayoutManager(ThreeViewLayout::Container::START,
-                               CreateDefaultEndsLayoutManager());
-      layout->SetMinSize(
-          ThreeViewLayout::Container::START,
-          gfx::Size(GetTrayConstant(TRAY_POPUP_ITEM_MIN_START_WIDTH), 0));
-      break;
-    case ThreeViewLayout::Container::CENTER:
-      layout->SetLayoutManager(ThreeViewLayout::Container::CENTER,
-                               CreateDefaultCenterLayoutManager());
-      layout->SetFlexForContainer(ThreeViewLayout::Container::CENTER, 1.f);
-      break;
-    case ThreeViewLayout::Container::END:
-      layout->SetLayoutManager(ThreeViewLayout::Container::END,
-                               CreateDefaultEndsLayoutManager());
-      layout->SetMinSize(
-          ThreeViewLayout::Container::END,
-          gfx::Size(GetTrayConstant(TRAY_POPUP_ITEM_MIN_END_WIDTH), 0));
-      break;
-  }
-}
-
-}  // namespace ash
diff --git a/ash/common/system/tray/tray_popup_layout_factory.h b/ash/common/system/tray/tray_popup_layout_factory.h
deleted file mode 100644
index 5e5669eb..0000000
--- a/ash/common/system/tray/tray_popup_layout_factory.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LAYOUT_FACTORY_H_
-#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LAYOUT_FACTORY_H_
-
-#include <memory>
-
-#include "ash/common/system/tray/three_view_layout.h"
-#include "base/macros.h"
-
-namespace views {
-class View;
-}  // namespace views
-
-namespace ash {
-
-// Factory functions for system menu row layout managers.
-class TrayPopupLayoutFactory {
- public:
-  // Sets the layout manager of |host| to the default layout manager used by
-  // most system menu rows. The newly created layout manager is owned by the
-  // |host| but is returned so child Views can be added.
-  //
-  // The returned layout manager consists of 3 regions: START, CENTER, and END.
-  // Any child Views added to the START and END containers will be added
-  // horizonatlly and any Views added to the CENTER container will be added
-  // vertically.
-  //
-  // The START and END containers have a fixed width but can grow into the
-  // CENTER container if space is required and available.
-  //
-  // The CENTER container has a flexible width.
-  static ThreeViewLayout* InstallDefaultLayout(views::View* host);
-
-  // Configures the different |container| Views with the default layout
-  // managers.
-  //
-  // This can be used by clients who need to embed portions of the default
-  // layout manager into a different container view, e.g. just the END layout
-  // into a clickable View.
-  static void ConfigureDefaultLayout(ThreeViewLayout* layout,
-                                     ThreeViewLayout::Container container);
-
- private:
-  TrayPopupLayoutFactory();
-  ~TrayPopupLayoutFactory();
-
-  DISALLOW_COPY_AND_ASSIGN(TrayPopupLayoutFactory);
-};
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_LAYOUT_FACTORY_H_
diff --git a/ash/common/test/BUILD.gn b/ash/common/test/BUILD.gn
index ec0392e..d47a2a1 100644
--- a/ash/common/test/BUILD.gn
+++ b/ash/common/test/BUILD.gn
@@ -14,6 +14,10 @@
     "test_palette_delegate.h",
     "test_session_state_delegate.cc",
     "test_session_state_delegate.h",
+    "test_shelf_delegate.cc",
+    "test_shelf_delegate.h",
+    "test_shelf_item_delegate.cc",
+    "test_shelf_item_delegate.h",
     "test_system_tray_delegate.cc",
     "test_system_tray_delegate.h",
     "wm_shell_test_api.cc",
diff --git a/ash/test/test_shelf_delegate.cc b/ash/common/test/test_shelf_delegate.cc
similarity index 69%
rename from ash/test/test_shelf_delegate.cc
rename to ash/common/test/test_shelf_delegate.cc
index 068e44c..36d711a 100644
--- a/ash/test/test_shelf_delegate.cc
+++ b/ash/common/test/test_shelf_delegate.cc
@@ -2,22 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/test/test_shelf_delegate.h"
+#include "ash/common/test/test_shelf_delegate.h"
 
 #include <utility>
 
-#include "ash/aura/wm_window_aura.h"
 #include "ash/common/shelf/shelf_model.h"
+#include "ash/common/test/test_shelf_item_delegate.h"
+#include "ash/common/wm_window.h"
 #include "ash/common/wm_window_property.h"
-#include "ash/test/test_shelf_item_delegate.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/aura/window.h"
+#include "base/memory/ptr_util.h"
 
 namespace ash {
 namespace test {
 
-TestShelfDelegate* TestShelfDelegate::instance_ = NULL;
+TestShelfDelegate* TestShelfDelegate::instance_ = nullptr;
 
 TestShelfDelegate::TestShelfDelegate(ShelfModel* model) : model_(model) {
   CHECK(!instance_);
@@ -25,25 +23,23 @@
 }
 
 TestShelfDelegate::~TestShelfDelegate() {
-  instance_ = NULL;
+  instance_ = nullptr;
 }
 
-void TestShelfDelegate::AddShelfItem(aura::Window* window) {
+void TestShelfDelegate::AddShelfItem(WmWindow* window) {
   AddShelfItem(window, STATUS_CLOSED);
 }
 
-void TestShelfDelegate::AddShelfItem(aura::Window* window,
+void TestShelfDelegate::AddShelfItem(WmWindow* window,
                                      const std::string& app_id) {
   AddShelfItem(window, STATUS_CLOSED);
-  WmWindow* wm_window = WmWindowAura::Get(window);
-  ShelfID shelf_id = wm_window->GetIntProperty(WmWindowProperty::SHELF_ID);
+  ShelfID shelf_id = window->GetIntProperty(WmWindowProperty::SHELF_ID);
   AddShelfIDToAppIDMapping(shelf_id, app_id);
 }
 
-void TestShelfDelegate::AddShelfItem(aura::Window* window,
-                                     ShelfItemStatus status) {
+void TestShelfDelegate::AddShelfItem(WmWindow* window, ShelfItemStatus status) {
   ShelfItem item;
-  if (window->type() == ui::wm::WINDOW_TYPE_PANEL)
+  if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL)
     item.type = TYPE_APP_PANEL;
   else
     item.type = TYPE_PLATFORM_APP;
@@ -52,15 +48,13 @@
   model_->Add(item);
   window->AddObserver(this);
 
-  std::unique_ptr<ShelfItemDelegate> delegate(
-      new TestShelfItemDelegate(window));
-  model_->SetShelfItemDelegate(id, std::move(delegate));
-  WmWindowAura::Get(window)->SetIntProperty(WmWindowProperty::SHELF_ID, id);
+  model_->SetShelfItemDelegate(id,
+                               base::MakeUnique<TestShelfItemDelegate>(window));
+  window->SetIntProperty(WmWindowProperty::SHELF_ID, id);
 }
 
-void TestShelfDelegate::RemoveShelfItemForWindow(aura::Window* window) {
-  WmWindow* wm_window = WmWindowAura::Get(window);
-  ShelfID shelf_id = wm_window->GetIntProperty(WmWindowProperty::SHELF_ID);
+void TestShelfDelegate::RemoveShelfItemForWindow(WmWindow* window) {
+  ShelfID shelf_id = window->GetIntProperty(WmWindowProperty::SHELF_ID);
   if (shelf_id == 0)
     return;
   int index = model_->ItemIndexByID(shelf_id);
@@ -76,12 +70,12 @@
   }
 }
 
-void TestShelfDelegate::OnWindowDestroying(aura::Window* window) {
+void TestShelfDelegate::OnWindowDestroying(WmWindow* window) {
   RemoveShelfItemForWindow(window);
 }
 
-void TestShelfDelegate::OnWindowHierarchyChanging(
-    const HierarchyChangeParams& params) {
+void TestShelfDelegate::OnWindowTreeChanging(WmWindow* window,
+                                             const TreeChangeParams& params) {
   // The window may be legitimately reparented while staying open if it moves
   // to another display or container. If the window does not have a new parent
   // then remove the shelf item.
diff --git a/ash/test/test_shelf_delegate.h b/ash/common/test/test_shelf_delegate.h
similarity index 77%
rename from ash/test/test_shelf_delegate.h
rename to ash/common/test/test_shelf_delegate.h
index 7fe5989..575a808f 100644
--- a/ash/test/test_shelf_delegate.h
+++ b/ash/common/test/test_shelf_delegate.h
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_TEST_TEST_SHELF_DELEGATE_H_
-#define ASH_TEST_TEST_SHELF_DELEGATE_H_
+#ifndef ASH_COMMON_TEST_TEST_SHELF_DELEGATE_H_
+#define ASH_COMMON_TEST_TEST_SHELF_DELEGATE_H_
 
 #include <map>
 #include <set>
 #include <string>
 
 #include "ash/common/shelf/shelf_delegate.h"
+#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
-#include "ui/aura/window_observer.h"
 
 namespace ash {
 
@@ -21,33 +21,34 @@
 
 // Test implementation of ShelfDelegate.
 // Tests may create icons for windows by calling AddShelfItem().
-class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver {
+class TestShelfDelegate : public ShelfDelegate, public WmWindowObserver {
  public:
   explicit TestShelfDelegate(ShelfModel* model);
   ~TestShelfDelegate() override;
 
   // Adds a ShelfItem for the given |window|. The ShelfItem's status will be
   // STATUS_CLOSED.
-  void AddShelfItem(aura::Window* window);
+  void AddShelfItem(WmWindow* window);
 
   // Adds a ShelfItem for the given |window| and adds a mapping from the added
   // ShelfItem's ShelfID to the given |app_id|. The ShelfItem's status will be
   // STATUS_CLOSED.
-  void AddShelfItem(aura::Window* window, const std::string& app_id);
+  void AddShelfItem(WmWindow* window, const std::string& app_id);
 
   // Adds a ShelfItem for the given |window| with the specified |status|.
-  void AddShelfItem(aura::Window* window, ShelfItemStatus status);
+  void AddShelfItem(WmWindow* window, ShelfItemStatus status);
 
   // Removes the ShelfItem for the specified |window| and unpins it if it was
   // pinned. The |window|'s ShelfID to app id mapping will be removed if it
   // exists.
-  void RemoveShelfItemForWindow(aura::Window* window);
+  void RemoveShelfItemForWindow(WmWindow* window);
 
   static TestShelfDelegate* instance() { return instance_; }
 
   // WindowObserver implementation
-  void OnWindowDestroying(aura::Window* window) override;
-  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
+  void OnWindowDestroying(WmWindow* window) override;
+  void OnWindowTreeChanging(WmWindow* window,
+                            const TreeChangeParams& params) override;
 
   // ShelfDelegate implementation.
   ShelfID GetShelfIDForAppID(const std::string& app_id) override;
@@ -81,4 +82,4 @@
 }  // namespace test
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_SHELF_DELEGATE_H_
+#endif  // ASH_COMMON_TEST_TEST_SHELF_DELEGATE_H_
diff --git a/ash/common/test/test_shelf_item_delegate.cc b/ash/common/test/test_shelf_item_delegate.cc
new file mode 100644
index 0000000..96916d6
--- /dev/null
+++ b/ash/common/test/test_shelf_item_delegate.cc
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/common/test/test_shelf_item_delegate.h"
+
+#include "ash/common/wm_lookup.h"
+#include "ash/common/wm_window.h"
+#include "ui/events/event.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace test {
+
+namespace {
+
+// Moves |window| to the root window where the |event| occurred.
+// Note: This was forked from ash/wm/window_util.h's wm::MoveWindowToEventRoot.
+void MoveWindowToEventRoot(WmWindow* window, const ui::Event& event) {
+  views::View* target = static_cast<views::View*>(event.target());
+  if (!target)
+    return;
+  WmWindow* target_root =
+      WmLookup::Get()->GetWindowForWidget(target->GetWidget())->GetRootWindow();
+  if (!target_root || target_root == window->GetRootWindow())
+    return;
+  WmWindow* window_container = target_root->GetChildByShellWindowId(
+      window->GetParent()->GetShellWindowId());
+  window_container->AddChild(window);
+}
+
+}  // namespace
+
+TestShelfItemDelegate::TestShelfItemDelegate(WmWindow* window)
+    : window_(window), is_draggable_(true) {}
+
+TestShelfItemDelegate::~TestShelfItemDelegate() {}
+
+ShelfItemDelegate::PerformedAction TestShelfItemDelegate::ItemSelected(
+    const ui::Event& event) {
+  if (window_) {
+    if (window_->GetType() == ui::wm::WINDOW_TYPE_PANEL)
+      MoveWindowToEventRoot(window_, event);
+    window_->Show();
+    window_->Activate();
+    return kExistingWindowActivated;
+  }
+  return kNoAction;
+}
+
+base::string16 TestShelfItemDelegate::GetTitle() {
+  return window_ ? window_->GetTitle() : base::string16();
+}
+
+ShelfMenuModel* TestShelfItemDelegate::CreateApplicationMenu(int event_flags) {
+  return nullptr;
+}
+
+bool TestShelfItemDelegate::IsDraggable() {
+  return is_draggable_;
+}
+
+bool TestShelfItemDelegate::CanPin() const {
+  return true;
+}
+
+bool TestShelfItemDelegate::ShouldShowTooltip() {
+  return true;
+}
+
+void TestShelfItemDelegate::Close() {}
+
+}  // namespace test
+}  // namespace ash
diff --git a/ash/test/test_shelf_item_delegate.h b/ash/common/test/test_shelf_item_delegate.h
similarity index 79%
rename from ash/test/test_shelf_item_delegate.h
rename to ash/common/test/test_shelf_item_delegate.h
index 8db8aeec..adb22c83 100644
--- a/ash/test/test_shelf_item_delegate.h
+++ b/ash/common/test/test_shelf_item_delegate.h
@@ -2,24 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_TEST_TEST_SHELF_ITEM_DELEGATE_H_
-#define ASH_TEST_TEST_SHELF_ITEM_DELEGATE_H_
+#ifndef ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_
+#define ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_
 
 #include "ash/common/shelf/shelf_item_delegate.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 
-namespace aura {
-class Window;
-}
-
 namespace ash {
+
+class WmWindow;
+
 namespace test {
 
 // Test implementation of ShelfItemDelegate.
 class TestShelfItemDelegate : public ShelfItemDelegate {
  public:
-  explicit TestShelfItemDelegate(aura::Window* window);
+  explicit TestShelfItemDelegate(WmWindow* window);
   ~TestShelfItemDelegate() override;
 
   void set_is_draggable(bool is_draggable) { is_draggable_ = is_draggable; }
@@ -35,7 +34,7 @@
   void Close() override;
 
  private:
-  aura::Window* window_;
+  WmWindow* window_;
 
   bool is_draggable_;
 
@@ -45,4 +44,4 @@
 }  // namespace test
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_SHELF_ITEM_DELEGATE_H_
+#endif  // ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/metrics/user_metrics_recorder_unittest.cc b/ash/metrics/user_metrics_recorder_unittest.cc
index c31e2da3..ad120a20 100644
--- a/ash/metrics/user_metrics_recorder_unittest.cc
+++ b/ash/metrics/user_metrics_recorder_unittest.cc
@@ -6,12 +6,13 @@
 
 #include <memory>
 
+#include "ash/aura/wm_window_aura.h"
 #include "ash/common/login_status.h"
 #include "ash/common/shelf/shelf_model.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/test/test_system_tray_delegate.h"
 #include "ash/common/wm_shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/test/user_metrics_recorder_test_api.h"
 #include "base/test/histogram_tester.h"
 #include "ui/aura/window.h"
@@ -196,21 +197,24 @@
   ASSERT_EQ(TYPE_APP_LIST, shelf_items[0].type);
 
   aura::Window* pinned_window_with_app_id_1 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(pinned_window_with_app_id_1, "app_id_1");
+  test_shelf_delegate->AddShelfItem(
+      WmWindowAura::Get(pinned_window_with_app_id_1), "app_id_1");
   test_shelf_delegate->PinAppWithID("app_id_1");
 
   aura::Window* pinned_window_with_app_id_2 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(pinned_window_with_app_id_2, "app_id_2");
+  test_shelf_delegate->AddShelfItem(
+      WmWindowAura::Get(pinned_window_with_app_id_2), "app_id_2");
   test_shelf_delegate->PinAppWithID("app_id_2");
 
   aura::Window* unpinned_window_with_app_id_3 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(unpinned_window_with_app_id_3, "app_id_3");
+  test_shelf_delegate->AddShelfItem(
+      WmWindowAura::Get(unpinned_window_with_app_id_3), "app_id_3");
 
   aura::Window* unpinned_window_4 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(unpinned_window_4);
+  test_shelf_delegate->AddShelfItem(WmWindowAura::Get(unpinned_window_4));
 
   aura::Window* unpinned_window_5 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(unpinned_window_5);
+  test_shelf_delegate->AddShelfItem(WmWindowAura::Get(unpinned_window_5));
 
   user_metrics_recorder_test_api()->RecordPeriodicMetrics();
   histograms().ExpectBucketCount(kAsh_Shelf_NumberOfItems, 5, 1);
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc
index 406be11..bfb3d1e 100644
--- a/ash/shelf/shelf_unittest.cc
+++ b/ash/shelf/shelf_unittest.cc
@@ -9,9 +9,9 @@
 #include "ash/common/shelf/shelf_view.h"
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/common/test/test_shelf_item_delegate.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_item_delegate.h"
 
 namespace ash {
 
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 0051b29..15e7f4c 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -23,7 +23,10 @@
 #include "ash/common/shelf/wm_shelf_observer.h"
 #include "ash/common/system/web_notification/web_notification_tray.h"
 #include "ash/common/test/material_design_controller_test_api.h"
+#include "ash/common/test/test_shelf_delegate.h"
+#include "ash/common/test/test_shelf_item_delegate.h"
 #include "ash/common/test/test_system_tray_delegate.h"
+#include "ash/common/wm_lookup.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
@@ -33,8 +36,6 @@
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/overflow_bubble_view_test_api.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
-#include "ash/test/test_shelf_item_delegate.h"
 #include "ash/test/test_shell_delegate.h"
 #include "base/i18n/rtl.h"
 #include "base/macros.h"
@@ -165,23 +166,21 @@
 };
 
 TEST_F(WmShelfObserverIconTest, AddRemove) {
-  TestShelfDelegate* shelf_delegate = TestShelfDelegate::instance();
-  ASSERT_TRUE(shelf_delegate);
-
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.bounds = gfx::Rect(0, 0, 200, 200);
   params.context = CurrentContext();
+  views::Widget widget;
+  widget.Init(params);
 
-  std::unique_ptr<views::Widget> widget(new views::Widget());
-  widget->Init(params);
-  shelf_delegate->AddShelfItem(widget->GetNativeWindow());
+  TestShelfDelegate::instance()->AddShelfItem(
+      WmLookup::Get()->GetWindowForWidget(&widget));
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   observer()->Reset();
 
-  widget->Show();
-  widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
+  widget.Show();
+  widget.GetNativeWindow()->parent()->RemoveChild(widget.GetNativeWindow());
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   observer()->Reset();
@@ -198,24 +197,22 @@
   WmShelf* second_shelf = second_root->GetRootWindowController()->GetShelf();
   TestWmShelfObserver second_observer(second_shelf);
 
-  TestShelfDelegate* shelf_delegate = TestShelfDelegate::instance();
-  ASSERT_TRUE(shelf_delegate);
-
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.bounds = gfx::Rect(0, 0, 200, 200);
   params.context = CurrentContext();
+  views::Widget widget;
+  widget.Init(params);
 
-  std::unique_ptr<views::Widget> widget(new views::Widget());
-  widget->Init(params);
-  shelf_delegate->AddShelfItem(widget->GetNativeWindow());
+  TestShelfDelegate::instance()->AddShelfItem(
+      WmLookup::Get()->GetWindowForWidget(&widget));
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   EXPECT_TRUE(second_observer.icon_positions_changed());
   observer()->Reset();
   second_observer.Reset();
 
-  widget->GetNativeWindow()->parent()->RemoveChild(widget->GetNativeWindow());
+  widget.GetNativeWindow()->parent()->RemoveChild(widget.GetNativeWindow());
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   EXPECT_TRUE(second_observer.icon_positions_changed());
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 5f9c01e..44fc929 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -13,6 +13,7 @@
 #include "ash/common/palette_delegate.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/system/tray/default_system_tray_delegate.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/default_wallpaper_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
@@ -21,7 +22,6 @@
 #include "ash/shell/example_factory.h"
 #include "ash/shell/toplevel_window.h"
 #include "ash/test/test_keyboard_ui.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/test/BUILD.gn b/ash/test/BUILD.gn
index e485c53..2a50f112 100644
--- a/ash/test/BUILD.gn
+++ b/ash/test/BUILD.gn
@@ -113,10 +113,6 @@
     "test_screenshot_delegate.h",
     "test_session_state_animator.cc",
     "test_session_state_animator.h",
-    "test_shelf_delegate.cc",
-    "test_shelf_delegate.h",
-    "test_shelf_item_delegate.cc",
-    "test_shelf_item_delegate.h",
     "test_shell_delegate.cc",
     "test_shell_delegate.h",
     "test_suite.cc",
diff --git a/ash/test/test_shelf_item_delegate.cc b/ash/test/test_shelf_item_delegate.cc
deleted file mode 100644
index c9c3a394..0000000
--- a/ash/test/test_shelf_item_delegate.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/test/test_shelf_item_delegate.h"
-
-#include "ash/wm/window_util.h"
-#include "ui/aura/window.h"
-
-namespace ash {
-namespace test {
-
-TestShelfItemDelegate::TestShelfItemDelegate(aura::Window* window)
-    : window_(window), is_draggable_(true) {}
-
-TestShelfItemDelegate::~TestShelfItemDelegate() {}
-
-ShelfItemDelegate::PerformedAction TestShelfItemDelegate::ItemSelected(
-    const ui::Event& event) {
-  if (window_) {
-    if (window_->type() == ui::wm::WINDOW_TYPE_PANEL)
-      wm::MoveWindowToEventRoot(window_, event);
-    window_->Show();
-    wm::ActivateWindow(window_);
-    return kExistingWindowActivated;
-  }
-  return kNoAction;
-}
-
-base::string16 TestShelfItemDelegate::GetTitle() {
-  return window_ ? window_->title() : base::string16();
-}
-
-ShelfMenuModel* TestShelfItemDelegate::CreateApplicationMenu(int event_flags) {
-  return nullptr;
-}
-
-bool TestShelfItemDelegate::IsDraggable() {
-  return is_draggable_;
-}
-
-bool TestShelfItemDelegate::CanPin() const {
-  return true;
-}
-
-bool TestShelfItemDelegate::ShouldShowTooltip() {
-  return true;
-}
-
-void TestShelfItemDelegate::Close() {}
-
-}  // namespace test
-}  // namespace ash
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
index 43254dd9..3be0f57b 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test/test_shell_delegate.cc
@@ -15,12 +15,12 @@
 #include "ash/common/palette_delegate.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/test/test_session_state_delegate.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/test/test_system_tray_delegate.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/test/test_keyboard_ui.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/test/test_wallpaper_delegate.h"
 #include "ash/wm/window_util.h"
 #include "base/logging.h"
diff --git a/ash/wm/dock/docked_window_layout_manager_unittest.cc b/ash/wm/dock/docked_window_layout_manager_unittest.cc
index d686e86..b204dd2 100644
--- a/ash/wm/dock/docked_window_layout_manager_unittest.cc
+++ b/ash/wm/dock/docked_window_layout_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/panels/panel_layout_manager.h"
 #include "ash/common/wm/window_resizer.h"
 #include "ash/common/wm/window_state.h"
@@ -17,7 +18,6 @@
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/shelf_view_test_api.h"
 #include "ash/test/shell_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -43,7 +43,6 @@
   void SetUp() override {
     AshTestBase::SetUp();
     UpdateDisplay("600x600");
-    ASSERT_TRUE(test::TestShelfDelegate::instance());
 
     shelf_view_test_.reset(new test::ShelfViewTestAPI(
         GetPrimaryShelf()->GetShelfViewForTesting()));
@@ -64,17 +63,7 @@
   }
 
   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
-    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
-        nullptr, window_type_, 0, bounds);
-    if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) {
-      test::TestShelfDelegate* shelf_delegate =
-          test::TestShelfDelegate::instance();
-      shelf_delegate->AddShelfItem(window);
-      PanelLayoutManager* manager =
-          PanelLayoutManager::Get(WmWindowAura::Get(window));
-      manager->Relayout();
-    }
-    return window;
+    return CreateTestWindowWithDelegate(bounds, nullptr);
   }
 
   aura::Window* CreateTestWindowWithDelegate(
@@ -83,12 +72,9 @@
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         delegate, window_type_, 0, bounds);
     if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) {
-      test::TestShelfDelegate* shelf_delegate =
-          test::TestShelfDelegate::instance();
-      shelf_delegate->AddShelfItem(window);
-      PanelLayoutManager* manager =
-          PanelLayoutManager::Get(WmWindowAura::Get(window));
-      manager->Relayout();
+      WmWindow* wm_window = WmWindowAura::Get(window);
+      test::TestShelfDelegate::instance()->AddShelfItem(wm_window);
+      PanelLayoutManager::Get(wm_window)->Relayout();
     }
     return window;
   }
diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc
index 88d35cfc..c3e56e69 100644
--- a/ash/wm/dock/docked_window_resizer_unittest.cc
+++ b/ash/wm/dock/docked_window_resizer_unittest.cc
@@ -7,6 +7,7 @@
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/dock/docked_window_layout_manager.h"
 #include "ash/common/wm/panels/panel_layout_manager.h"
 #include "ash/common/wm/window_state.h"
@@ -20,7 +21,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/drag_window_resizer.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
@@ -72,12 +72,9 @@
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         &delegate_, window_type_, 0, bounds);
     if (window_type_ == ui::wm::WINDOW_TYPE_PANEL) {
-      test::TestShelfDelegate* shelf_delegate =
-          test::TestShelfDelegate::instance();
-      shelf_delegate->AddShelfItem(window);
-      PanelLayoutManager* manager =
-          PanelLayoutManager::Get(WmWindowAura::Get(window));
-      manager->Relayout();
+      WmWindow* wm_window = WmWindowAura::Get(window);
+      test::TestShelfDelegate::instance()->AddShelfItem(wm_window);
+      PanelLayoutManager::Get(wm_window)->Relayout();
     }
     return window;
   }
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 9b149d5..67bc00c 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/system/tray/system_tray.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/dock/docked_window_layout_manager.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm/mru_window_tracker.h"
@@ -36,7 +37,6 @@
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/shelf_view_test_api.h"
 #include "ash/test/shell_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
@@ -117,7 +117,6 @@
 
   void SetUp() override {
     test::AshTestBase::SetUp();
-    ASSERT_TRUE(test::TestShelfDelegate::instance());
 
     shelf_view_test_.reset(new test::ShelfViewTestAPI(
         GetPrimaryShelf()->GetShelfViewForTesting()));
@@ -168,7 +167,8 @@
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         nullptr, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
     window->SetProperty(aura::client::kTopViewInset, kHeaderHeight);
-    test::TestShelfDelegate::instance()->AddShelfItem(window);
+    test::TestShelfDelegate::instance()->AddShelfItem(
+        WmWindowAura::Get(window));
     shelf_view_test()->RunMessageLoopUntilAnimationsDone();
     return window;
   }
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index d2106b1b..bc7cda0be 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/system/web_notification/web_notification_tray.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/mru_window_tracker.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_root_window_controller.h"
@@ -25,7 +26,6 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
@@ -72,7 +72,6 @@
 
   void SetUp() override {
     test::AshTestBase::SetUp();
-    ASSERT_TRUE(test::TestShelfDelegate::instance());
 
     shelf_view_test_.reset(new test::ShelfViewTestAPI(
         GetPrimaryShelf()->GetShelfViewForTesting()));
@@ -95,9 +94,8 @@
                                               const gfx::Rect& bounds) {
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
-    test::TestShelfDelegate* shelf_delegate =
-        test::TestShelfDelegate::instance();
-    shelf_delegate->AddShelfItem(window);
+    test::TestShelfDelegate::instance()->AddShelfItem(
+        WmWindowAura::Get(window));
     shelf_view_test()->RunMessageLoopUntilAnimationsDone();
     return window;
   }
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc
index e0deeee..8b71a15 100644
--- a/ash/wm/panels/panel_window_resizer_unittest.cc
+++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -9,6 +9,7 @@
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm/wm_event.h"
 #include "ash/common/wm_shell.h"
@@ -19,7 +20,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/drag_window_resizer.h"
 #include "ash/wm/window_state_aura.h"
 #include "base/i18n/rtl.h"
@@ -42,7 +42,6 @@
     AshTestBase::SetUp();
     UpdateDisplay("600x400");
     model_ = WmShell::Get()->shelf_model();
-    shelf_delegate_ = test::TestShelfDelegate::instance();
   }
 
   void TearDown() override { AshTestBase::TearDown(); }
@@ -61,7 +60,8 @@
     gfx::Rect bounds(origin, gfx::Size(101, 101));
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         NULL, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
-    shelf_delegate_->AddShelfItem(window);
+    test::TestShelfDelegate::instance()->AddShelfItem(
+        WmWindowAura::Get(window));
     return window;
   }
 
@@ -176,7 +176,6 @@
  private:
   std::unique_ptr<WindowResizer> resizer_;
   ShelfModel* model_;
-  test::TestShelfDelegate* shelf_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTest);
 };
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc
index 2efc376..e879592 100644
--- a/ash/wm/system_gesture_event_filter_unittest.cc
+++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -17,7 +17,6 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/shell_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/window_state_aura.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index 4851c26a..28ca6b1c 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/window_cycle_list.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm/wm_event.h"
@@ -21,7 +22,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/test/test_shell_delegate.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
@@ -84,7 +84,6 @@
 
   void SetUp() override {
     test::AshTestBase::SetUp();
-    ASSERT_TRUE(test::TestShelfDelegate::instance());
 
     WindowCycleList::DisableInitialDelayForTesting();
 
@@ -97,7 +96,8 @@
     gfx::Rect rect(100, 100);
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         NULL, ui::wm::WINDOW_TYPE_PANEL, 0, rect);
-    test::TestShelfDelegate::instance()->AddShelfItem(window);
+    test::TestShelfDelegate::instance()->AddShelfItem(
+        WmWindowAura::Get(window));
     shelf_view_test_->RunMessageLoopUntilAnimationsDone();
     return window;
   }
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index cdbd7f2..80915c6 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -11,6 +11,7 @@
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/system/status_area_widget.h"
+#include "ash/common/test/test_shelf_delegate.h"
 #include "ash/common/wm/panels/panel_layout_manager.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm/workspace/workspace_window_resizer.h"
@@ -19,7 +20,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_md_test_base.h"
 #include "ash/test/shell_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -121,12 +121,9 @@
                                 const gfx::Rect& bounds) {
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
-    test::TestShelfDelegate* shelf_delegate =
-        test::TestShelfDelegate::instance();
-    shelf_delegate->AddShelfItem(window);
-    PanelLayoutManager* manager =
-        PanelLayoutManager::Get(WmWindowAura::Get(window));
-    manager->Relayout();
+    WmWindow* wm_window = WmWindowAura::Get(window);
+    test::TestShelfDelegate::instance()->AddShelfItem(wm_window);
+    PanelLayoutManager::Get(wm_window)->Relayout();
     return window;
   }
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index b718962..0fb3efe 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2322,7 +2322,6 @@
       "android/java/src/org/chromium/base/library_loader/ModernLinker.java",
       "android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java",
       "android/java/src/org/chromium/base/library_loader/ProcessInitException.java",
-      "android/java/src/org/chromium/base/metrics/CachedMetrics.java",
       "android/java/src/org/chromium/base/metrics/RecordHistogram.java",
       "android/java/src/org/chromium/base/metrics/RecordUserAction.java",
       "android/java/src/org/chromium/base/metrics/StatisticsRecorderAndroid.java",
diff --git a/base/android/java/src/org/chromium/base/metrics/CachedMetrics.java b/base/android/java/src/org/chromium/base/metrics/CachedMetrics.java
deleted file mode 100644
index f57dba2..0000000
--- a/base/android/java/src/org/chromium/base/metrics/CachedMetrics.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.base.metrics;
-
-import org.chromium.base.library_loader.LibraryLoader;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Utility classes for recording UMA metrics before the native library
- * may have been loaded.  Metrics are cached until the library is known
- * to be loaded, then committed to the MetricsService all at once.
- */
-public class CachedMetrics {
-    /**
-     * Creating an instance of a subclass of this class automatically adds it to a list of objects
-     * that are committed when the native library is available.
-     */
-    private abstract static class CachedHistogram {
-        private static final List<CachedHistogram> sEvents = new ArrayList<CachedHistogram>();
-
-        protected final String mHistogramName;
-
-        /**
-         * @param histogramName Name of the histogram to record.
-         */
-        protected CachedHistogram(String histogramName) {
-            mHistogramName = histogramName;
-            sEvents.add(this);
-        }
-
-        /** Commits the histogram. Expects the native library to be loaded. */
-        protected abstract void commitAndClear();
-    }
-
-    /**
-     * Caches an action that will be recorded after native side is loaded.
-     */
-    public static class ActionEvent extends CachedHistogram {
-        private int mCount;
-
-        public ActionEvent(String actionName) {
-            super(actionName);
-        }
-
-        public void record() {
-            if (LibraryLoader.isInitialized()) {
-                recordWithNative();
-            } else {
-                mCount++;
-            }
-        }
-
-        private void recordWithNative() {
-            RecordUserAction.record(mHistogramName);
-        }
-
-        @Override
-        protected void commitAndClear() {
-            while (mCount > 0) {
-                recordWithNative();
-                mCount--;
-            }
-        }
-    }
-
-    /** Caches a set of integer histogram samples. */
-    public static class SparseHistogramSample extends CachedHistogram {
-        private final List<Integer> mSamples = new ArrayList<Integer>();
-
-        public SparseHistogramSample(String histogramName) {
-            super(histogramName);
-        }
-
-        public void record(int sample) {
-            if (LibraryLoader.isInitialized()) {
-                recordWithNative(sample);
-            } else {
-                mSamples.add(sample);
-            }
-        }
-
-        private void recordWithNative(int sample) {
-            RecordHistogram.recordSparseSlowlyHistogram(mHistogramName, sample);
-        }
-
-        @Override
-        protected void commitAndClear() {
-            for (Integer sample : mSamples) {
-                recordWithNative(sample);
-            }
-            mSamples.clear();
-        }
-    }
-
-    /** Caches a set of enumerated histogram samples. */
-    public static class EnumeratedHistogramSample extends CachedHistogram {
-        private final List<Integer> mSamples = new ArrayList<Integer>();
-        private final int mMaxValue;
-
-        public EnumeratedHistogramSample(String histogramName, int maxValue) {
-            super(histogramName);
-            mMaxValue = maxValue;
-        }
-
-        public void record(int sample) {
-            if (LibraryLoader.isInitialized()) {
-                recordWithNative(sample);
-            } else {
-                mSamples.add(sample);
-            }
-        }
-
-        private void recordWithNative(int sample) {
-            RecordHistogram.recordEnumeratedHistogram(mHistogramName, sample, mMaxValue);
-        }
-
-        @Override
-        protected void commitAndClear() {
-            for (Integer sample : mSamples) {
-                recordWithNative(sample);
-            }
-            mSamples.clear();
-        }
-    }
-
-    /** Caches a set of times histogram samples. */
-    public static class TimesHistogramSample extends CachedHistogram {
-        private final List<Long> mSamples = new ArrayList<Long>();
-        private final TimeUnit mTimeUnit;
-
-        public TimesHistogramSample(String histogramName, TimeUnit timeUnit) {
-            super(histogramName);
-            mTimeUnit = timeUnit;
-        }
-
-        public void record(long sample) {
-            if (LibraryLoader.isInitialized()) {
-                recordWithNative(sample);
-            } else {
-                mSamples.add(sample);
-            }
-        }
-
-        private void recordWithNative(long sample) {
-            RecordHistogram.recordTimesHistogram(mHistogramName, sample, mTimeUnit);
-        }
-
-        @Override
-        protected void commitAndClear() {
-            for (Long sample : mSamples) {
-                recordWithNative(sample);
-            }
-            mSamples.clear();
-        }
-    }
-
-    /**
-     * Calls out to native code to commit any cached histograms and events.
-     * Should be called once the native library has been loaded.
-     */
-    public static void commitCachedMetrics() {
-        for (CachedHistogram event : CachedHistogram.sEvents) event.commitAndClear();
-    }
-}
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
index 930a280..9615f9d 100644
--- a/base/mac/mac_util.mm
+++ b/base/mac/mac_util.mm
@@ -296,11 +296,21 @@
   ProcessInfoRec info = {};
   info.processInfoLength = sizeof(info);
 
+// GetProcessInformation has been deprecated since macOS 10.9, but there is no
+// replacement that provides the information we need. See
+// https://crbug.com/650854.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
   if (GetProcessInformation(&psn, &info) == noErr) {
+#pragma clang diagnostic pop
     ProcessInfoRec parent_info = {};
     parent_info.processInfoLength = sizeof(parent_info);
-    if (GetProcessInformation(&info.processLauncher, &parent_info) == noErr)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    if (GetProcessInformation(&info.processLauncher, &parent_info) == noErr) {
+#pragma clang diagnostic pop
       return parent_info.processSignature == 'lgnw';
+    }
   }
   return false;
 }
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 4d4f9936..76bad02 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -474,12 +474,12 @@
   layer_->SetHasWillChangeTransformHint(has_will_change);
 }
 
-void WebLayerImpl::setPreferredRasterScale(float raster_scale) {
-  layer_->SetPreferredRasterScale(raster_scale);
+void WebLayerImpl::setPreferredRasterBounds(const WebSize& bounds) {
+  layer_->SetPreferredRasterBounds(bounds);
 }
 
-void WebLayerImpl::clearPreferredRasterScale() {
-  layer_->ClearPreferredRasterScale();
+void WebLayerImpl::clearPreferredRasterBounds() {
+  layer_->ClearPreferredRasterBounds();
 }
 
 }  // namespace cc_blink
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index 28e15ff..432153d 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -136,8 +136,8 @@
   void setCompositorMutableProperties(uint32_t properties) override;
   uint32_t compositorMutableProperties() const override;
   void setHasWillChangeTransformHint(bool has_will_change) override;
-  void setPreferredRasterScale(float raster_scale) override;
-  void clearPreferredRasterScale() override;
+  void setPreferredRasterBounds(const blink::WebSize&) override;
+  void clearPreferredRasterBounds() override;
 
   void setScrollParent(blink::WebLayer* parent) override;
   void setClipParent(blink::WebLayer* parent) override;
diff --git a/cc/input/scrollbar_animation_controller.cc b/cc/input/scrollbar_animation_controller.cc
index 45feb3a..086f63e3 100644
--- a/cc/input/scrollbar_animation_controller.cc
+++ b/cc/input/scrollbar_animation_controller.cc
@@ -15,12 +15,10 @@
     int scroll_layer_id,
     ScrollbarAnimationControllerClient* client,
     base::TimeDelta delay_before_starting,
-    base::TimeDelta resize_delay_before_starting,
-    base::TimeDelta duration)
+    base::TimeDelta resize_delay_before_starting)
     : client_(client),
       delay_before_starting_(delay_before_starting),
       resize_delay_before_starting_(resize_delay_before_starting),
-      duration_(duration),
       is_animating_(false),
       scroll_layer_id_(scroll_layer_id),
       currently_scrolling_(false),
@@ -47,7 +45,7 @@
 float ScrollbarAnimationController::AnimationProgressAtTime(
     base::TimeTicks now) {
   base::TimeDelta delta = now - last_awaken_time_;
-  float progress = delta.InSecondsF() / duration_.InSecondsF();
+  float progress = delta.InSecondsF() / Duration().InSecondsF();
   return std::max(std::min(progress, 1.f), 0.f);
 }
 
@@ -57,7 +55,6 @@
 
 void ScrollbarAnimationController::DidScrollUpdate(bool on_resize) {
   StopAnimation();
-  delayed_scrollbar_fade_.Cancel();
 
   // As an optimization, we avoid spamming fade delay tasks during active fast
   // scrolls.  But if we're not within one, we need to post every scroll update.
@@ -94,6 +91,7 @@
 }
 
 void ScrollbarAnimationController::StopAnimation() {
+  delayed_scrollbar_fade_.Cancel();
   is_animating_ = false;
 }
 
diff --git a/cc/input/scrollbar_animation_controller.h b/cc/input/scrollbar_animation_controller.h
index a3b6100bc..d1f3787 100644
--- a/cc/input/scrollbar_animation_controller.h
+++ b/cc/input/scrollbar_animation_controller.h
@@ -50,10 +50,10 @@
   ScrollbarAnimationController(int scroll_layer_id,
                                ScrollbarAnimationControllerClient* client,
                                base::TimeDelta delay_before_starting,
-                               base::TimeDelta resize_delay_before_starting,
-                               base::TimeDelta duration);
+                               base::TimeDelta resize_delay_before_starting);
 
   virtual void RunAnimationFrame(float progress) = 0;
+  virtual const base::TimeDelta& Duration() = 0;
 
   void StartAnimation();
   void StopAnimation();
@@ -61,17 +61,16 @@
 
   ScrollbarAnimationControllerClient* client_;
 
+  void PostDelayedAnimationTask(bool on_resize);
+
  private:
   // Returns how far through the animation we are as a progress value from
   // 0 to 1.
   float AnimationProgressAtTime(base::TimeTicks now);
 
-  void PostDelayedAnimationTask(bool on_resize);
-
   base::TimeTicks last_awaken_time_;
   base::TimeDelta delay_before_starting_;
   base::TimeDelta resize_delay_before_starting_;
-  base::TimeDelta duration_;
 
   bool is_animating_;
 
diff --git a/cc/input/scrollbar_animation_controller_linear_fade.cc b/cc/input/scrollbar_animation_controller_linear_fade.cc
index 8695bfa..ee7f4afe6 100644
--- a/cc/input/scrollbar_animation_controller_linear_fade.cc
+++ b/cc/input/scrollbar_animation_controller_linear_fade.cc
@@ -33,8 +33,8 @@
     : ScrollbarAnimationController(scroll_layer_id,
                                    client,
                                    delay_before_starting,
-                                   resize_delay_before_starting,
-                                   duration) {}
+                                   resize_delay_before_starting),
+      duration_(duration) {}
 
 ScrollbarAnimationControllerLinearFade::
     ~ScrollbarAnimationControllerLinearFade() {}
@@ -46,6 +46,10 @@
     StopAnimation();
 }
 
+const base::TimeDelta& ScrollbarAnimationControllerLinearFade::Duration() {
+  return duration_;
+}
+
 void ScrollbarAnimationControllerLinearFade::DidScrollUpdate(bool on_resize) {
   ScrollbarAnimationController::DidScrollUpdate(on_resize);
   ApplyOpacityToScrollbars(1.f);
diff --git a/cc/input/scrollbar_animation_controller_linear_fade.h b/cc/input/scrollbar_animation_controller_linear_fade.h
index f5993e7..f5ef13a 100644
--- a/cc/input/scrollbar_animation_controller_linear_fade.h
+++ b/cc/input/scrollbar_animation_controller_linear_fade.h
@@ -37,11 +37,14 @@
       base::TimeDelta duration);
 
   void RunAnimationFrame(float progress) override;
+  const base::TimeDelta& Duration() override;
 
  private:
   float OpacityAtTime(base::TimeTicks now) const;
   void ApplyOpacityToScrollbars(float opacity);
 
+  base::TimeDelta duration_;
+
   DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerLinearFade);
 };
 
diff --git a/cc/input/scrollbar_animation_controller_thinning.cc b/cc/input/scrollbar_animation_controller_thinning.cc
index 74352996..57b1c92 100644
--- a/cc/input/scrollbar_animation_controller_thinning.cc
+++ b/cc/input/scrollbar_animation_controller_thinning.cc
@@ -12,7 +12,6 @@
 
 namespace {
 const float kIdleThicknessScale = 0.4f;
-const float kIdleOpacity = 0.7f;
 const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
 }
 
@@ -24,10 +23,11 @@
     ScrollbarAnimationControllerClient* client,
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
-    base::TimeDelta duration) {
+    base::TimeDelta fade_duration,
+    base::TimeDelta thinning_duration) {
   return base::WrapUnique(new ScrollbarAnimationControllerThinning(
       scroll_layer_id, client, delay_before_starting,
-      resize_delay_before_starting, duration));
+      resize_delay_before_starting, fade_duration, thinning_duration));
 }
 
 ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
@@ -35,50 +35,78 @@
     ScrollbarAnimationControllerClient* client,
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
-    base::TimeDelta duration)
+    base::TimeDelta fade_duration,
+    base::TimeDelta thinning_duration)
     : ScrollbarAnimationController(scroll_layer_id,
                                    client,
                                    delay_before_starting,
-                                   resize_delay_before_starting,
-                                   duration),
+                                   resize_delay_before_starting),
+      opacity_(0.0f),
       captured_(false),
       mouse_is_over_scrollbar_(false),
       mouse_is_near_scrollbar_(false),
       thickness_change_(NONE),
-      opacity_change_(NONE),
       mouse_move_distance_to_trigger_animation_(
-          kDefaultMouseMoveDistanceToTriggerAnimation) {
-  ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale);
+          kDefaultMouseMoveDistanceToTriggerAnimation),
+      fade_duration_(fade_duration),
+      thinning_duration_(thinning_duration),
+      current_animating_property_(OPACITY) {
+  ApplyOpacity(0.f);
+  ApplyThumbThicknessScale(kIdleThicknessScale);
 }
 
 ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {}
 
 void ScrollbarAnimationControllerThinning::RunAnimationFrame(float progress) {
-  float opacity = OpacityAtAnimationProgress(progress);
-  float thumb_thickness_scale =
-      ThumbThicknessScaleAtAnimationProgress(progress);
-  ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale);
+  if (captured_)
+    return;
+
+  if (current_animating_property_ == OPACITY)
+    ApplyOpacity(1.f - progress);
+  else
+    ApplyThumbThicknessScale(ThumbThicknessScaleAt(progress));
+
   client_->SetNeedsRedrawForScrollbarAnimation();
   if (progress == 1.f) {
-    opacity_change_ = NONE;
-    thickness_change_ = NONE;
     StopAnimation();
+    if (current_animating_property_ == THICKNESS) {
+      thickness_change_ = NONE;
+      SetCurrentAnimatingProperty(OPACITY);
+      PostDelayedAnimationTask(false);
+    }
   }
 }
 
+const base::TimeDelta& ScrollbarAnimationControllerThinning::Duration() {
+  if (current_animating_property_ == OPACITY)
+    return fade_duration_;
+  else
+    return thinning_duration_;
+}
+
 void ScrollbarAnimationControllerThinning::DidCaptureScrollbarBegin() {
+  if (opacity_ == 0.0f)
+    return;
+  StopAnimation();
   captured_ = true;
-  ApplyOpacityAndThumbThicknessScale(1, 1.f);
+  ApplyOpacity(1.f);
+  ApplyThumbThicknessScale(1.f);
 }
 
 void ScrollbarAnimationControllerThinning::DidCaptureScrollbarEnd() {
+  if (opacity_ == 0.0f)
+    return;
   captured_ = false;
+  StopAnimation();
 
-  if (!mouse_is_over_scrollbar_)
-    opacity_change_ = DECREASE;
-  if (!mouse_is_near_scrollbar_)
+  if (!mouse_is_near_scrollbar_) {
+    SetCurrentAnimatingProperty(THICKNESS);
     thickness_change_ = DECREASE;
-  StartAnimation();
+    StartAnimation();
+  } else {
+    SetCurrentAnimatingProperty(OPACITY);
+    PostDelayedAnimationTask(false);
+  }
 }
 
 void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar() {
@@ -88,66 +116,54 @@
   mouse_is_over_scrollbar_ = false;
   mouse_is_near_scrollbar_ = false;
 
-  if (captured_)
+  if (captured_ || opacity_ == 0.0f)
     return;
 
-  opacity_change_ = DECREASE;
   thickness_change_ = DECREASE;
+  SetCurrentAnimatingProperty(THICKNESS);
   StartAnimation();
 }
 
 void ScrollbarAnimationControllerThinning::DidScrollUpdate(bool on_resize) {
-  if (captured_) {
+  if (captured_)
     return;
-  }
 
   ScrollbarAnimationController::DidScrollUpdate(on_resize);
-  ApplyOpacityAndThumbThicknessScale(
-      1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
-
-  if (!mouse_is_over_scrollbar_)
-    opacity_change_ = DECREASE;
+  ApplyOpacity(1.f);
+  ApplyThumbThicknessScale(mouse_is_near_scrollbar_ ? 1.f
+                                                    : kIdleThicknessScale);
+  SetCurrentAnimatingProperty(OPACITY);
 }
 
 void ScrollbarAnimationControllerThinning::DidMouseMoveNear(float distance) {
-  bool mouse_is_over_scrollbar = distance == 0.0;
+  bool mouse_is_over_scrollbar = distance == 0.0f;
   bool mouse_is_near_scrollbar =
       distance < mouse_move_distance_to_trigger_animation_;
 
-  if (captured_) {
+  if (captured_ || opacity_ == 0.0f) {
     mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
     mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
     return;
-  } else {
-    if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ &&
-        mouse_is_near_scrollbar == mouse_is_near_scrollbar_)
-      return;
-
-    if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) {
-      mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
-      opacity_change_ = mouse_is_over_scrollbar_ ? INCREASE : DECREASE;
-    }
-
-    if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) {
-      mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
-      thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE;
-    }
-
-    StartAnimation();
   }
+
+  if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ &&
+      mouse_is_near_scrollbar == mouse_is_near_scrollbar_)
+    return;
+
+  if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar)
+    mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
+
+  if (mouse_is_near_scrollbar_ != mouse_is_near_scrollbar) {
+    mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
+    thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE;
+  }
+
+  SetCurrentAnimatingProperty(THICKNESS);
+  StartAnimation();
 }
 
-float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress(
+float ScrollbarAnimationControllerThinning::ThumbThicknessScaleAt(
     float progress) {
-  if (opacity_change_ == NONE)
-    return mouse_is_over_scrollbar_ ? 1.f : kIdleOpacity;
-  float factor = opacity_change_ == INCREASE ? progress : (1.f - progress);
-  float ret = ((1.f - kIdleOpacity) * factor) + kIdleOpacity;
-  return ret;
-}
-
-float ScrollbarAnimationControllerThinning::
-    ThumbThicknessScaleAtAnimationProgress(float progress) {
   if (thickness_change_ == NONE)
     return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
   float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
@@ -174,17 +190,11 @@
   return result;
 }
 
-void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
-    float opacity,
-    float thumb_thickness_scale) {
+void ScrollbarAnimationControllerThinning::ApplyOpacity(float opacity) {
   for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) {
     if (!scrollbar->is_overlay_scrollbar())
       continue;
-    float effective_opacity =
-        scrollbar->CanScrollOrientation()
-            ? AdjustScale(opacity, scrollbar->Opacity(), opacity_change_,
-                          kIdleOpacity, 1)
-            : 0;
+    float effective_opacity = scrollbar->CanScrollOrientation() ? opacity : 0;
     PropertyTrees* property_trees =
         scrollbar->layer_tree_impl()->property_trees();
     // If this method is called during LayerImpl::PushPropertiesTo, we may not
@@ -199,10 +209,32 @@
           property_trees->effect_id_to_index_map[scrollbar->id()],
           scrollbar->layer_tree_impl());
     }
+  }
+
+  opacity_ = opacity;
+}
+
+void ScrollbarAnimationControllerThinning::ApplyThumbThicknessScale(
+    float thumb_thickness_scale) {
+  for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) {
+    if (!scrollbar->is_overlay_scrollbar())
+      continue;
+
     scrollbar->SetThumbThicknessScaleFactor(AdjustScale(
         thumb_thickness_scale, scrollbar->thumb_thickness_scale_factor(),
         thickness_change_, kIdleThicknessScale, 1));
   }
 }
 
+void ScrollbarAnimationControllerThinning::SetCurrentAnimatingProperty(
+    AnimatingProperty property) {
+  if (current_animating_property_ == property)
+    return;
+
+  StopAnimation();
+  current_animating_property_ = property;
+  if (current_animating_property_ == THICKNESS)
+    ApplyOpacity(1.f);
+}
+
 }  // namespace cc
diff --git a/cc/input/scrollbar_animation_controller_thinning.h b/cc/input/scrollbar_animation_controller_thinning.h
index d1d4ee0..e3b2ab8e 100644
--- a/cc/input/scrollbar_animation_controller_thinning.h
+++ b/cc/input/scrollbar_animation_controller_thinning.h
@@ -24,7 +24,8 @@
       ScrollbarAnimationControllerClient* client,
       base::TimeDelta delay_before_starting,
       base::TimeDelta resize_delay_before_starting,
-      base::TimeDelta duration);
+      base::TimeDelta fade_duration,
+      base::TimeDelta thinning_duration);
 
   ~ScrollbarAnimationControllerThinning() override;
 
@@ -47,34 +48,42 @@
       ScrollbarAnimationControllerClient* client,
       base::TimeDelta delay_before_starting,
       base::TimeDelta resize_delay_before_starting,
-      base::TimeDelta duration);
+      base::TimeDelta fade_duration,
+      base::TimeDelta thinning_duration);
 
   void RunAnimationFrame(float progress) override;
+  const base::TimeDelta& Duration() override;
 
  private:
-  // Describes whether the current animation should INCREASE (darken / thicken)
-  // a bar or DECREASE it (lighten / thin).
+  // Describes whether the current animation should INCREASE (thicken)
+  // a bar or DECREASE it (thin).
   enum AnimationChange { NONE, INCREASE, DECREASE };
-  float OpacityAtAnimationProgress(float progress);
-  float ThumbThicknessScaleAtAnimationProgress(float progress);
+  enum AnimatingProperty { OPACITY, THICKNESS };
+  float ThumbThicknessScaleAt(float progress);
   float AdjustScale(float new_value,
                     float current_value,
                     AnimationChange animation_change,
                     float min_value,
                     float max_value);
-  void ApplyOpacityAndThumbThicknessScale(float opacity,
-                                          float thumb_thickness_scale);
+  void ApplyOpacity(float opacity);
+  void ApplyThumbThicknessScale(float thumb_thickness_scale);
 
+  void SetCurrentAnimatingProperty(AnimatingProperty property);
+
+  float opacity_;
   bool captured_;
   bool mouse_is_over_scrollbar_;
   bool mouse_is_near_scrollbar_;
   // Are we narrowing or thickening the bars.
   AnimationChange thickness_change_;
-  // Are we darkening or lightening the bars.
-  AnimationChange opacity_change_;
   // How close should the mouse be to the scrollbar before we thicken it.
   float mouse_move_distance_to_trigger_animation_;
 
+  base::TimeDelta fade_duration_;
+  base::TimeDelta thinning_duration_;
+
+  AnimatingProperty current_animating_property_;
+
   DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerThinning);
 };
 
diff --git a/cc/input/scrollbar_animation_controller_thinning_unittest.cc b/cc/input/scrollbar_animation_controller_thinning_unittest.cc
index 64096b7..de24f292 100644
--- a/cc/input/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/input/scrollbar_animation_controller_thinning_unittest.cc
@@ -16,6 +16,11 @@
 namespace cc {
 namespace {
 
+// These constants are hard-coded and should match the values in
+// scrollbar_animation_controller_thinning.cc.
+const float kIdleThicknessScale = 0.4f;
+const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
+
 class ScrollbarAnimationControllerThinningTest
     : public testing::Test,
       public ScrollbarAnimationControllerClient {
@@ -41,9 +46,11 @@
   }
 
  protected:
-  const int kDelayBeforeStarting = 2;
-  const int kResizeDelayBeforeStarting = 5;
-  const int kDuration = 3;
+  const base::TimeDelta kDelayBeforeStarting = base::TimeDelta::FromSeconds(2);
+  const base::TimeDelta kResizeDelayBeforeStarting =
+      base::TimeDelta::FromSeconds(5);
+  const base::TimeDelta kFadeDuration = base::TimeDelta::FromSeconds(3);
+  const base::TimeDelta kThinningDuration = base::TimeDelta::FromSeconds(2);
 
   void SetUp() override {
     std::unique_ptr<LayerImpl> scroll_layer =
@@ -77,10 +84,8 @@
     host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
 
     scrollbar_controller_ = ScrollbarAnimationControllerThinning::Create(
-        scroll_layer_ptr->id(), this,
-        base::TimeDelta::FromSeconds(kDelayBeforeStarting),
-        base::TimeDelta::FromSeconds(kResizeDelayBeforeStarting),
-        base::TimeDelta::FromSeconds(kDuration));
+        scroll_layer_ptr->id(), this, kDelayBeforeStarting,
+        kResizeDelayBeforeStarting, kFadeDuration, kThinningDuration);
   }
 
   FakeImplTaskRunnerProvider task_runner_provider_;
@@ -97,24 +102,28 @@
   bool did_request_animate_;
 };
 
-// Check initialization of scrollbar.
+// Check initialization of scrollbar. Should start off invisible and thin.
 TEST_F(ScrollbarAnimationControllerThinningTest, Idle) {
-  scrollbar_controller_->Animate(base::TimeTicks());
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
-// Check that scrollbar appears again, when the layer becomes scrollable.
+// Check that scrollbar appears again when the layer becomes scrollable.
 TEST_F(ScrollbarAnimationControllerThinningTest, AppearOnResize) {
+  scrollbar_controller_->DidScrollBegin();
   scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
   // Make the Layer non-scrollable, scrollbar disappears.
   clip_layer_->SetBounds(gfx::Size(200, 200));
   scrollbar_controller_->DidScrollUpdate(false);
   EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+
   // Make the layer scrollable, scrollbar appears again.
   clip_layer_->SetBounds(gfx::Size(100, 100));
   scrollbar_controller_->DidScrollUpdate(false);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
 }
 
 // Check that scrollbar disappears when the layer becomes non-scrollable.
@@ -149,72 +158,350 @@
   scrollbar_controller_->DidScrollEnd();
 }
 
-// Scroll content. Confirm the scrollbar gets dark and then becomes light
-// after stopping.
-TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) {
+// Scroll content. Confirm the scrollbar appears and fades out.
+TEST_F(ScrollbarAnimationControllerThinningTest, BasicAppearAndFadeOut) {
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
+
+  // Scrollbar should be invisible by default.
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+
+  // Scrollbar should appear only on scroll update.
+  scrollbar_controller_->DidScrollBegin();
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+
   scrollbar_controller_->DidScrollUpdate(false);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-  // Scrollbar doesn't change size if triggered by scroll.
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
+  scrollbar_controller_->DidScrollEnd();
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
   start_fade_.Run();
 
-  time += base::TimeDelta::FromSeconds(1);
+  // Scrollbar should fade out over kFadeDuration.
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  time += kFadeDuration;
+  scrollbar_controller_->Animate(time);
 
-  // Subsequent scroll restarts animation.
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+}
+
+// Scroll content. Move the mouse near the scrollbar and confirm it becomes
+// thick. Ensure it fades out after that.
+TEST_F(ScrollbarAnimationControllerThinningTest, MoveNearAndFadeOut) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
   scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
 
-  start_fade_.Run();
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
 
-  time += base::TimeDelta::FromSeconds(2);
+  // Now move the mouse near the scrollbar. This should cancel the currently
+  // queued fading animation and start animating thickness.
+  scrollbar_controller_->DidMouseMoveNear(1);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_TRUE(start_fade_.IsCancelled());
+
+  // Scrollbar should become thick.
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  // Once the thickening animation is complete, it should enqueue the delayed
+  // fade animation.
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_FALSE(start_fade_.IsCancelled());
+}
 
+// Scroll content. Move the mouse over the scrollbar and confirm it becomes
+// thick. Ensure it fades out after that.
+TEST_F(ScrollbarAnimationControllerThinningTest, MoveOverAndFadeOut) {
+  base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+
+  // Now move the mouse over the scrollbar. This should cancel the currently
+  // queued fading animation and start animating thickness.
+  scrollbar_controller_->DidMouseMoveNear(0);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_TRUE(start_fade_.IsCancelled());
+
+  // Scrollbar should become thick.
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  time += kThinningDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Once the thickening animation is complete, it should enqueue the delayed
+  // fade animation.
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_FALSE(start_fade_.IsCancelled());
+}
+
+// Make sure a scrollbar captured before the thickening animation doesn't try
+// to fade out.
+TEST_F(ScrollbarAnimationControllerThinningTest,
+       DontFadeWhileCapturedBeforeThick) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+
+  // Now move the mouse over the scrollbar and capture it. It should become
+  // thick without need for an animation.
+  scrollbar_controller_->DidMouseMoveNear(0);
+  scrollbar_controller_->DidCaptureScrollbarBegin();
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // The fade animation should have been cancelled.
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_TRUE(start_fade_.IsCancelled());
+}
+
+// Make sure a scrollbar captured after a thickening animation doesn't try to
+// fade out.
+TEST_F(ScrollbarAnimationControllerThinningTest, DontFadeWhileCaptured) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+
+  // Now move the mouse over the scrollbar and animate it until it's thick.
+  scrollbar_controller_->DidMouseMoveNear(0);
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Since the scrollbar became thick, it should have queued up a fade.
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_FALSE(start_fade_.IsCancelled());
+
+  // Make sure capturing the scrollbar stops the fade.
+  scrollbar_controller_->DidCaptureScrollbarBegin();
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_TRUE(start_fade_.IsCancelled());
+}
+
+// Make sure releasing a captured scrollbar causes it to fade out.
+TEST_F(ScrollbarAnimationControllerThinningTest, FadeAfterReleased) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+
+  // Now move the mouse over the scrollbar and capture it.
+  scrollbar_controller_->DidMouseMoveNear(0);
+  scrollbar_controller_->DidCaptureScrollbarBegin();
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Since the scrollbar became thick, it should have queued up a fade.
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_TRUE(start_fade_.IsCancelled());
+
+  scrollbar_controller_->DidCaptureScrollbarEnd();
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_FALSE(start_fade_.IsCancelled());
+}
+
+// Make sure moving near a scrollbar while it's fading out causes it to reset
+// the opacity and thicken.
+TEST_F(ScrollbarAnimationControllerThinningTest, MoveNearScrollbarWhileFading) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // An animation should have been enqueued. Start it.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+  start_fade_.Run();
+
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
+  // Proceed half way through the fade out animation.
+  time += kFadeDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.5f, scrollbar_layer_->Opacity());
+
+  // Now move the mouse near the scrollbar. It should reset opacity to 1
+  // instantly and start animating to thick.
+  scrollbar_controller_->DidMouseMoveNear(1);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+}
+
+// Make sure capturing a scrollbar while it's fading out causes it to reset the
+// opacity and thicken instantly.
+TEST_F(ScrollbarAnimationControllerThinningTest, CaptureScrollbarWhileFading) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // Move mouse over the scrollbar.
+  scrollbar_controller_->DidMouseMoveNear(0);
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // A fade animation should have been enqueued. Start it.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+  start_fade_.Run();
+
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
+  // Proceed half way through the fade out animation.
+  time += kFadeDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.5f, scrollbar_layer_->Opacity());
+
+  // Now capture the scrollbar. It should reset opacity to 1 instantly.
+  scrollbar_controller_->DidCaptureScrollbarBegin();
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+}
+
+// Make sure we can't capture scrollbar that's completely faded out
+TEST_F(ScrollbarAnimationControllerThinningTest, TestCantCaptureWhenFaded) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // Move mouse over the scrollbar.
+  scrollbar_controller_->DidMouseMoveNear(0);
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // A fade animation should have been enqueued. Start it.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+  start_fade_.Run();
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
+  // Fade the scrollbar out completely.
+  time += kFadeDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  start_fade_.Reset();
+
+  // Now try to capture the scrollbar. It shouldn't do anything since it's
+  // completely faded out.
+  scrollbar_controller_->DidCaptureScrollbarBegin();
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_TRUE(start_fade_.is_null());
+
+  // Similarly, releasing the scrollbar should have no effect.
+  scrollbar_controller_->DidCaptureScrollbarEnd();
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_TRUE(start_fade_.is_null());
 }
 
 // Initiate a scroll when the pointer is already near the scrollbar. It should
-// remain thick.
+// appear thick and remain thick.
 TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) {
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
 
   scrollbar_controller_->DidMouseMoveNear(1);
   scrollbar_controller_->Animate(time);
-  time += base::TimeDelta::FromSeconds(3);
+  time += kThinningDuration;
 
+  // Since the scrollbar isn't visible yet (because we haven't scrolled), we
+  // shouldn't have applied the thickening.
   scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+
+  // Now that we've received a scroll, we should be thick without an animation.
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  scrollbar_controller_->DidScrollUpdate(false);
+  // An animation for the fade should have been enqueued.
+  scrollbar_controller_->DidScrollEnd();
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+
   start_fade_.Run();
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-  // Scrollbar should still be thick.
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(5);
+  // Scrollbar should still be thick, even though the scrollbar fades out.
+  time += kFadeDuration;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
@@ -223,79 +510,62 @@
 TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
+
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
   scrollbar_controller_->DidMouseMoveNear(1);
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Should animate to thickened but not darken.
-  time += base::TimeDelta::FromSeconds(1);
+  // Should animate to thickened.
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Subsequent moves should not change anything.
-  scrollbar_controller_->DidMouseMoveNear(1);
+  // Subsequent moves within the nearness threshold should not change anything.
+  scrollbar_controller_->DidMouseMoveNear(2);
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   // Now move away from bar.
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->DidMouseMoveNear(26);
+  scrollbar_controller_->DidMouseMoveNear(
+      kDefaultMouseMoveDistanceToTriggerAnimation);
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  // Animate to narrow.
-  time += base::TimeDelta::FromSeconds(1);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
-// Move the pointer over the scrollbar. Make sure it gets thick and dark
-// and that it gets thin and light when moved away.
+// Move the pointer over the scrollbar. Make sure it gets thick that it gets
+// thin when moved away.
 TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
+
   scrollbar_controller_->DidMouseMoveNear(0);
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Should animate to thickened and darkened.
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
+  // Should animate to thickened.
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -303,66 +573,53 @@
   // Subsequent moves should not change anything.
   scrollbar_controller_->DidMouseMoveNear(0);
   scrollbar_controller_->Animate(time);
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Moving off the scrollbar but still withing the "near" threshold should do
+  // nothing.
+  scrollbar_controller_->DidMouseMoveNear(
+      kDefaultMouseMoveDistanceToTriggerAnimation - 1.f);
+  scrollbar_controller_->Animate(time);
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
   // Now move away from bar.
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->DidMouseMoveNear(26);
+  scrollbar_controller_->DidMouseMoveNear(
+      kDefaultMouseMoveDistanceToTriggerAnimation);
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  // Animate to narrow.
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
-// First move the pointer near the scrollbar, then over it, then back near
-// then far away. Confirm that first the bar gets thick, then dark, then light,
-// then narrow.
-TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) {
+// First move the pointer over the scrollbar off of it. Make sure the thinning
+// animation kicked off in DidMouseMoveOffScrollbar gets overridden by the
+// thickening animation in the DidMouseMoveNear call.
+TEST_F(ScrollbarAnimationControllerThinningTest,
+       MouseNearThenAwayWhileAnimating) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->DidMouseMoveNear(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Should animate to thickened but not darken.
-  time += base::TimeDelta::FromSeconds(3);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  // Now move over.
   scrollbar_controller_->DidMouseMoveNear(0);
   scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Should animate to darkened.
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
+  // Should animate to thickened.
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -374,183 +631,304 @@
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->DidMouseMoveOffScrollbar();
   scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
+  // Let the animation run half of the way through the thinning animation.
+  time += kThinningDuration / 2;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
+  // Now we get a notification for the mouse moving over the scroller. The
+  // animation is reset to the thickening direction but we won't start
+  // thickening until the new animation catches up to the current thickness.
   scrollbar_controller_->DidMouseMoveNear(1);
   scrollbar_controller_->Animate(time);
-  // A new animation is kicked off.
+  EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
+  // Until we reach the half way point, the animation will have no effect.
+  time += kThinningDuration / 4;
   scrollbar_controller_->Animate(time);
-  // We will initiate the narrowing again, but it won't get decremented until
-  // the new animation catches up to it.
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  // Now the thickness should be increasing, but it shouldn't happen until the
-  // animation catches up.
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
+  time += kThinningDuration / 4;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->Opacity());
-  // The thickness now gets big again.
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
+  // We're now at three quarters of the way through so it should now started
+  // thickening again.
+  time += kThinningDuration / 4;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  // The thickness now gets big again.
+  EXPECT_FLOAT_EQ(kIdleThicknessScale + 3 * (1.0f - kIdleThicknessScale) / 4.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // And all the way to the end.
+  time += kThinningDuration / 4;
+  scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
 // First move the pointer on the scrollbar, then press it, then away.
-// Confirm that the bar gets thick and dark. Then mouse up. Confirm that
-// the bar gets thin and light.
+// Confirm that the bar gets thick. Then mouse up. Confirm that
+// the bar gets thin.
 TEST_F(ScrollbarAnimationControllerThinningTest,
        MouseCaptureAndReleaseOutOfBar) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
 
-  // Move in
+  // Move over the scrollbar.
   scrollbar_controller_->DidMouseMoveNear(0);
-
-  // Jump X seconds, first we need to make the time not 0, second we need to
-  // call Animate once to start the animation(initial the last_awaken_time_),
-  // now you can jump x seconds.
   scrollbar_controller_->Animate(time);
-  time += base::TimeDelta::FromSeconds(kDuration);
+  time += kFadeDuration;
   scrollbar_controller_->Animate(time);
-
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Capture
+  // Capture.
   scrollbar_controller_->DidCaptureScrollbarBegin();
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // test for 10 seconds, stay thick and dark
-  for (int i = 0; i < 10; ++i) {
-    // move away from bar.
-    scrollbar_controller_->DidMouseMoveNear(26 + i);
-    time += base::TimeDelta::FromSeconds(1);
-    scrollbar_controller_->Animate(time);
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-  }
+  // Should stay thick for a while.
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
 
-  // release
-  scrollbar_controller_->DidCaptureScrollbarEnd();
-
-  // get thickness and light
-  time += base::TimeDelta::FromSeconds(1);
+  // Move outside the "near" threshold. Because the scrollbar is captured it
+  // should remain thick.
+  scrollbar_controller_->DidMouseMoveNear(
+      kDefaultMouseMoveDistanceToTriggerAnimation);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
+  // Release.
+  scrollbar_controller_->DidCaptureScrollbarEnd();
 
+  // Should become thin.
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.6f, scrollbar_layer_->thumb_thickness_scale_factor());
-
-  time += base::TimeDelta::FromSeconds(1);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
-  EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->Opacity());
-  EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
-// First move the pointer on the scrollbar, then press it, then away.
-// Confirm that the bar gets thick and dark. Then move point on the
-// scrollbar and mouse up. Confirm that the bar gets thick and dark.
+// First move the pointer on the scrollbar, then press it, then away.  Confirm
+// that the bar gets thick. Then move point on the scrollbar and mouse up.
+// Confirm that the bar stays thick.
 TEST_F(ScrollbarAnimationControllerThinningTest, MouseCaptureAndReleaseOnBar) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
 
-  // Move in
+  // Move over scrollbar.
   scrollbar_controller_->DidMouseMoveNear(0);
-
   scrollbar_controller_->Animate(time);
-  time += base::TimeDelta::FromSeconds(kDuration);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Capture
+  // Capture. Nothing should change.
   scrollbar_controller_->DidCaptureScrollbarBegin();
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->Animate(time);
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // test for 10 seconds, stay thick and dark
-  for (int i = 0; i < 10; ++i) {
-    // move away from bar.
-    scrollbar_controller_->DidMouseMoveNear(26 + i);
-    time += base::TimeDelta::FromSeconds(1);
-    scrollbar_controller_->Animate(time);
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-  }
+  // Move away from scrollbar. Nothing should change.
+  scrollbar_controller_->DidMouseMoveNear(
+      kDefaultMouseMoveDistanceToTriggerAnimation);
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // move to the bar.
+  // Move over scrollbar and release. Since we're near the scrollbar, it should
+  // remain thick.
   scrollbar_controller_->DidMouseMoveNear(0);
-
-  // release
   scrollbar_controller_->DidCaptureScrollbarEnd();
-
-  // stay thick and dark
-  // test for 10 seconds, stay thick and dark
-  for (int i = 0; i < 10; ++i) {
-    time += base::TimeDelta::FromSeconds(1);
-    scrollbar_controller_->Animate(time);
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-  }
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  time += base::TimeDelta::FromSeconds(10);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 }
 
 // Move mouse on scrollbar and capture then move out of window. Confirm that
-// the bar stays thick and dark.
+// the bar stays thick.
 TEST_F(ScrollbarAnimationControllerThinningTest,
        MouseCapturedAndExitWindowFromScrollbar) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
 
-  // Move in
+  // Move mouse over scrollbar.
   scrollbar_controller_->DidMouseMoveNear(0);
-
   scrollbar_controller_->Animate(time);
-  time += base::TimeDelta::FromSeconds(kDuration);
+  time += kThinningDuration;
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // Capture
+  // Capture.
   scrollbar_controller_->DidCaptureScrollbarBegin();
-  time += base::TimeDelta::FromSeconds(1);
-  scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
 
-  // move out of window
+  // Move out of window. Since the scrollbar is capture, it shouldn't change in
+  // any way.
   scrollbar_controller_->DidMouseMoveOffScrollbar();
+  scrollbar_controller_->Animate(time);
+  time += kThinningDuration;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+}
 
-  // test for 10 seconds, stay thick and dark
-  for (int i = 0; i < 10; ++i) {
-    time += base::TimeDelta::FromSeconds(1);
-    scrollbar_controller_->Animate(time);
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
-    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
-  }
+// Tests that the thickening/thinning effects are animated.
+TEST_F(ScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  // Move mouse near scrollbar. Test that at half the duration time, the
+  // thickness is half way through its animation.
+  scrollbar_controller_->DidMouseMoveNear(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += kThinningDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(kIdleThicknessScale + (1.0f - kIdleThicknessScale) / 2.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += kThinningDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Move mouse away from scrollbar. Same check.
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->DidMouseMoveNear(
+      kDefaultMouseMoveDistanceToTriggerAnimation);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += kThinningDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+
+  time += kThinningDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(kIdleThicknessScale,
+                  scrollbar_layer_->thumb_thickness_scale_factor());
+}
+
+// Tests that main thread scroll updates immediatley queue a fade animation
+// without requiring a ScrollEnd.
+TEST_F(ScrollbarAnimationControllerThinningTest, MainThreadScrollQueuesFade) {
+  ASSERT_TRUE(start_fade_.is_null());
+
+  // A ScrollUpdate without a ScrollBegin indicates a main thread scroll update
+  // so we should schedule a fade animation without waiting for a ScrollEnd
+  // (which will never come).
+  scrollbar_controller_->DidScrollUpdate(false);
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+
+  start_fade_.Reset();
+
+  // If we got a ScrollBegin, we shouldn't schedule the fade animation until we
+  // get a corresponding ScrollEnd.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  EXPECT_TRUE(start_fade_.is_null());
+  scrollbar_controller_->DidScrollEnd();
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+}
+
+// Make sure that if the scroll update is as a result of a resize, we use the
+// resize delay time instead of the default one.
+TEST_F(ScrollbarAnimationControllerThinningTest, ResizeFadeDuration) {
+  ASSERT_TRUE(delay_.is_zero());
+
+  scrollbar_controller_->DidScrollUpdate(true);
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_EQ(kResizeDelayBeforeStarting, delay_);
+
+  delay_ = base::TimeDelta();
+
+  // We should use the gesture delay rather than the resize delay if we're in a
+  // gesture scroll, even if the resize param is set.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(true);
+  scrollbar_controller_->DidScrollEnd();
+
+  EXPECT_FALSE(start_fade_.is_null());
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+}
+
+// Tests that the fade effect is animated.
+TEST_F(ScrollbarAnimationControllerThinningTest, FadeAnimated) {
+  // Scroll to make the scrollbars visible.
+  scrollbar_controller_->DidScrollBegin();
+  scrollbar_controller_->DidScrollUpdate(false);
+  scrollbar_controller_->DidScrollEnd();
+
+  // Appearance is instant.
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
+  // An animation should have been enqueued.
+  EXPECT_EQ(kDelayBeforeStarting, delay_);
+  EXPECT_FALSE(start_fade_.is_null());
+  start_fade_.Run();
+
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  // Test that at half the fade duration time, the opacity is at half.
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+
+  time += kFadeDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.5f, scrollbar_layer_->Opacity());
+
+  time += kFadeDuration / 2;
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->Opacity());
 }
 
 }  // namespace
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 5462c1f..1abdaeb 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -67,10 +67,9 @@
       scroll_parent(nullptr),
       clip_parent(nullptr),
       has_will_change_transform_hint(false),
-      has_preferred_raster_scale(false),
+      has_preferred_raster_bounds(false),
       hide_layer_and_subtree(false),
-      client(nullptr),
-      preferred_raster_scale(1.0) {}
+      client(nullptr) {}
 
 Layer::Inputs::~Inputs() {}
 
@@ -1184,10 +1183,10 @@
   layer->SetUpdateRect(inputs_.update_rect);
 
   layer->SetHasWillChangeTransformHint(has_will_change_transform_hint());
-  if (has_preferred_raster_scale())
-    layer->SetPreferredRasterScale(preferred_raster_scale());
+  if (has_preferred_raster_bounds())
+    layer->SetPreferredRasterBounds(preferred_raster_bounds());
   else
-    layer->ClearPreferredRasterScale();
+    layer->ClearPreferredRasterBounds();
   layer->SetNeedsPushProperties();
 
   // Reset any state that should be cleared for the next update.
@@ -1766,21 +1765,21 @@
   SetNeedsCommit();
 }
 
-void Layer::SetPreferredRasterScale(float preferred_raster_scale) {
-  if (inputs_.has_preferred_raster_scale &&
-      inputs_.preferred_raster_scale == preferred_raster_scale)
+void Layer::SetPreferredRasterBounds(const gfx::Size& preferred_raster_bounds) {
+  if (inputs_.has_preferred_raster_bounds &&
+      inputs_.preferred_raster_bounds == preferred_raster_bounds)
     return;
 
-  inputs_.has_preferred_raster_scale = true;
-  inputs_.preferred_raster_scale = preferred_raster_scale;
+  inputs_.has_preferred_raster_bounds = true;
+  inputs_.preferred_raster_bounds = preferred_raster_bounds;
   SetNeedsCommit();
 }
 
-void Layer::ClearPreferredRasterScale() {
-  if (!inputs_.has_preferred_raster_scale)
+void Layer::ClearPreferredRasterBounds() {
+  if (!inputs_.has_preferred_raster_bounds)
     return;
-  inputs_.has_preferred_raster_scale = false;
-  inputs_.preferred_raster_scale = 1.0f;
+  inputs_.has_preferred_raster_bounds = false;
+  inputs_.preferred_raster_bounds = gfx::Size();
   SetNeedsCommit();
 }
 
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 577ccc9..5f98c71 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -478,14 +478,19 @@
     return inputs_.has_will_change_transform_hint;
   }
 
-  void SetPreferredRasterScale(float preferred_raster_scale);
-  bool has_preferred_raster_scale() {
-    return inputs_.has_preferred_raster_scale;
+  // The preferred raster bounds are the ideal resolution at which to raster the
+  // contents of this Layer's bitmap. This may not be the same size as the Layer
+  // bounds, in cases where the contents have an "intrinsic" size that differs.
+  // Consider for example an image with a given intrinsic size that is being
+  // scaled into a Layer of a different size.
+  void SetPreferredRasterBounds(const gfx::Size& preferred_Raster_bounds);
+  bool has_preferred_raster_bounds() const {
+    return inputs_.has_preferred_raster_bounds;
   }
-  float preferred_raster_scale() const {
-    return inputs_.preferred_raster_scale;
+  const gfx::Size& preferred_raster_bounds() const {
+    return inputs_.preferred_raster_bounds;
   }
-  void ClearPreferredRasterScale();
+  void ClearPreferredRasterBounds();
 
   AnimationHost* GetAnimationHost() const;
 
@@ -680,7 +685,7 @@
     Layer* clip_parent;
 
     bool has_will_change_transform_hint : 1;
-    bool has_preferred_raster_scale : 1;
+    bool has_preferred_raster_bounds : 1;
 
     bool hide_layer_and_subtree : 1;
 
@@ -689,7 +694,7 @@
     base::Closure did_scroll_callback;
     std::vector<std::unique_ptr<CopyOutputRequest>> copy_requests;
 
-    float preferred_raster_scale;
+    gfx::Size preferred_raster_bounds;
   };
 
   Layer* parent_;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 832fe51..aad1b1c 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -79,8 +79,7 @@
       current_draw_mode_(DRAW_MODE_NONE),
       mutable_properties_(MutableProperty::kNone),
       debug_info_(nullptr),
-      preferred_raster_scale_(1.0f),
-      has_preferred_raster_scale_(false),
+      has_preferred_raster_bounds_(false),
       scrolls_drawn_descendant_(false),
       has_will_change_transform_hint_(false),
       needs_push_properties_(false) {
@@ -109,14 +108,15 @@
   has_will_change_transform_hint_ = has_will_change;
 }
 
-void LayerImpl::SetPreferredRasterScale(float preferred_raster_scale) {
-  has_preferred_raster_scale_ = true;
-  preferred_raster_scale_ = preferred_raster_scale;
+void LayerImpl::SetPreferredRasterBounds(
+    const gfx::Size& preferred_raster_bounds) {
+  has_preferred_raster_bounds_ = true;
+  preferred_raster_bounds_ = preferred_raster_bounds;
 }
 
-void LayerImpl::ClearPreferredRasterScale() {
-  has_preferred_raster_scale_ = false;
-  preferred_raster_scale_ = 1.0f;
+void LayerImpl::ClearPreferredRasterBounds() {
+  has_preferred_raster_bounds_ = false;
+  preferred_raster_bounds_ = gfx::Size();
 }
 
 AnimationHost* LayerImpl::GetAnimationHost() const {
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 01de99c..f1f458f 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -447,10 +447,14 @@
     return has_will_change_transform_hint_;
   }
 
-  void SetPreferredRasterScale(float raster_scale);
-  bool has_preferred_raster_scale() { return has_preferred_raster_scale_; }
-  float preferred_raster_scale() const { return preferred_raster_scale_; }
-  void ClearPreferredRasterScale();
+  void SetPreferredRasterBounds(const gfx::Size& preferred_raster_bounds);
+  bool has_preferred_raster_bounds() const {
+    return has_preferred_raster_bounds_;
+  }
+  const gfx::Size& preferred_raster_scale() const {
+    return preferred_raster_bounds_;
+  }
+  void ClearPreferredRasterBounds();
 
   AnimationHost* GetAnimationHost() const;
 
@@ -568,9 +572,9 @@
       owned_debug_info_;
   base::trace_event::ConvertableToTraceFormat* debug_info_;
   std::unique_ptr<RenderSurfaceImpl> render_surface_;
-  float preferred_raster_scale_;
+  gfx::Size preferred_raster_bounds_;
 
-  bool has_preferred_raster_scale_ : 1;
+  bool has_preferred_raster_bounds_ : 1;
   bool scrolls_drawn_descendant_ : 1;
   bool has_will_change_transform_hint_ : 1;
   bool needs_push_properties_ : 1;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 0c28f8a..9a6842fd 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3966,6 +3966,10 @@
   return animation_host_->AnimationsPreserveAxisAlignment(layer->element_id());
 }
 
+void LayerTreeHostImpl::SetNeedUpdateGpuRasterizationStatus() {
+  need_update_gpu_rasterization_status_ = true;
+}
+
 void LayerTreeHostImpl::SetElementFilterMutated(
     ElementId element_id,
     ElementListType list_type,
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index cb3c955..6d97f27 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -268,6 +268,7 @@
                                        LayerTreeImpl* tree,
                                        const gfx::ScrollOffset& scroll_offset);
   bool AnimationsPreserveAxisAlignment(const LayerImpl* layer) const;
+  void SetNeedUpdateGpuRasterizationStatus();
 
   // MutatorHostClient implementation.
   bool IsElementInList(ElementId element_id,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index d78e07a24..d73bf728 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -11110,15 +11110,9 @@
   EXPECT_FALSE(controller.did_draw_frame());
 }
 
-TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusModes) {
-  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
-
-  host_impl_->SetHasGpuRasterizationTrigger(true);
-  host_impl_->SetContentIsSuitableForGpuRasterization(true);
-  host_impl_->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
-  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
-
+// Tests that SetHasGpuRasterizationTrigger behaves as expected.
+TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusTrigger) {
+  // Set initial state, before varying GPU rasterization trigger.
   host_impl_->SetHasGpuRasterizationTrigger(false);
   host_impl_->SetContentIsSuitableForGpuRasterization(true);
   host_impl_->CommitComplete();
@@ -11126,22 +11120,94 @@
             host_impl_->gpu_rasterization_status());
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
 
+  // Toggle the trigger on.
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+
+  // And off.
+  host_impl_->SetHasGpuRasterizationTrigger(false);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::OFF_VIEWPORT,
+            host_impl_->gpu_rasterization_status());
+  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+}
+
+// Tests that SetContentIsSuitableForGpuRasterization behaves as expected.
+TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusSuitability) {
+  // Set initial state, before varying GPU rasterization suitability.
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentIsSuitableForGpuRasterization(false);
   host_impl_->CommitComplete();
   EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
             host_impl_->gpu_rasterization_status());
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+
+  // Toggle suitability on.
+  host_impl_->SetContentIsSuitableForGpuRasterization(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());
 
+  // And off.
+  host_impl_->SetContentIsSuitableForGpuRasterization(false);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+            host_impl_->gpu_rasterization_status());
+  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+  EXPECT_FALSE(host_impl_->use_msaa());
+}
+
+// Tests that SetDeviceScaleFactor correctly impacts GPU rasterization.
+TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusDeviceScaleFactor) {
+  // Create a host impl with MSAA support.
   std::unique_ptr<TestWebGraphicsContext3D> context_with_msaa =
       TestWebGraphicsContext3D::Create();
-  context_with_msaa->SetMaxSamples(8);
+  context_with_msaa->SetMaxSamples(4);
+  LayerTreeSettings msaaSettings = GpuRasterizationEnabledSettings();
+  msaaSettings.gpu_rasterization_msaa_sample_count = -1;
+  EXPECT_TRUE(CreateHostImpl(msaaSettings, FakeCompositorFrameSink::Create3d(
+                                               std::move(context_with_msaa))));
 
+  // Set initial state, before varying scale factor.
+  host_impl_->SetHasGpuRasterizationTrigger(true);
+  host_impl_->SetContentIsSuitableForGpuRasterization(false);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+            host_impl_->gpu_rasterization_status());
+  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+
+  // Set device scale factor to 2, which lowers the required MSAA samples from
+  // 8 to 4.
+  host_impl_->active_tree()->SetDeviceScaleFactor(2.0f);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
+            host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+  EXPECT_TRUE(host_impl_->use_msaa());
+
+  // Set device scale factor back to 1.
+  host_impl_->active_tree()->SetDeviceScaleFactor(1.0f);
+  host_impl_->CommitComplete();
+  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+            host_impl_->gpu_rasterization_status());
+  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+  EXPECT_FALSE(host_impl_->use_msaa());
+}
+
+// Tests that explicit MSAA sample count correctly impacts GPU rasterization.
+TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusExplicitMSAACount) {
+  // Create a host impl with MSAA support and a forced sample count of 4.
+  std::unique_ptr<TestWebGraphicsContext3D> context_with_msaa =
+      TestWebGraphicsContext3D::Create();
+  context_with_msaa->SetMaxSamples(4);
   LayerTreeSettings msaaSettings = GpuRasterizationEnabledSettings();
   msaaSettings.gpu_rasterization_msaa_sample_count = 4;
   EXPECT_TRUE(CreateHostImpl(msaaSettings, FakeCompositorFrameSink::Create3d(
                                                std::move(context_with_msaa))));
+
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentIsSuitableForGpuRasterization(false);
   host_impl_->CommitComplete();
@@ -11149,7 +11215,11 @@
             host_impl_->gpu_rasterization_status());
   EXPECT_TRUE(host_impl_->use_gpu_rasterization());
   EXPECT_TRUE(host_impl_->use_msaa());
+}
 
+// Tests that GPU rasterization overrides work as expected.
+TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusOverrides) {
+  // GPU rasterization explicitly disabled.
   LayerTreeSettings settings = DefaultSettings();
   settings.gpu_rasterization_enabled = false;
   EXPECT_TRUE(CreateHostImpl(settings, FakeCompositorFrameSink::Create3d()));
@@ -11160,6 +11230,7 @@
             host_impl_->gpu_rasterization_status());
   EXPECT_FALSE(host_impl_->use_gpu_rasterization());
 
+  // GPU rasterization explicitly forced.
   settings.gpu_rasterization_forced = true;
   EXPECT_TRUE(CreateHostImpl(settings, FakeCompositorFrameSink::Create3d()));
 
diff --git a/cc/trees/layer_tree_host_in_process.cc b/cc/trees/layer_tree_host_in_process.cc
index bc72f510..138f16b 100644
--- a/cc/trees/layer_tree_host_in_process.cc
+++ b/cc/trees/layer_tree_host_in_process.cc
@@ -462,10 +462,6 @@
   RecordGpuRasterizationHistogram();
 
   host_impl->SetViewportSize(layer_tree_->device_viewport_size());
-  // TODO(senorblanco): Move this to LayerTree::PushPropertiesTo so that it
-  // happens before GPU rasterization properties are set, since those trigger an
-  // update of GPU rasterization status, which depends on the device scale
-  // factor. (crbug.com/535700)
   sync_tree->SetDeviceScaleFactor(layer_tree_->device_scale_factor());
   host_impl->SetDebugState(debug_state_);
 
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 89035df5..70e352dd 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -858,6 +858,7 @@
   set_needs_update_draw_properties();
   if (IsActiveTree())
     layer_tree_host_impl_->SetFullViewportDamage();
+  layer_tree_host_impl_->SetNeedUpdateGpuRasterizationStatus();
 }
 
 void LayerTreeImpl::SetDeviceColorSpace(
@@ -1362,17 +1363,19 @@
   DCHECK(!settings().scrollbar_fade_duration.is_zero());
   base::TimeDelta delay = settings().scrollbar_fade_delay;
   base::TimeDelta resize_delay = settings().scrollbar_fade_resize_delay;
-  base::TimeDelta duration = settings().scrollbar_fade_duration;
+  base::TimeDelta fade_duration = settings().scrollbar_fade_duration;
   switch (settings().scrollbar_animator) {
     case LayerTreeSettings::LINEAR_FADE: {
       return ScrollbarAnimationControllerLinearFade::Create(
           scroll_layer_id, layer_tree_host_impl_, delay, resize_delay,
-          duration);
+          fade_duration);
     }
     case LayerTreeSettings::THINNING: {
+      base::TimeDelta thinning_duration =
+          settings().scrollbar_thinning_duration;
       return ScrollbarAnimationControllerThinning::Create(
           scroll_layer_id, layer_tree_host_impl_, delay, resize_delay,
-          duration);
+          fade_duration, thinning_duration);
     }
     case LayerTreeSettings::NO_ANIMATOR:
       NOTREACHED();
diff --git a/chrome/VERSION b/chrome/VERSION
index 9b8a705..0d56692b 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=56
 MINOR=0
-BUILD=2897
+BUILD=2898
 PATCH=0
diff --git a/chrome/android/java/res/color/item_chooser_row_text_color.xml b/chrome/android/java/res/color/item_chooser_row_text_color.xml
new file mode 100644
index 0000000..a5f0b24
--- /dev/null
+++ b/chrome/android/java/res/color/item_chooser_row_text_color.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2016 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/white" android:state_activated="true"/>
+  <item android:color="@color/primary_text_disabled_material_light" android:state_enabled="false"/>
+  <item android:color="@color/default_text_color"/>
+</selector>
diff --git a/chrome/android/java/res/drawable/item_chooser_row_background.xml b/chrome/android/java/res/drawable/item_chooser_row_background.xml
new file mode 100644
index 0000000..e67f07b8
--- /dev/null
+++ b/chrome/android/java/res/drawable/item_chooser_row_background.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2016 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:drawable="@color/light_active_color" android:state_activated="true"/>
+  <item android:drawable="@android:color/transparent"/>
+</selector>
diff --git a/chrome/android/java/res/layout/item_chooser_dialog_row.xml b/chrome/android/java/res/layout/item_chooser_dialog_row.xml
index f36586a3..a3543dc 100644
--- a/chrome/android/java/res/layout/item_chooser_dialog_row.xml
+++ b/chrome/android/java/res/layout/item_chooser_dialog_row.xml
@@ -2,12 +2,18 @@
 <!-- Copyright 2015 The Chromium Authors. All rights reserved.
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="48dp"
-    android:paddingStart="16dp"
-    android:paddingEnd="16dp"
-    android:ellipsize="end"
-    android:gravity="center_vertical"
-    android:singleLine="true" />
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="48dp"
+                android:paddingStart="16dp"
+                android:paddingEnd="16dp"
+                android:background="@drawable/item_chooser_row_background">
+    <TextView
+        android:id="@+id/description"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ellipsize="end"
+        android:maxLines="1"
+        android:textColor="@color/item_chooser_row_text_color"
+        android:layout_centerVertical="true"/>
+</RelativeLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
index c3bece9..3d2289f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java
@@ -338,8 +338,7 @@
     @VisibleForTesting
     @CalledByNative
     void addOrUpdateDevice(String deviceId, String deviceName) {
-        mItemChooserDialog.addOrUpdateItem(
-                new ItemChooserDialog.ItemChooserRow(deviceId, deviceName));
+        mItemChooserDialog.addOrUpdateItem(deviceId, deviceName);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
index 50de5333..b71813a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
@@ -11,6 +11,7 @@
 import android.graphics.Color;
 import android.graphics.drawable.ColorDrawable;
 import android.text.SpannableString;
+import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -26,7 +27,6 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.util.MathUtils;
@@ -71,17 +71,16 @@
             mDescription = description;
         }
 
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ItemChooserRow)) return false;
-            if (this == obj) return true;
-            ItemChooserRow item = (ItemChooserRow) obj;
-            return mKey.equals(item.mKey) && mDescription.equals(item.mDescription);
-        }
-
-        @Override
-        public int hashCode() {
-            return mKey.hashCode() + mDescription.hashCode();
+        /**
+         * Returns true if all parameters match the corresponding member.
+         *
+         * @param key Expected item unique identifier.
+         * @param description Expected item description.
+         */
+        public boolean hasSameContents(String key, String description) {
+            if (!TextUtils.equals(mKey, key)) return false;
+            if (!TextUtils.equals(mDescription, description)) return false;
+            return true;
         }
     }
 
@@ -121,6 +120,17 @@
     }
 
     /**
+     * Item holder for performance boost.
+     */
+    private static class ViewHolder {
+        private TextView mTextView;
+
+        public ViewHolder(View view) {
+            mTextView = (TextView) view.findViewById(R.id.description);
+        }
+    }
+
+    /**
      * The various states the dialog can represent.
      */
     private enum State { STARTING, PROGRESS_UPDATE_AVAILABLE, DISCOVERY_IDLE }
@@ -132,12 +142,6 @@
             implements AdapterView.OnItemClickListener {
         private final LayoutInflater mInflater;
 
-        // The background color of the highlighted item.
-        private final int mBackgroundHighlightColor;
-
-        // The color of the non-highlighted text.
-        private final int mDefaultTextColor;
-
         // The zero-based index of the item currently selected in the dialog,
         // or -1 (INVALID_POSITION) if nothing is selected.
         private int mSelectedItem = ListView.INVALID_POSITION;
@@ -155,11 +159,6 @@
             super(context, resource);
 
             mInflater = LayoutInflater.from(context);
-
-            mBackgroundHighlightColor = ApiCompatibilityUtils.getColor(getContext().getResources(),
-                    R.color.light_active_color);
-            mDefaultTextColor = ApiCompatibilityUtils.getColor(getContext().getResources(),
-                    R.color.default_text_color);
         }
 
         @Override
@@ -176,31 +175,34 @@
             return isEmpty;
         }
 
-        public void addOrUpdate(ItemChooserRow item) {
-            ItemChooserRow oldItem = mKeyToItemMap.get(item.mKey);
+        public void addOrUpdate(String key, String description) {
+            ItemChooserRow oldItem = mKeyToItemMap.get(key);
             if (oldItem != null) {
-                if (oldItem.equals(item)) {
+                if (oldItem.hasSameContents(key, description)) {
                     // No need to update anything.
                     return;
                 }
-                if (!oldItem.mDescription.equals(item.mDescription)) {
+
+                if (!TextUtils.equals(oldItem.mDescription, description)) {
                     removeFromDescriptionsMap(oldItem.mDescription);
-                    oldItem.mDescription = item.mDescription;
+                    oldItem.mDescription = description;
                     addToDescriptionsMap(oldItem.mDescription);
                 }
+
                 notifyDataSetChanged();
                 return;
             }
-            ItemChooserRow result = mKeyToItemMap.put(item.mKey, item);
-            assert result == null;
 
-            addToDescriptionsMap(item.mDescription);
-            add(item);
+            assert !mKeyToItemMap.containsKey(key);
+            ItemChooserRow newItem = new ItemChooserRow(key, description);
+            mKeyToItemMap.put(key, newItem);
+
+            addToDescriptionsMap(newItem.mDescription);
+            add(newItem);
         }
 
-        @Override
-        public void remove(ItemChooserRow item) {
-            ItemChooserRow oldItem = mKeyToItemMap.remove(item.mKey);
+        public void removeItemWithKey(String key) {
+            ItemChooserRow oldItem = mKeyToItemMap.remove(key);
             if (oldItem == null) return;
             int oldItemPosition = getPosition(oldItem);
             // If the removed item is the item that is currently selected, deselect it
@@ -292,37 +294,26 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            TextView view;
-            if (convertView instanceof TextView) {
-                view = (TextView) convertView;
+            ViewHolder row;
+            if (convertView == null) {
+                convertView = mInflater.inflate(R.layout.item_chooser_dialog_row, parent, false);
+                row = new ViewHolder(convertView);
+                convertView.setTag(row);
             } else {
-                view = (TextView) mInflater.inflate(
-                        R.layout.item_chooser_dialog_row, parent, false);
+                row = (ViewHolder) convertView.getTag();
             }
 
-            // Set highlighting for currently selected item.
-            if (position == mSelectedItem) {
-                view.setBackgroundColor(mBackgroundHighlightColor);
-                view.setTextColor(Color.WHITE);
-            } else {
-                view.setBackground(null);
-                if (!isEnabled(position)) {
-                    view.setTextColor(ApiCompatibilityUtils.getColor(getContext().getResources(),
-                            R.color.primary_text_disabled_material_light));
-                } else {
-                    view.setTextColor(mDefaultTextColor);
-                }
-            }
+            row.mTextView.setEnabled(isEnabled(position));
+            row.mTextView.setText(getDisplayText(position));
 
-            view.setText(getDisplayText(position));
-            return view;
+            return convertView;
         }
 
         @Override
         public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
             mSelectedItem = position;
             mConfirmButton.setEnabled(true);
-            mItemAdapter.notifyDataSetChanged();
+            notifyDataSetChanged();
         }
 
         private void addToDescriptionsMap(String description) {
@@ -421,6 +412,7 @@
         mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_row);
         mItemAdapter.setNotifyOnChange(true);
         mListView.setAdapter(mItemAdapter);
+        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
         mListView.setEmptyView(mEmptyMessage);
         mListView.setOnItemClickListener(mItemAdapter);
         mListView.setDivider(null);
@@ -486,24 +478,25 @@
     }
 
     /**
-    * Add an item to the end of the list to show in the dialog if the item
-    * was not in the chooser. Otherwise update the items description.
-    *
-    * @param item The item to be added to the end of the chooser or updated.
-    */
-    public void addOrUpdateItem(ItemChooserRow item) {
+     * Adds an item to the end of the list to show in the dialog if the item
+     * was not in the chooser. Otherwise updates the items description.
+     *
+     * @param key Unique identifier for that item.
+     * @param description Text in the row.
+     */
+    public void addOrUpdateItem(String key, String description) {
         mProgressBar.setVisibility(View.GONE);
-        mItemAdapter.addOrUpdate(item);
+        mItemAdapter.addOrUpdate(key, description);
         setState(State.PROGRESS_UPDATE_AVAILABLE);
     }
 
     /**
-    * Remove an item that is shown in the dialog.
-    *
-    * @param item The item to be removed in the chooser.
-    */
-    public void removeItemFromList(ItemChooserRow item) {
-        mItemAdapter.remove(item);
+     * Removes an item that is shown in the dialog.
+     *
+     * @param key Unique identifier for the item.
+     */
+    public void removeItemFromList(String key) {
+        mItemAdapter.removeItemWithKey(key);
         setState(State.DISCOVERY_IDLE);
     }
 
@@ -517,11 +510,11 @@
 
     /**
      * Sets whether the item is enabled.
-     * @param id The id of the item to affect.
+     * @param key Unique indetifier for the item.
      * @param enabled Whether the item should be enabled or not.
      */
-    public void setEnabled(String id, boolean enabled) {
-        mItemAdapter.setEnabled(id, enabled);
+    public void setEnabled(String key, boolean enabled) {
+        mItemAdapter.setEnabled(key, enabled);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java
index 08b7dc1..9f58988 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/UsbChooserDialog.java
@@ -125,14 +125,12 @@
     @VisibleForTesting
     @CalledByNative
     void addDevice(String deviceId, String deviceName) {
-        mItemChooserDialog.addOrUpdateItem(
-                new ItemChooserDialog.ItemChooserRow(deviceId, deviceName));
+        mItemChooserDialog.addOrUpdateItem(deviceId, deviceName);
     }
 
     @CalledByNative
-    private void removeDevice(String deviceId, String deviceName) {
-        mItemChooserDialog.removeItemFromList(
-                new ItemChooserDialog.ItemChooserRow(deviceId, deviceName));
+    private void removeDevice(String deviceId) {
+        mItemChooserDialog.removeItemFromList(deviceId);
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
index e1df0422..7c44e26 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
@@ -22,9 +22,9 @@
 import android.widget.RemoteViews;
 
 import org.chromium.base.Log;
-import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.metrics.LaunchMetrics;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
@@ -35,10 +35,10 @@
  */
 class CustomTabBottomBarDelegate {
     private static final String TAG = "CustomTab";
-    private static final CachedMetrics.ActionEvent REMOTE_VIEWS_SHOWN =
-            new CachedMetrics.ActionEvent("CustomTabsRemoteViewsShown");
-    private static final CachedMetrics.ActionEvent REMOTE_VIEWS_UPDATED =
-            new CachedMetrics.ActionEvent("CustomTabsRemoteViewsUpdated");
+    private static final LaunchMetrics.ActionEvent REMOTE_VIEWS_SHOWN =
+            new LaunchMetrics.ActionEvent("CustomTabsRemoteViewsShown");
+    private static final LaunchMetrics.ActionEvent REMOTE_VIEWS_UPDATED =
+            new LaunchMetrics.ActionEvent("CustomTabsRemoteViewsUpdated");
     private static final int SLIDE_ANIMATION_DURATION_MS = 400;
     private ChromeActivity mActivity;
     private ViewGroup mBottomBarView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index b893850..a452147 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -25,7 +25,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.TraceEvent;
-import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeSwitches;
@@ -43,6 +42,7 @@
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
 import org.chromium.chrome.browser.firstrun.LightweightFirstRunActivity;
 import org.chromium.chrome.browser.instantapps.InstantAppsHandler;
+import org.chromium.chrome.browser.metrics.LaunchMetrics;
 import org.chromium.chrome.browser.metrics.MediaNotificationUma;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.notifications.NotificationPlatformBridge;
@@ -87,8 +87,8 @@
      */
     private static final int PARTNER_BROWSER_CUSTOMIZATIONS_TIMEOUT_MS = 10000;
 
-    private static final CachedMetrics.SparseHistogramSample sIntentFlagsHistogram =
-            new CachedMetrics.SparseHistogramSample("Launch.IntentFlags");
+    private static final LaunchMetrics.SparseHistogramSample sIntentFlagsHistogram =
+            new LaunchMetrics.SparseHistogramSample("Launch.IntentFlags");
 
     private IntentHandler mIntentHandler;
     private boolean mIsInLegacyMultiInstanceMode;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
index d1a18e6..d986610 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java
@@ -21,9 +21,9 @@
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.base.metrics.CachedMetrics.SparseHistogramSample;
-import org.chromium.base.metrics.CachedMetrics.TimesHistogramSample;
 import org.chromium.chrome.browser.ChromeApplication;
+import org.chromium.chrome.browser.metrics.LaunchMetrics.SparseHistogramSample;
+import org.chromium.chrome.browser.metrics.LaunchMetrics.TimesHistogramSample;
 
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
index 7461ca17..c913dfe2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalauth/UserRecoverableErrorHandler.java
@@ -11,7 +11,7 @@
 import com.google.android.gms.common.GoogleApiAvailability;
 
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample;
+import org.chromium.chrome.browser.metrics.LaunchMetrics.EnumeratedHistogramSample;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
index e512bed..d88fac1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java
@@ -15,11 +15,11 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.FieldTrialList;
 import org.chromium.base.Log;
-import org.chromium.base.metrics.CachedMetrics.TimesHistogramSample;
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
+import org.chromium.chrome.browser.metrics.LaunchMetrics.TimesHistogramSample;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.content_public.browser.WebContents;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java
index f74cf9b8..ad58bb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java
@@ -7,11 +7,14 @@
 import android.util.Pair;
 
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.metrics.CachedMetrics;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Used for recording metrics about Chrome launches that need to be recorded before the native
@@ -20,6 +23,150 @@
  */
 @JNINamespace("metrics")
 public class LaunchMetrics {
+
+    /**
+     * Creating an instance of a subclass of this class automatically adds it to a list of objects
+     * that are committed when the native library is available.
+     */
+    private abstract static class CachedHistogram {
+        private static final List<CachedHistogram> sEvents = new ArrayList<CachedHistogram>();
+
+        protected final String mHistogramName;
+
+        /**
+         * @param histogramName Name of the histogram to record.
+         */
+        protected CachedHistogram(String histogramName) {
+            mHistogramName = histogramName;
+            sEvents.add(this);
+        }
+
+        /** Commits the histogram. Expects the native library to be loaded. */
+        protected abstract void commitAndClear();
+    }
+
+    /**
+     * Caches an action that will be recorded after native side is loaded.
+     */
+    public static class ActionEvent extends CachedHistogram {
+        private int mCount;
+
+        public ActionEvent(String actionName) {
+            super(actionName);
+        }
+
+        public void record() {
+            if (LibraryLoader.isInitialized()) {
+                recordWithNative();
+            } else {
+                mCount++;
+            }
+        }
+
+        private void recordWithNative() {
+            RecordUserAction.record(mHistogramName);
+        }
+
+        @Override
+        protected void commitAndClear() {
+            while (mCount > 0) {
+                recordWithNative();
+                mCount--;
+            }
+        }
+    }
+
+    /** Caches a set of integer histogram samples. */
+    public static class SparseHistogramSample extends CachedHistogram {
+        private final List<Integer> mSamples = new ArrayList<Integer>();
+
+        public SparseHistogramSample(String histogramName) {
+            super(histogramName);
+        }
+
+        public void record(int sample) {
+            if (LibraryLoader.isInitialized()) {
+                recordWithNative(sample);
+            } else {
+                mSamples.add(sample);
+            }
+        }
+
+        private void recordWithNative(int sample) {
+            RecordHistogram.recordSparseSlowlyHistogram(mHistogramName, sample);
+        }
+
+        @Override
+        protected void commitAndClear() {
+            for (Integer sample : mSamples) {
+                recordWithNative(sample);
+            }
+            mSamples.clear();
+        }
+    }
+
+    /** Caches a set of enumerated histogram samples. */
+    public static class EnumeratedHistogramSample extends CachedHistogram {
+        private final List<Integer> mSamples = new ArrayList<Integer>();
+        private final int mMaxValue;
+
+        public EnumeratedHistogramSample(String histogramName, int maxValue) {
+            super(histogramName);
+            mMaxValue = maxValue;
+        }
+
+        public void record(int sample) {
+            if (LibraryLoader.isInitialized()) {
+                recordWithNative(sample);
+            } else {
+                mSamples.add(sample);
+            }
+        }
+
+        private void recordWithNative(int sample) {
+            RecordHistogram.recordEnumeratedHistogram(mHistogramName, sample, mMaxValue);
+        }
+
+        @Override
+        protected void commitAndClear() {
+            for (Integer sample : mSamples) {
+                recordWithNative(sample);
+            }
+            mSamples.clear();
+        }
+    }
+
+    /** Caches a set of times histogram samples. */
+    public static class TimesHistogramSample extends CachedHistogram {
+        private final List<Long> mSamples = new ArrayList<Long>();
+        private final TimeUnit mTimeUnit;
+
+        public TimesHistogramSample(String histogramName, TimeUnit timeUnit) {
+            super(histogramName);
+            mTimeUnit = timeUnit;
+        }
+
+        public void record(long sample) {
+            if (LibraryLoader.isInitialized()) {
+                recordWithNative(sample);
+            } else {
+                mSamples.add(sample);
+            }
+        }
+
+        private void recordWithNative(long sample) {
+            RecordHistogram.recordTimesHistogram(mHistogramName, sample, mTimeUnit);
+        }
+
+        @Override
+        protected void commitAndClear() {
+            for (Long sample : mSamples) {
+                recordWithNative(sample);
+            }
+            mSamples.clear();
+        }
+    }
+
     // Each list item is a pair of the url and where it was added from e.g. from the add to
     // homescreen menu item, an app banner, or unknown. The mapping of int source values to
     // their string names is found in the C++ ShortcutInfo struct.
@@ -75,7 +222,7 @@
         sTabUrls.clear();
 
         // Record generic cached events.
-        CachedMetrics.commitCachedMetrics();
+        for (CachedHistogram event : CachedHistogram.sEvents) event.commitAndClear();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/MediaNotificationUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/MediaNotificationUma.java
index d13b46f2..625c1f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/MediaNotificationUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/MediaNotificationUma.java
@@ -4,7 +4,7 @@
 
 package org.chromium.chrome.browser.metrics;
 
-import static org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample;
+import static org.chromium.chrome.browser.metrics.LaunchMetrics.EnumeratedHistogramSample;
 
 import android.content.Intent;
 
@@ -23,7 +23,8 @@
             "org.chromium.chrome.browser.metrics.MediaNotificationUma.EXTRA_CLICK_SOURCE";
 
     private static final EnumeratedHistogramSample sClickSourceHistogram =
-            new EnumeratedHistogramSample("Media.Notification.Click", SOURCE_MAX);
+            new LaunchMetrics.EnumeratedHistogramSample(
+                    "Media.Notification.Click", SOURCE_MAX);
 
     /**
      * Record the UMA as specified by {@link intent}. The {@link intent} should contain intent extra
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java
index 37c9fd1..146e20b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillContact.java
@@ -16,6 +16,7 @@
  */
 public class AutofillContact extends PaymentOption {
     private final AutofillProfile mProfile;
+    @Nullable private String mPayerName;
     @Nullable private String mPayerPhone;
     @Nullable private String mPayerEmail;
 
@@ -23,17 +24,24 @@
      * Builds contact details.
      *
      * @param profile    The autofill profile where this contact data lives.
-     * @param phone      The phone number. If not empty, this will be the primary label.
-     * @param email      The email address. If phone is empty, this will be the primary label.
+     * @param name       The payer name. If not empty, this will be the primary label.
+     * @param phone      The phone number. If name is empty, this will be the primary label.
+     * @param email      The email address. If name and phone are empty, this will be the primary
+     *                   label.
      * @param isComplete Whether the data in this contact can be sent to the merchant as-is. If
      *                   false, user needs to add more information here.
      */
-    public AutofillContact(AutofillProfile profile, @Nullable String phone, @Nullable String email,
-            boolean isComplete) {
+    public AutofillContact(AutofillProfile profile, @Nullable String name,
+            @Nullable String phone, @Nullable String email, boolean isComplete) {
         super(profile.getGUID(), null, null, PaymentOption.NO_ICON);
         mProfile = profile;
         mIsComplete = isComplete;
-        setGuidPhoneEmail(profile.getGUID(), phone, email);
+        setContactInfo(profile.getGUID(), name, phone, email);
+    }
+
+    /** @return Payer name. Null if the merchant did not request it or data is incomplete. */
+    @Nullable public String getPayerName() {
+        return mPayerName;
     }
 
     /** @return Email address. Null if the merchant did not request it or data is incomplete. */
@@ -52,23 +60,35 @@
     }
 
     /**
-     * Updates the profile guid, email address, and phone number and marks this information
-     * "complete." Called after the user has edited this contact information. Updates the
-     * identifier, label, and sublabel.
+     * Updates the profile guid, payer name, email address, and phone number and marks this
+     * information "complete." Called after the user has edited this contact information.
+     * Update the identifier, label, sublabel, and tertiarylabel.
      *
      * @param guid  The new identifier to use. Should not be null or empty.
-     * @param phone The new phone number to use. If not empty, this will be the primary label.
-     * @param email The new email address to use. If phone is empty, this will be the primary label.
+     * @param name  The new payer name to use. If not empty, this will be the primary label.
+     * @param phone The new phone number to use. If name is empty, this will be the primary label.
+     * @param email The new email address to use. If email and phone are empty, this will be the
+     *              primary label.
      */
-    public void completeContact(String guid, @Nullable String phone, @Nullable String email) {
+    public void completeContact(String guid, @Nullable String name,
+            @Nullable String phone, @Nullable String email) {
         mIsComplete = true;
-        setGuidPhoneEmail(guid, phone, email);
+        setContactInfo(guid, name, phone, email);
     }
 
-    private void setGuidPhoneEmail(String guid, @Nullable String phone, @Nullable String email) {
+    private void setContactInfo(String guid, @Nullable String name,
+            @Nullable String phone, @Nullable String email) {
+        mPayerName = TextUtils.isEmpty(name) ? null : name;
         mPayerPhone = TextUtils.isEmpty(phone) ? null : phone;
         mPayerEmail = TextUtils.isEmpty(email) ? null : email;
-        updateIdentifierAndLabels(guid, mPayerPhone == null ? mPayerEmail : mPayerPhone,
-                mPayerPhone == null ? null : mPayerEmail);
+
+        if (mPayerName == null) {
+            updateIdentifierAndLabels(guid, mPayerPhone == null ? mPayerEmail : mPayerPhone,
+                    mPayerPhone == null ? null : mPayerEmail);
+        } else {
+            updateIdentifierAndLabels(guid, mPayerName,
+                    mPayerPhone == null ? mPayerEmail : mPayerPhone,
+                    mPayerPhone == null ? null : mPayerEmail);
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
index bade26f..0fac706 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ContactEditor.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.payments;
 
 import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
 import android.util.Patterns;
 
 import org.chromium.base.Callback;
@@ -24,8 +25,10 @@
  * Contact information editor.
  */
 public class ContactEditor extends EditorBase<AutofillContact> {
+    private final boolean mRequestPayerName;
     private final boolean mRequestPayerPhone;
     private final boolean mRequestPayerEmail;
+    private final Set<CharSequence> mPayerNames;
     private final Set<CharSequence> mPhoneNumbers;
     private final Set<CharSequence> mEmailAddresses;
     @Nullable private EditorFieldValidator mPhoneValidator;
@@ -34,13 +37,17 @@
     /**
      * Builds a contact information editor.
      *
+     * @param requestPayerName Whether to request the user's name.
      * @param requestPayerPhone Whether to request the user's phone number.
      * @param requestPayerEmail Whether to request the user's email address.
      */
-    public ContactEditor(boolean requestPayerPhone, boolean requestPayerEmail) {
-        assert requestPayerPhone || requestPayerEmail;
+    public ContactEditor(boolean requestPayerName,
+            boolean requestPayerPhone, boolean requestPayerEmail) {
+        assert requestPayerName || requestPayerPhone || requestPayerEmail;
+        mRequestPayerName = requestPayerName;
         mRequestPayerPhone = requestPayerPhone;
         mRequestPayerEmail = requestPayerEmail;
+        mPayerNames = new HashSet<>();
         mPhoneNumbers = new HashSet<>();
         mEmailAddresses = new HashSet<>();
     }
@@ -49,16 +56,28 @@
      * Returns whether the following contact information can be sent to the merchant as-is without
      * editing first.
      *
+     * @param name  The payer name to check.
      * @param phone The phone number to check.
      * @param email The email address to check.
      * @return Whether the contact information is complete.
      */
-    public boolean isContactInformationComplete(@Nullable String phone, @Nullable String email) {
-        return (!mRequestPayerPhone || getPhoneValidator().isValid(phone))
+    public boolean isContactInformationComplete(
+            @Nullable String name, @Nullable String phone, @Nullable String email) {
+        return (!mRequestPayerName || !TextUtils.isEmpty(name))
+                && (!mRequestPayerPhone || getPhoneValidator().isValid(phone))
                 && (!mRequestPayerEmail || getEmailValidator().isValid(email));
     }
 
     /**
+     * Adds the given payer name to the autocomplete set, if it's valid.
+     *
+     * @param payerName The payer name to possibly add.
+     */
+    public void addPayerNameIfValid(@Nullable CharSequence payerName) {
+        if (!TextUtils.isEmpty(payerName)) mPayerNames.add(payerName);
+    }
+
+    /**
      * Adds the given phone number to the autocomplete set, if it's valid.
      *
      * @param phoneNumber The phone number to possibly add.
@@ -81,7 +100,15 @@
         super.edit(toEdit, callback);
 
         final AutofillContact contact = toEdit == null
-                ? new AutofillContact(new AutofillProfile(), null, null, false) : toEdit;
+                ? new AutofillContact(new AutofillProfile(), null, null, null, false) : toEdit;
+
+        final EditorFieldModel nameField = mRequestPayerName
+                ? EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME,
+                          mContext.getString(R.string.payments_name_field_in_contact_details),
+                          mPayerNames, null,
+                          mContext.getString(R.string.payments_field_required_validation_message),
+                          null, contact.getPayerName())
+                : null;
 
         final EditorFieldModel phoneField = mRequestPayerPhone
                 ? EditorFieldModel.createTextInput(EditorFieldModel.INPUT_TYPE_HINT_PHONE,
@@ -104,6 +131,7 @@
         EditorModel editor = new EditorModel(
                 mContext.getString(toEdit == null ? R.string.payments_add_contact_details_label
                                                   : R.string.payments_edit_contact_details_label));
+        if (nameField != null) editor.addField(nameField);
         if (phoneField != null) editor.addField(phoneField);
         if (emailField != null) editor.addField(emailField);
 
@@ -117,9 +145,15 @@
         editor.setDoneCallback(new Runnable() {
             @Override
             public void run() {
+                String name = null;
                 String phone = null;
                 String email = null;
 
+                if (nameField != null) {
+                    name = nameField.getValue().toString();
+                    contact.getProfile().setFullName(name);
+                }
+
                 if (phoneField != null) {
                     phone = phoneField.getValue().toString();
                     contact.getProfile().setPhoneNumber(phone);
@@ -131,7 +165,7 @@
                 }
 
                 String guid = PersonalDataManager.getInstance().setProfile(contact.getProfile());
-                contact.completeContact(guid, phone, email);
+                contact.completeContact(guid, name, phone, email);
                 callback.onResult(contact);
             }
         });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 44bc75d..0535e1ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -271,11 +271,12 @@
         getMatchingPaymentInstruments();
 
         boolean requestShipping = options != null && options.requestShipping;
+        boolean requestPayerName = options != null && options.requestPayerName;
         boolean requestPayerPhone = options != null && options.requestPayerPhone;
         boolean requestPayerEmail = options != null && options.requestPayerEmail;
 
         List<AutofillProfile> profiles = null;
-        if (requestShipping || requestPayerPhone || requestPayerEmail) {
+        if (requestShipping || requestPayerName || requestPayerPhone || requestPayerEmail) {
             profiles = PersonalDataManager.getInstance().getProfilesToSuggest(
                     false /* includeNameInLabel */);
         }
@@ -324,30 +325,34 @@
                             firstCompleteAddressIndex, addresses);
         }
 
-        if (requestPayerPhone || requestPayerEmail) {
+        if (requestPayerName || requestPayerPhone || requestPayerEmail) {
             Set<String> uniqueContactInfos = new HashSet<>();
-            mContactEditor = new ContactEditor(requestPayerPhone, requestPayerEmail);
+            mContactEditor = new ContactEditor(
+                    requestPayerName, requestPayerPhone, requestPayerEmail);
             List<AutofillContact> contacts = new ArrayList<>();
 
             for (int i = 0; i < profiles.size(); i++) {
                 AutofillProfile profile = profiles.get(i);
+                String name = requestPayerName && !TextUtils.isEmpty(profile.getFullName())
+                        ? profile.getFullName() : null;
                 String phone = requestPayerPhone && !TextUtils.isEmpty(profile.getPhoneNumber())
                         ? profile.getPhoneNumber() : null;
                 String email = requestPayerEmail && !TextUtils.isEmpty(profile.getEmailAddress())
                         ? profile.getEmailAddress() : null;
+                mContactEditor.addPayerNameIfValid(name);
                 mContactEditor.addPhoneNumberIfValid(phone);
                 mContactEditor.addEmailAddressIfValid(email);
 
-                if (phone != null || email != null) {
+                if (name != null || phone != null || email != null) {
                     // Different profiles can have identical contact info. Do not add the same
                     // contact info to the list twice.
-                    String uniqueContactInfo = phone + email;
+                    String uniqueContactInfo = name + phone + email;
                     if (!uniqueContactInfos.contains(uniqueContactInfo)) {
                         uniqueContactInfos.add(uniqueContactInfo);
 
                         boolean isComplete =
-                                mContactEditor.isContactInformationComplete(phone, email);
-                        contacts.add(new AutofillContact(profile, phone, email, isComplete));
+                                mContactEditor.isContactInformationComplete(name, phone, email);
+                        contacts.add(new AutofillContact(profile, name, phone, email, isComplete));
                     }
                 }
             }
@@ -373,8 +378,8 @@
         }
 
         mUI = new PaymentRequestUI(mContext, this, requestShipping,
-                requestPayerPhone || requestPayerEmail, mMerchantSupportsAutofillPaymentInstruments,
-                mMerchantName, mOrigin);
+                requestPayerName || requestPayerPhone || requestPayerEmail,
+                mMerchantSupportsAutofillPaymentInstruments, mMerchantName, mOrigin);
 
         if (mFavicon != null) mUI.setTitleBitmap(mFavicon);
         mFavicon = null;
@@ -1070,6 +1075,7 @@
             if (selectedContact != null) {
                 // Contacts are created in show(). These should all be instances of AutofillContact.
                 assert selectedContact instanceof AutofillContact;
+                response.payerName = ((AutofillContact) selectedContact).getPayerName();
                 response.payerPhone = ((AutofillContact) selectedContact).getPayerPhone();
                 response.payerEmail = ((AutofillContact) selectedContact).getPayerEmail();
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index ba2101c..1b80f380 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -312,8 +312,8 @@
      * @param activity        The activity on top of which the UI should be displayed.
      * @param client          The consumer of the PaymentRequest UI.
      * @param requestShipping Whether the UI should show the shipping address and option selection.
-     * @param requestContact  Whether the UI should show the email address and phone number
-     *                        selection.
+     * @param requestContact  Whether the UI should show the payer name, email address and
+     *                        phone number selection.
      * @param canAddCards     Whether the UI should show the [+ADD CARD] button. This can be false,
      *                        for example, when the merchant does not accept credit cards, so
      *                        there's no point in adding cards within PaymentRequest UI.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappAuthenticator.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappAuthenticator.java
index 571616bd..521cee1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappAuthenticator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappAuthenticator.java
@@ -12,7 +12,7 @@
 import android.util.Log;
 
 import org.chromium.base.SecureRandomInitializer;
-import org.chromium.base.metrics.CachedMetrics.TimesHistogramSample;
+import org.chromium.chrome.browser.metrics.LaunchMetrics.TimesHistogramSample;
 
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 6e0435e..b92b8db 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2516,6 +2516,9 @@
       </message>
 
       <!-- Payments -->
+      <message name="IDS_PAYMENTS_NAME_FIELD_IN_CONTACT_DETAILS" desc="The label for text input field containing the full name of a person. [CHAR-LIMIT=32]">
+        Name
+      </message>
       <message name="IDS_PAYMENTS_SAVE_CARD_TO_DEVICE_CHECKBOX" desc="The label for the checkbox that enables the user to save a credit card to their device, for example, on their phone.">
         Save this card to this device
       </message>
@@ -2528,10 +2531,10 @@
       <message name="IDS_PAYMENTS_CONTACT_DETAILS_LABEL" desc="The title for the section that lets the user select how they can be contacted.">
         Contact info
       </message>
-      <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as email address or phone number.">
+      <message name="IDS_PAYMENTS_ADD_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to add new contact information, such as the user's full name, an email address or a phone number.">
         Add contact info
       </message>
-      <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as email address or phone number.">
+      <message name="IDS_PAYMENTS_EDIT_CONTACT_DETAILS_LABEL" desc="The title of the dialog for user to edit their contact information, such as the user's full name, an email address or a phone number.">
         Edit contact info
       </message>
       <message name="IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL" desc="The title for the section of shipping information.">
@@ -2573,7 +2576,7 @@
       <message name="IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE" desc="The text that informs the user that the credit card number they have entered is not valid.">
         Invalid card number
       </message>
-      <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like phone number or email address.">
+      <message name="IDS_PAYMENTS_ADD_CONTACT" desc="Text on a button that lets a user add new contact details, like the user's full name, an email address or a phone number.">
         Add contact info
       </message>
       <message name="IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS" desc="Text implying that a user needs to pick a shipping address to see the shipping methods.">
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
index d97836dc..357e328 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
@@ -133,8 +133,8 @@
         assertFalse(button.isEnabled());
         assertEquals(View.GONE, items.getVisibility());
 
-        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key", "key"));
-        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "key2"));
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
 
         // Two items showing, the empty view should be no more and the button
         // should now be enabled.
@@ -153,7 +153,7 @@
         assertFalse(button.isEnabled());
 
         // Select the first item and verify it got selected.
-        selectItem(dialog, 1, "key", true);
+        selectItem(dialog, 1, "key1", true);
 
         mChooserDialog.dismiss();
     }
@@ -191,11 +191,11 @@
         Dialog dialog = mChooserDialog.getDialogForTesting();
         assertTrue(dialog.isShowing());
 
-        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key", "key"));
-        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "key2"));
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
 
         // Disable one item and try to select it.
-        mChooserDialog.setEnabled("key", false);
+        mChooserDialog.setEnabled("key1", false);
         selectItem(dialog, 1, "None", false);
         // The other is still selectable.
         selectItem(dialog, 2, "key2", true);
@@ -211,8 +211,8 @@
 
         final Button button = (Button) dialog.findViewById(R.id.positive);
 
-        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key1", "desc1"));
-        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "desc2"));
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
 
         selectItem(dialog, 1, "key1", true);
         assertTrue(button.isEnabled());
@@ -233,17 +233,13 @@
 
         final Button button = (Button) dialog.findViewById(R.id.positive);
 
-        ItemChooserDialog.ItemChooserRow item1 =
-                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
-        ItemChooserDialog.ItemChooserRow item2 =
-                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
-        mChooserDialog.addOrUpdateItem(item1);
-        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
 
         selectItem(dialog, 1, "key1", true);
         assertTrue(button.isEnabled());
 
-        mChooserDialog.removeItemFromList(item1);
+        mChooserDialog.removeItemFromList("key1");
         assertFalse(button.isEnabled());
 
         mChooserDialog.dismiss();
@@ -257,27 +253,20 @@
         final Button button = (Button) dialog.findViewById(R.id.positive);
         ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
 
-        ItemChooserDialog.ItemChooserRow item1 =
-                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
-        ItemChooserDialog.ItemChooserRow item2 =
-                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
-        ItemChooserDialog.ItemChooserRow item3 =
-                new ItemChooserDialog.ItemChooserRow("key3", "desc3");
-
-        mChooserDialog.addOrUpdateItem(item1);
-        mChooserDialog.addOrUpdateItem(item2);
-        mChooserDialog.addOrUpdateItem(item3);
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
+        mChooserDialog.addOrUpdateItem("key3", "desc3");
 
         selectItem(dialog, 2, "key2", true);
         assertTrue(button.isEnabled());
 
         // Remove the item before the currently selected item.
-        mChooserDialog.removeItemFromList(item1);
+        mChooserDialog.removeItemFromList("key1");
         assertTrue(button.isEnabled());
         assertEquals("key2", itemAdapter.getSelectedItemKey());
 
         // Remove the item after the currently selected item.
-        mChooserDialog.removeItemFromList(item3);
+        mChooserDialog.removeItemFromList("key3");
         assertTrue(button.isEnabled());
         assertEquals("key2", itemAdapter.getSelectedItemKey());
 
@@ -292,22 +281,15 @@
         final Button button = (Button) dialog.findViewById(R.id.positive);
         ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
 
-        ItemChooserDialog.ItemChooserRow item1 =
-                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
-        ItemChooserDialog.ItemChooserRow item2 =
-                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
-        ItemChooserDialog.ItemChooserRow item3 =
-                new ItemChooserDialog.ItemChooserRow("key3", "desc3");
-
-        mChooserDialog.addOrUpdateItem(item1);
-        mChooserDialog.addOrUpdateItem(item2);
-        mChooserDialog.addOrUpdateItem(item3);
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
+        mChooserDialog.addOrUpdateItem("key3", "desc3");
 
         selectItem(dialog, 2, "key2", true);
         assertTrue(button.isEnabled());
 
         // Remove the selected item.
-        mChooserDialog.removeItemFromList(item2);
+        mChooserDialog.removeItemFromList("key2");
         assertFalse(button.isEnabled());
         assertEquals("", itemAdapter.getSelectedItemKey());
 
@@ -316,7 +298,7 @@
 
     @LargeTest
     @UiThreadTest
-    public void testAddOrUpdateItemAndRemoveItemFromList() throws InterruptedException {
+    public void testUpdateItemAndRemoveItemFromList() throws InterruptedException {
         Dialog dialog = mChooserDialog.getDialogForTesting();
         assertTrue(dialog.isShowing());
 
@@ -326,48 +308,84 @@
         final Button button = (Button) dialog.findViewById(R.id.positive);
 
         ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
-        ItemChooserDialog.ItemChooserRow nonExistentItem =
-                new ItemChooserDialog.ItemChooserRow("key", "key");
+        final String nonExistentKey = "key";
 
         // Initially the itemAdapter is empty.
         assertTrue(itemAdapter.isEmpty());
 
         // Try removing an item from an empty itemAdapter.
-        mChooserDialog.removeItemFromList(nonExistentItem);
+        mChooserDialog.removeItemFromList(nonExistentKey);
         assertTrue(itemAdapter.isEmpty());
 
         // Add item 1.
-        ItemChooserDialog.ItemChooserRow item1 =
-                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
-        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
         assertEquals(1, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1);
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc1"));
 
-        // Add item 1 with different description.
-        ItemChooserDialog.ItemChooserRow item1_again =
-                new ItemChooserDialog.ItemChooserRow("key1", "desc1_again");
-        mChooserDialog.addOrUpdateItem(item1_again);
+        // Update item 1 with different description.
+        mChooserDialog.addOrUpdateItem("key1", "desc2");
         assertEquals(1, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1_again);
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc2"));
+
+        mChooserDialog.setIdleState();
+
+        // Remove item 1.
+        mChooserDialog.removeItemFromList("key1");
+        assertTrue(itemAdapter.isEmpty());
+
+        // Listview should now be showing empty, with an empty view visible
+        // and the button should not be enabled.
+        // The chooser should show a status message at the bottom.
+        assertEquals(View.GONE, items.getVisibility());
+        assertEquals(View.VISIBLE, items.getEmptyView().getVisibility());
+        assertEquals("statusIdleNoneFound", statusView.getText().toString());
+        assertFalse(button.isEnabled());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    @UiThreadTest
+    public void testAddItemAndRemoveItemFromList() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        TextViewWithClickableSpans statusView =
+                (TextViewWithClickableSpans) dialog.findViewById(R.id.status);
+        final ListView items = (ListView) dialog.findViewById(R.id.items);
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
+        final String nonExistentKey = "key";
+
+        // Initially the itemAdapter is empty.
+        assertTrue(itemAdapter.isEmpty());
+
+        // Try removing an item from an empty itemAdapter.
+        mChooserDialog.removeItemFromList(nonExistentKey);
+        assertTrue(itemAdapter.isEmpty());
+
+        // Add item 1.
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
+        assertEquals(1, itemAdapter.getCount());
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc1"));
 
         // Add item 2.
-        ItemChooserDialog.ItemChooserRow item2 =
-                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
-        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
         assertEquals(2, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1_again);
-        assertEquals(itemAdapter.getItem(1), item2);
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc1"));
+        assertTrue(itemAdapter.getItem(1).hasSameContents("key2", "desc2"));
 
         mChooserDialog.setIdleState();
 
         // Try removing an item that doesn't exist.
-        mChooserDialog.removeItemFromList(nonExistentItem);
+        mChooserDialog.removeItemFromList(nonExistentKey);
         assertEquals(2, itemAdapter.getCount());
 
         // Remove item 2.
-        mChooserDialog.removeItemFromList(item2);
+        mChooserDialog.removeItemFromList("key2");
         assertEquals(1, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1_again);
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc1"));
 
         // The list should be visible with one item, it should not show
         // the empty view and the button should not be enabled.
@@ -378,7 +396,7 @@
         assertFalse(button.isEnabled());
 
         // Remove item 1.
-        mChooserDialog.removeItemFromList(item1_again);
+        mChooserDialog.removeItemFromList("key1");
         assertTrue(itemAdapter.isEmpty());
 
         // Listview should now be showing empty, with an empty view visible
@@ -401,52 +419,41 @@
         ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
 
         // Add item 1.
-        ItemChooserDialog.ItemChooserRow item1 =
-                new ItemChooserDialog.ItemChooserRow("device_id_1", "same_device_name");
-        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem("key1", "desc1");
         assertEquals(1, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1);
-
         // Add item 2.
-        ItemChooserDialog.ItemChooserRow item2 =
-                new ItemChooserDialog.ItemChooserRow("device_id_2", "different_device_name");
-        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem("key2", "desc2");
         assertEquals(2, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1);
-        assertEquals(itemAdapter.getItem(1), item2);
-
-        // Add item 3.
-        ItemChooserDialog.ItemChooserRow item3 =
-                new ItemChooserDialog.ItemChooserRow("device_id_3", "same_device_name");
-        mChooserDialog.addOrUpdateItem(item3);
+        // Add item 3 with same description as item 1.
+        mChooserDialog.addOrUpdateItem("key3", "desc1");
         assertEquals(3, itemAdapter.getCount());
-        assertEquals(itemAdapter.getItem(0), item1);
-        assertEquals(itemAdapter.getItem(1), item2);
-        assertEquals(itemAdapter.getItem(2), item3);
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc1"));
+        assertTrue(itemAdapter.getItem(1).hasSameContents("key2", "desc2"));
+        assertTrue(itemAdapter.getItem(2).hasSameContents("key3", "desc1"));
 
         // Since two items have the same name, their display text should have their unique
         // keys appended.
-        assertEquals("same_device_name (device_id_1)", itemAdapter.getDisplayText(0));
-        assertEquals("different_device_name", itemAdapter.getDisplayText(1));
-        assertEquals("same_device_name (device_id_3)", itemAdapter.getDisplayText(2));
+        assertEquals("desc1 (key1)", itemAdapter.getDisplayText(0));
+        assertEquals("desc2", itemAdapter.getDisplayText(1));
+        assertEquals("desc1 (key3)", itemAdapter.getDisplayText(2));
 
         // Remove item 2.
-        mChooserDialog.removeItemFromList(item2);
+        mChooserDialog.removeItemFromList("key2");
         assertEquals(2, itemAdapter.getCount());
         // Make sure the remaining items are item 1 and item 3.
-        assertEquals(itemAdapter.getItem(0), item1);
-        assertEquals(itemAdapter.getItem(1), item3);
-        assertEquals("same_device_name (device_id_1)", itemAdapter.getDisplayText(0));
-        assertEquals("same_device_name (device_id_3)", itemAdapter.getDisplayText(1));
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key1", "desc1"));
+        assertTrue(itemAdapter.getItem(1).hasSameContents("key3", "desc1"));
+        assertEquals("desc1 (key1)", itemAdapter.getDisplayText(0));
+        assertEquals("desc1 (key3)", itemAdapter.getDisplayText(1));
 
         // Remove item 1.
-        mChooserDialog.removeItemFromList(item1);
+        mChooserDialog.removeItemFromList("key1");
         assertEquals(1, itemAdapter.getCount());
         // Make sure the remaining item is item 3.
-        assertEquals(itemAdapter.getItem(0), item3);
+        assertTrue(itemAdapter.getItem(0).hasSameContents("key3", "desc1"));
         // After removing item 1, item 3 is the only remaining item, so its display text
         // also changed to its original description.
-        assertEquals("same_device_name", itemAdapter.getDisplayText(0));
+        assertEquals("desc1", itemAdapter.getDisplayText(0));
 
         mChooserDialog.dismiss();
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
index 78cd4172..6e05b1f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsAndFreeShippingTest.java
@@ -18,8 +18,8 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * A payment integration test for a merchant that requests an email address and a phone number and
- * provides free shipping regardless of address.
+ * A payment integration test for a merchant that requests a payer name, an email address and
+ * a phone number and provides free shipping regardless of address.
  */
 public class PaymentRequestContactDetailsAndFreeShippingTest extends PaymentRequestTestBase {
     public PaymentRequestContactDetailsAndFreeShippingTest() {
@@ -43,8 +43,8 @@
     }
 
     /**
-     * Submit the email address, phone number and shipping address to the merchant when the user
-     * clicks "Pay."
+     * Submit the payer name, email address, phone number and shipping address to the merchant when
+     * the user clicks "Pay."
      */
     @MediumTest
     @Feature({"Payments"})
@@ -53,9 +53,9 @@
         clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
         setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
         clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
-        expectResultContains(new String[] {"jon.doe@google.com", "555-555-5555", "Jon Doe",
-                "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St", "CA",
-                "Los Angeles", "90291", "US", "en", "freeShippingOption"});
+        expectResultContains(new String[] {"Jon Doe", "jon.doe@google.com", "555-555-5555",
+                "Jon Doe", "4111111111111111", "12", "2050", "visa", "123", "Google", "340 Main St",
+                "CA", "Los Angeles", "90291", "US", "en", "freeShippingOption"});
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
index 4cbd129..1c36989c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestContactDetailsTest.java
@@ -23,7 +23,7 @@
  */
 public class PaymentRequestContactDetailsTest extends PaymentRequestTestBase {
     public PaymentRequestContactDetailsTest() {
-        // The merchant requests both a phone number and an email address.
+        // The merchant requests a payer name, a phone number and an email address.
         super("payment_request_contact_details_test.html");
     }
 
@@ -31,7 +31,7 @@
     public void onMainActivityStarted()
             throws InterruptedException, ExecutionException, TimeoutException {
         AutofillTestHelper helper = new AutofillTestHelper();
-        // The user has valid phone number and email address on disk.
+        // The user has valid payer name, phone number and email address on disk.
         String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
                 true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
                 "US", "555-555-5555", "jon.doe@google.com", "en-US"));
@@ -40,7 +40,7 @@
                 billingAddressId, "" /* serverId */));
     }
 
-    /** Provide the existing valid phone number and email address to the merchant. */
+    /** Provide the existing valid payer name, phone number and email address to the merchant. */
     @MediumTest
     @Feature({"Payments"})
     public void testPay() throws InterruptedException, ExecutionException, TimeoutException {
@@ -48,10 +48,10 @@
         clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
         setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
         clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
-        expectResultContains(new String[] {"555-555-5555", "jon.doe@google.com"});
+        expectResultContains(new String[] {"Jon Doe", "555-555-5555", "jon.doe@google.com"});
     }
 
-    /** Attempt to add invalid phone number and email address and cancel the transaction. */
+    /** Attempt to add invalid contact information and cancel the transaction. */
     @MediumTest
     @Feature({"Payments"})
     public void testAddInvalidContactAndCancel()
@@ -59,14 +59,14 @@
         triggerUIAndWait(mReadyToPay);
         clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
         clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit);
-        setTextInEditorAndWait(new String[] {"+++", "jane.jones"}, mEditorTextUpdate);
+        setTextInEditorAndWait(new String[] {"", "+++", "jane.jones"}, mEditorTextUpdate);
         clickInEditorAndWait(R.id.payments_edit_done_button, mEditorValidationError);
         clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
         clickAndWait(R.id.close_button, mDismissed);
         expectResultContains(new String[] {"Request cancelled"});
     }
 
-    /** Add new phone number and email address and provide that to the merchant. */
+    /** Add new payer name, phone number and email address and provide that to the merchant. */
     @MediumTest
     @Feature({"Payments"})
     public void testAddContactAndPay()
@@ -74,13 +74,13 @@
         triggerUIAndWait(mReadyToPay);
         clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
         clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit);
-        setTextInEditorAndWait(new String[] {"999-999-9999", "jane.jones@google.com"},
+        setTextInEditorAndWait(new String[] {"Jane Jones", "999-999-9999", "jane.jones@google.com"},
                 mEditorTextUpdate);
         clickInEditorAndWait(R.id.payments_edit_done_button, mReadyToPay);
         clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
         setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
         clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
-        expectResultContains(new String[] {"999-999-9999", "jane.jones@google.com"});
+        expectResultContains(new String[] {"Jane Jones", "999-999-9999", "jane.jones@google.com"});
     }
 
     /** Quickly pressing on "add contact info" and then [X] should not crash. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
index 5ac9f6e..850d402 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompleteContactDetailsTest.java
@@ -47,7 +47,7 @@
         triggerUIAndWait(mReadyForInput);
         clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
         clickInContactInfoAndWait(R.id.payments_first_radio_button, mReadyToEdit);
-        setTextInEditorAndWait(new String[] {"---", "jane.jones"}, mEditorTextUpdate);
+        setTextInEditorAndWait(new String[] {"", "---", "jane.jones"}, mEditorTextUpdate);
         clickInEditorAndWait(R.id.payments_edit_done_button, mEditorValidationError);
         clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
         clickAndWait(R.id.close_button, mDismissed);
@@ -62,12 +62,12 @@
         triggerUIAndWait(mReadyForInput);
         clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
         clickInContactInfoAndWait(R.id.payments_first_radio_button, mReadyToEdit);
-        setTextInEditorAndWait(new String[] {"555-555-5555", "jon.doe@google.com"},
+        setTextInEditorAndWait(new String[] {"Jon Doe", "555-555-5555", "jon.doe@google.com"},
                 mEditorTextUpdate);
         clickInEditorAndWait(R.id.payments_edit_done_button, mReadyToPay);
         clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
         setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
         clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
-        expectResultContains(new String[] {"555-555-5555", "jon.doe@google.com"});
+        expectResultContains(new String[] {"Jon Doe", "555-555-5555", "jon.doe@google.com"});
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
index 7f162500..f98ea70 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMultipleContactDetailsTest.java
@@ -85,9 +85,11 @@
         triggerUIAndWait(mReadyToPay);
         clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
         assertEquals(4, getNumberOfContactDetailSuggestions());
-        assertEquals("555 123-4567\nlisa@simpson.com", getContactDetailsSuggestionLabel(0));
-        assertEquals("555 123-4567\nmaggie@simpson.com", getContactDetailsSuggestionLabel(1));
-        assertEquals("bart@simpson.com", getContactDetailsSuggestionLabel(2));
-        assertEquals("homer@simpson.com", getContactDetailsSuggestionLabel(3));
+        assertEquals("Lisa Simpson\n555 123-4567\nlisa@simpson.com",
+                getContactDetailsSuggestionLabel(0));
+        assertEquals("Maggie Simpson\n555 123-4567\nmaggie@simpson.com",
+                getContactDetailsSuggestionLabel(1));
+        assertEquals("Bart Simpson\nbart@simpson.com", getContactDetailsSuggestionLabel(2));
+        assertEquals("Homer Simpson\nhomer@simpson.com", getContactDetailsSuggestionLabel(3));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
new file mode 100644
index 0000000..9149fbd
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameAndFreeShippingTest.java
@@ -0,0 +1,76 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.content.DialogInterface;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A payment integration test for a merchant that requests a payer name and provides free shipping
+ * regardless of address.
+ */
+public class PaymentRequestNameAndFreeShippingTest extends PaymentRequestTestBase {
+    public PaymentRequestNameAndFreeShippingTest() {
+        // This merchant requests a payer name and provides free shipping worldwide.
+        super("payment_request_name_and_free_shipping_test.html");
+    }
+
+    @Override
+    public void onMainActivityStarted()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        AutofillTestHelper helper = new AutofillTestHelper();
+        // The user has a shipping address with a valid payer name on disk.
+        String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
+                true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
+                "US", "555-555-5555", "", "en-US"));
+        helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
+                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa,
+                billingAddressId, "" /* serverId */));
+    }
+
+    /** Submit the payer name and shipping address to the merchant when the user clicks "Pay." */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testPay() throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
+        setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
+        clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
+        expectResultContains(new String[] {"Jon Doe", "Jon Doe", "4111111111111111", "12",
+                "2050", "visa", "123", "Google", "340 Main St", "CA", "Los Angeles", "90291", "US",
+                "en", "freeShippingOption"});
+    }
+
+    /**
+     * Test that starting a payment request that requires a payer name and a shipping address
+     * results in the appropriate metric being logged in the PaymentRequest.RequestedInformation
+     * histogram.
+     */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testRequestedInformationMetric() throws InterruptedException, ExecutionException,
+            TimeoutException {
+        // Start the Payment Request.
+        triggerUIAndWait(mReadyToPay);
+
+        // Make sure that only the appropriate enum value was logged.
+        for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) {
+            assertEquals((i == (PaymentRequestMetrics.REQUESTED_INFORMATION_PHONE
+                    | PaymentRequestMetrics.REQUESTED_INFORMATION_SHIPPING) ? 1 : 0),
+                    RecordHistogram.getHistogramValueCountForTesting(
+                            "PaymentRequest.RequestedInformation", i));
+        }
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
new file mode 100644
index 0000000..344c1ea
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNameTest.java
@@ -0,0 +1,102 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.content.DialogInterface;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.AutofillTestHelper;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A payment integration test for a merchant that requests payer name.
+ */
+public class PaymentRequestNameTest extends PaymentRequestTestBase {
+    public PaymentRequestNameTest() {
+        // This merchant request a payer name.
+        super("payment_request_name_test.html");
+    }
+
+    @Override
+    public void onMainActivityStarted()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        AutofillTestHelper helper = new AutofillTestHelper();
+        // The user has a valid payer name on disk.
+        String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
+                true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
+                "US", "555-555-5555", "jon.doe@google.com", "en-US"));
+        helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
+                "4111111111111111", "1111", "12", "2050", "visa", R.drawable.pr_visa,
+                billingAddressId, "" /* serverId */));
+    }
+
+    /** Provide the existing valid payer name to the merchant. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testPay() throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
+        setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
+        clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
+        expectResultContains(new String[] {"Jon Doe"});
+    }
+
+    /** Attempt to add an invalid payer name and cancel the transaction. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testAddInvalidNameAndCancel()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
+        clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit);
+        setTextInEditorAndWait(new String[] {""}, mEditorTextUpdate);
+        clickInEditorAndWait(R.id.payments_edit_done_button, mEditorValidationError);
+        clickInEditorAndWait(R.id.payments_edit_cancel_button, mReadyForInput);
+        clickAndWait(R.id.close_button, mDismissed);
+        expectResultContains(new String[] {"Request cancelled"});
+    }
+
+    /** Add a new payer name and provide that to the merchant. */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testAddNameAndPay()
+            throws InterruptedException, ExecutionException, TimeoutException {
+        triggerUIAndWait(mReadyToPay);
+        clickInContactInfoAndWait(R.id.payments_section, mReadyForInput);
+        clickInContactInfoAndWait(R.id.payments_add_option_button, mReadyToEdit);
+        setTextInEditorAndWait(new String[] {"Jane Jones"}, mEditorTextUpdate);
+        clickInEditorAndWait(R.id.payments_edit_done_button, mReadyToPay);
+        clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
+        setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
+        clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
+        expectResultContains(new String[] {"Jane Jones"});
+    }
+
+    /**
+     * Test that starting a payment request that requires only the user's payer name results in
+     * the appropriate metric being logged in the PaymentRequest.RequestedInformation histogram.
+     */
+    @MediumTest
+    @Feature({"Payments"})
+    public void testRequestedInformationMetric() throws InterruptedException, ExecutionException,
+            TimeoutException {
+        // Start the Payment Request.
+        triggerUIAndWait(mReadyToPay);
+
+        // Make sure that only the appropriate enum value was logged.
+        for (int i = 0; i < PaymentRequestMetrics.REQUESTED_INFORMATION_MAX; ++i) {
+            assertEquals((i == PaymentRequestMetrics.REQUESTED_INFORMATION_EMAIL ? 1 : 0),
+                    RecordHistogram.getHistogramValueCountForTesting(
+                            "PaymentRequest.RequestedInformation", i));
+        }
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java
index 60596a8..48c1d10e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/payments/AutofillContactTest.java
@@ -4,14 +4,14 @@
 
 package org.chromium.chrome.browser.payments;
 
-import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
-
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+
 import java.util.Arrays;
 import java.util.Collection;
 
@@ -23,58 +23,98 @@
     @Parameters
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][] {
-            {"555-5555", "j@d.co", true, "555-5555", "j@d.co", "j@d.co", "555-5555"},
-            {null, "j@d.co", true, "j@d.co", null, "j@d.co", null},
-            {"", "j@d.co", true, "j@d.co", null, "j@d.co", null},
-            {"555-5555", null, true, "555-5555", null, null, "555-5555"},
-            {"555-5555", "", false, "555-5555", null, null, "555-5555"},
+            {"Jon Doe", "555-5555", "j@d.co", true,
+             "Jon Doe", "555-5555", "j@d.co",
+             "Jon Doe", "555-5555", "j@d.co"},
+            {null, "555-5555", "j@d.co", true,
+             "555-5555", "j@d.co", null,
+             null, "555-5555", "j@d.co"},
+            {"", "555-5555", "j@d.co", true,
+             "555-5555", "j@d.co", null,
+             null, "555-5555", "j@d.co"},
+            {"Jon Doe", null, "j@d.co", true,
+             "Jon Doe", "j@d.co", null,
+             "Jon Doe", null, "j@d.co"},
+            {"Jon Doe", "", "j@d.co", true,
+             "Jon Doe", "j@d.co", null,
+             "Jon Doe", null, "j@d.co"},
+            {"Jon Doe", "555-5555", null, true,
+             "Jon Doe", "555-5555", null,
+             "Jon Doe", "555-5555", null},
+            {"Jon Doe", "555-5555", "", true,
+             "Jon Doe", "555-5555", null,
+             "Jon Doe", "555-5555", null},
+            {null, "555-5555", null, true,
+             "555-5555", null, null,
+             null, "555-5555", null},
+            {"", "555-5555", "", true,
+             "555-5555", null, null,
+             null, "555-5555", null},
+            {null, null, "j@d.co", true,
+             "j@d.co", null, null,
+             null, null, "j@d.co"},
+            {"", "", "j@d.co", true,
+             "j@d.co", null, null,
+             null, null, "j@d.co"},
+            {"", "555-5555", "", false,
+             "555-5555", null, null,
+             null, "555-5555", null}
         });
     }
 
+    private final String mPayerName;
     private final String mPayerPhone;
     private final String mPayerEmail;
     private final boolean mIsComplete;
     private final String mExpectedLabel;
     private final String mExpectedSublabel;
+    private final String mExpectedTertiaryLabel;
+    private final String mExpectedPayerName;
     private final String mExpectedPayerEmail;
     private final String mExpectedPayerPhone;
 
-    public AutofillContactTest(String payerPhone, String payerEmail, boolean isComplete,
-            String expectedLabel, String expectedSublabel, String expectedPayerEmail,
-            String expectedPayerPhone) {
+    public AutofillContactTest(String payerName, String payerPhone, String payerEmail,
+            boolean isComplete, String expectedLabel, String expectedSublabel,
+            String expectedTertiaryLabel, String expectedPayerName, String expectedPayerPhone,
+            String expectedPayerEmail) {
+        mPayerName = payerName;
         mPayerPhone = payerPhone;
         mPayerEmail = payerEmail;
         mIsComplete = isComplete;
         mExpectedLabel = expectedLabel;
         mExpectedSublabel = expectedSublabel;
-        mExpectedPayerEmail = expectedPayerEmail;
+        mExpectedTertiaryLabel = expectedTertiaryLabel;
+        mExpectedPayerName = expectedPayerName;
         mExpectedPayerPhone = expectedPayerPhone;
+        mExpectedPayerEmail = expectedPayerEmail;
     }
 
     @Test
     public void test() {
         AutofillProfile profile = new AutofillProfile();
         AutofillContact contact =
-                new AutofillContact(profile, mPayerPhone, mPayerEmail, mIsComplete);
+                new AutofillContact(profile, mPayerName, mPayerPhone, mPayerEmail, mIsComplete);
 
         Assert.assertEquals(
                 mIsComplete ? "Contact should be complete" : "Contact should be incomplete",
                 mIsComplete, contact.isComplete());
         Assert.assertEquals("Contact's profile should be the same as passed into the constructor",
                 profile, contact.getProfile());
-        assertIdPhoneEmailLabelSublabel(profile.getGUID(), mExpectedPayerPhone, mExpectedPayerEmail,
-                mExpectedLabel, mExpectedSublabel, contact);
+        assertContact(profile.getGUID(), mExpectedPayerName, mExpectedPayerPhone,
+                mExpectedPayerEmail, mExpectedLabel, mExpectedSublabel, mExpectedTertiaryLabel,
+                contact);
 
-        contact.completeContact("some-guid-here", "999-9999", "a@b.com");
+        contact.completeContact("some-guid-here", "Jon Doe", "999-9999", "a@b.com");
         Assert.assertTrue("Contact should be complete", contact.isComplete());
-        assertIdPhoneEmailLabelSublabel("some-guid-here", "999-9999", "a@b.com", "999-9999",
-                "a@b.com", contact);
+        assertContact("some-guid-here", "Jon Doe", "999-9999", "a@b.com",
+                "Jon Doe", "999-9999", "a@b.com", contact);
     }
 
-    private void assertIdPhoneEmailLabelSublabel(String id, String expectedPhone,
+    private void assertContact(String id, String expectedName, String expectedPhone,
             String expectedEmail, String expectedLabel, String expectedSublabel,
-            AutofillContact actual) {
+            String expectedTertiaryLabel, AutofillContact actual) {
         Assert.assertEquals("Identifier should be " + id, id, actual.getIdentifier());
+        Assert.assertEquals("Name should be " + expectedName, expectedName, actual.getPayerName());
         Assert.assertEquals(
                 "Phone should be " + expectedPhone, expectedPhone, actual.getPayerPhone());
         Assert.assertEquals(
@@ -82,5 +122,7 @@
         Assert.assertEquals("Label should be " + expectedLabel, expectedLabel, actual.getLabel());
         Assert.assertEquals(
                 "Sublabel should be " + expectedSublabel, expectedSublabel, actual.getSublabel());
+        Assert.assertEquals("TertiaryLabel should be " + expectedTertiaryLabel,
+                expectedTertiaryLabel, actual.getTertiaryLabel());
     }
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index f87e7d50..06e2d43 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6120,12 +6120,6 @@
     System time
   </message>
 
-  <message name="IDS_FLAGS_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME" desc="Title for the flag for automatic timezone update on user location change.">
-    Automatic timezone update by geolocation
-  </message>
-  <message name="IDS_FLAGS_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION" desc="Description for the flag for user setting to automatically update timezone by user geolocation.">
-    Enables the user setting to automatically select timezone by the current geolocation.
-  </message>
   <message name="IDS_OPTIONS_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION" desc="Label for checkbox to allow automatic timezone update by user geolocation.">
     Set time zone automatically using your location
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0c9203ce2..daddafb 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8658,13 +8658,7 @@
           Out of bounds page reference, limit is <ph name="MAXIMUM_PAGE">$1<ex>1</ex></ph>
         </message>
         <message name="IDS_PRINT_PREVIEW_COPIES_INSTRUCTION" desc="Instruction shown when the user enters an invalid number of copies.">
-          Use a number to indicate how many copies to print (1 or more).
-        </message>
-        <message name="IDS_PRINT_PREVIEW_INCREMENT_TITLE" desc="Title shown when the user hovers mouse over the increment button. Also added for improved accessibility">
-          More copies
-        </message>
-        <message name="IDS_PRINT_PREVIEW_DECREMENT_TITLE" desc="Title shown when the user hovers mouse over the decrement button. Also added for improved accessibility">
-          Less copies
+          Use a number to indicate how many copies to print (1 to 999).
         </message>
         <message name="IDS_PRINT_PREVIEW_PRINT_PAGES_LABEL" desc="ARIA label used by screen reader to explain the purpose of the page selection textbox">
           Print Specific Pages
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 1a79738..9a51a0f 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4298,7 +4298,7 @@
 
   deps = [
     "//components/metrics:test_support",
-    "//components/password_manager/content/public/interfaces",
+    "//components/password_manager/content/common:mojo_interfaces",
     "//components/password_manager/core/browser:test_support",
     "//components/translate/content/common",
     "//skia",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index bfa6859..3084799 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1496,13 +1496,6 @@
      IDS_FLAGS_HARFBUZZ_RENDERTEXT_DESCRIPTION, kOsMac,
      SINGLE_VALUE_TYPE(switches::kEnableHarfBuzzRenderText)},
 #endif  // OS_MACOSX
-#if defined(OS_CHROMEOS)
-    {"disable-timezone-tracking",
-     IDS_FLAGS_RESOLVE_TIMEZONE_BY_GEOLOCATION_NAME,
-     IDS_FLAGS_RESOLVE_TIMEZONE_BY_GEOLOCATION_DESCRIPTION, kOsCrOS,
-     SINGLE_DISABLE_VALUE_TYPE(
-         chromeos::switches::kDisableTimeZoneTrackingOption)},
-#endif  // OS_CHROMEOS
     {"data-reduction-proxy-lo-fi", IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_NAME,
      IDS_FLAGS_DATA_REDUCTION_PROXY_LO_FI_DESCRIPTION, kOsAll,
      MULTI_VALUE_TYPE(kDataReductionProxyLoFiChoices)},
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 4dcf58a..3e73fc3 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -243,6 +243,8 @@
     "arc/fileapi/arc_content_file_system_backend_delegate.h",
     "arc/fileapi/arc_content_file_system_file_stream_reader.cc",
     "arc/fileapi/arc_content_file_system_file_stream_reader.h",
+    "arc/fileapi/arc_content_file_system_url_util.cc",
+    "arc/fileapi/arc_content_file_system_url_util.h",
     "arc/gpu_arc_video_service_host.cc",
     "arc/gpu_arc_video_service_host.h",
     "attestation/attestation_ca_client.cc",
@@ -1359,6 +1361,7 @@
     "arc/arc_downloads_watcher_service_unittest.cc",
     "arc/arc_navigation_throttle_unittest.cc",
     "arc/arc_policy_bridge_unittest.cc",
+    "arc/fileapi/arc_content_file_system_url_util_unittest.cc",
     "attestation/attestation_ca_client_unittest.cc",
     "attestation/attestation_policy_observer_unittest.cc",
     "attestation/fake_certificate.cc",
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc
index 1457d49..00f01215 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -651,7 +651,7 @@
   auth_account_callback_.Reset();
   android_management_checker_.reset();
   auth_code_fetcher_.reset();
-  arc_bridge_service()->Shutdown();
+  arc_bridge_service()->RequestStop();
   if (state_ != State::NOT_INITIALIZED)
     SetState(State::STOPPED);
   for (auto& observer : observer_list_)
@@ -706,7 +706,7 @@
 
 void ArcAuthService::StartArc() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  arc_bridge_service()->HandleStartup();
+  arc_bridge_service()->RequestStart();
   SetState(State::ACTIVE);
 }
 
diff --git a/chrome/browser/chromeos/arc/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/arc_auth_service_browsertest.cc
index b8a19fc..9ac9f84 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_service_browsertest.cc
@@ -139,7 +139,8 @@
             fake_session_manager_client));
 
     // Mock out ARC bridge.
-    auto service = base::MakeUnique<ArcBridgeServiceImpl>();
+    // Here inject FakeArcSession so blocking task runner is not needed.
+    auto service = base::MakeUnique<ArcBridgeServiceImpl>(nullptr);
     service->SetArcSessionFactoryForTesting(base::Bind(FakeArcSession::Create));
     ArcServiceManager::SetArcBridgeServiceForTesting(std::move(service));
   }
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index d8ed220..ecff7163 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/chromeos/arc/arc_tts_service.h"
 #include "chrome/browser/chromeos/arc/arc_wallpaper_service.h"
 #include "chrome/browser/chromeos/arc/gpu_arc_video_service_host.h"
-#include "components/arc/arc_bridge_service.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -63,7 +62,6 @@
 void ArcServiceLauncher::Shutdown() {
   DCHECK(arc_service_manager_);
   arc_service_manager_->Shutdown();
-  arc_service_manager_->arc_bridge_service()->Shutdown();
 }
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.cc
new file mode 100644
index 0000000..e125742
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.cc
@@ -0,0 +1,42 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h"
+
+#include "base/files/file_path.h"
+#include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
+#include "net/base/escape.h"
+
+namespace arc {
+
+namespace {
+
+const char kMountPointName[] = "arc-content";
+
+}  // namespace
+
+GURL ArcUrlToExternalFileUrl(const GURL& arc_url) {
+  // Return "externalfile:arc-content/<|arc_url| escaped>".
+  base::FilePath virtual_path =
+      base::FilePath::FromUTF8Unsafe(kMountPointName)
+          .Append(base::FilePath::FromUTF8Unsafe(
+              net::EscapeQueryParamValue(arc_url.spec(), false)));
+  return chromeos::VirtualPathToExternalFileURL(virtual_path);
+}
+
+GURL ExternalFileUrlToArcUrl(const GURL& external_file_url) {
+  base::FilePath virtual_path =
+      chromeos::ExternalFileURLToVirtualPath(external_file_url);
+  base::FilePath path_after_root;
+  if (!base::FilePath::FromUTF8Unsafe(kMountPointName)
+           .AppendRelativePath(virtual_path, &path_after_root)) {
+    return GURL();
+  }
+  return GURL(net::UnescapeURLComponent(
+      path_after_root.AsUTF8Unsafe(),
+      net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
+          net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h
new file mode 100644
index 0000000..86fa236
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_URL_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_URL_UTIL_H_
+
+#include "url/gurl.h"
+
+namespace arc {
+
+// Converts a URL which can be used within the ARC container to an externalfile:
+// URL which can be used by Chrome.
+GURL ArcUrlToExternalFileUrl(const GURL& arc_url);
+
+// Converts an externalfile: URL to a URL which can be used within the ARC
+// container. If the given URL cannot be converted to an ARC URL, returns an
+// empty GURL.
+GURL ExternalFileUrlToArcUrl(const GURL& external_file_url);
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_URL_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util_unittest.cc
new file mode 100644
index 0000000..a8b4de9c
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_url_util.h"
+#include "content/public/common/url_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace arc {
+
+TEST(ArcContentFileSystemUrlUtilTest, EncodeAndDecode) {
+  {
+    GURL src("file://foo/bar/baz");
+    GURL dest = ArcUrlToExternalFileUrl(src);
+    EXPECT_TRUE(dest.is_valid());
+    EXPECT_EQ(content::kExternalFileScheme, dest.scheme());
+    GURL result = ExternalFileUrlToArcUrl(dest);
+    EXPECT_TRUE(result.is_valid());
+    EXPECT_EQ(src, result);
+  }
+  {
+    GURL src("content://org.chromium.foo/bar/baz");
+    GURL dest = ArcUrlToExternalFileUrl(src);
+    EXPECT_TRUE(dest.is_valid());
+    EXPECT_EQ(content::kExternalFileScheme, dest.scheme());
+    GURL result = ExternalFileUrlToArcUrl(dest);
+    EXPECT_TRUE(result.is_valid());
+    EXPECT_EQ(src, result);
+  }
+  {
+    GURL src("content://org.chromium.foo/bar/%19%20%21");
+    GURL dest = ArcUrlToExternalFileUrl(src);
+    EXPECT_TRUE(dest.is_valid());
+    EXPECT_EQ(content::kExternalFileScheme, dest.scheme());
+    GURL result = ExternalFileUrlToArcUrl(dest);
+    EXPECT_TRUE(result.is_valid());
+    EXPECT_EQ(src, result);
+  }
+  {
+    GURL src("content://org.chromium.foo/!@#$%^&*()_+|~-=\\`[]{};':\"<>?,./");
+    GURL dest = ArcUrlToExternalFileUrl(src);
+    EXPECT_TRUE(dest.is_valid());
+    EXPECT_EQ(content::kExternalFileScheme, dest.scheme());
+    GURL result = ExternalFileUrlToArcUrl(dest);
+    EXPECT_TRUE(result.is_valid());
+    EXPECT_EQ(src, result);
+  }
+  {
+    base::string16 utf16_string = {
+        0x307b,  // HIRAGANA_LETTER_HO
+        0x3052,  // HIRAGANA_LETTER_GE
+    };
+    GURL src("content://org.chromium.foo/" + base::UTF16ToUTF8(utf16_string));
+    GURL dest = ArcUrlToExternalFileUrl(src);
+    EXPECT_TRUE(dest.is_valid());
+    EXPECT_EQ(content::kExternalFileScheme, dest.scheme());
+    GURL result = ExternalFileUrlToArcUrl(dest);
+    EXPECT_TRUE(result.is_valid());
+    EXPECT_EQ(src, result);
+  }
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_util.cc b/chrome/browser/chromeos/fileapi/external_file_url_util.cc
index 74910d7..42c7e3d3 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_util.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_util.cc
@@ -37,10 +37,7 @@
     return GURL();
   }
 
-  return GURL(base::StringPrintf(
-      "%s:%s",
-      content::kExternalFileScheme,
-      file_system_url.virtual_path().AsUTF8Unsafe().c_str()));
+  return VirtualPathToExternalFileURL(file_system_url.virtual_path());
 }
 
 base::FilePath ExternalFileURLToVirtualPath(const GURL& url) {
@@ -51,6 +48,11 @@
   return base::FilePath::FromUTF8Unsafe(path_string);
 }
 
+GURL VirtualPathToExternalFileURL(const base::FilePath& virtual_path) {
+  return GURL(base::StringPrintf("%s:%s", content::kExternalFileScheme,
+                                 virtual_path.AsUTF8Unsafe().c_str()));
+}
+
 GURL CreateExternalFileURLFromPath(Profile* profile,
                                    const base::FilePath& path) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_util.h b/chrome/browser/chromeos/fileapi/external_file_url_util.h
index afcf8ca8..3d01da5 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_util.h
+++ b/chrome/browser/chromeos/fileapi/external_file_url_util.h
@@ -32,6 +32,9 @@
 // Converts a externalfile: URL back to a virtual path of FileSystemURL.
 base::FilePath ExternalFileURLToVirtualPath(const GURL& url);
 
+// Converts a virtual path of FileSystemURL to an externalfile: URL.
+GURL VirtualPathToExternalFileURL(const base::FilePath& virtual_path);
+
 // Obtains external file URL (e.g. external:drive/root/sample.txt) from file
 // path (e.g. /special/drive-xxx/root/sample.txt), if the |path| points an
 // external location (drive, MTP, or FSP). Otherwise, it returns empty URL.
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_util_unittest.cc b/chrome/browser/chromeos/fileapi/external_file_url_util_unittest.cc
index e166c08..61486959 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_util_unittest.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_util_unittest.cc
@@ -8,6 +8,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/drive/file_system_core_util.h"
+#include "content/public/common/url_constants.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -78,4 +79,12 @@
                 .AsUTF8Unsafe());
 }
 
+TEST_F(ExternalFileURLUtilTest, VirtualPathToExternalFileURL) {
+  base::FilePath virtual_path(FILE_PATH_LITERAL("foo/bar012.txt"));
+  GURL result = VirtualPathToExternalFileURL(virtual_path);
+  EXPECT_TRUE(result.is_valid());
+  EXPECT_EQ(content::kExternalFileScheme, result.scheme());
+  EXPECT_EQ(virtual_path.value(), ExternalFileURLToVirtualPath(result).value());
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 1e87b4b..75f257f 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -1173,11 +1173,6 @@
 }
 
 void ChromeUserManagerImpl::UpdateUserTimeZoneRefresher(Profile* profile) {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kDisableTimeZoneTrackingOption)) {
-    return;
-  }
-
   const user_manager::User* user =
       ProfileHelper::Get()->GetUserByProfile(profile);
   if (user == NULL)
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.cc b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
index a25a76e..ac9f358 100644
--- a/chrome/browser/chromeos/system/timezone_resolver_manager.cc
+++ b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
@@ -160,10 +160,6 @@
 }
 
 bool TimeZoneResolverManager::TimeZoneResolverShouldBeRunning() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kDisableTimeZoneTrackingOption)) {
-    return false;
-  }
   ServiceConfiguration result = GetServiceConfigurationFromPolicy();
 
   if (result == UNSPECIFIED) {
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index 4437b54..ae6d93e 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -289,10 +289,6 @@
 
 void SiteEngagementService::CleanupEngagementScores(
     bool update_last_engagement_time) const {
-  // This method should not be called with |update_last_engagement_time| = true
-  // if the last engagement time isn't stale.
-  DCHECK(!update_last_engagement_time || IsLastEngagementStale());
-
   HostContentSettingsMap* settings_map =
       HostContentSettingsMapFactory::GetForProfile(profile_);
   std::unique_ptr<ContentSettingsForOneType> engagement_settings =
@@ -304,25 +300,51 @@
   base::Time last_engagement_time = GetLastEngagementTime();
   base::Time rebase_time = now - GetMaxDecayPeriod();
   base::Time new_last_engagement_time;
+
+  // If |update_last_engagement_time| is true, we must have either:
+  //   a) last_engagement_time is in the future; OR
+  //   b) last_engagement_time < rebase_time < now
+  DCHECK(!update_last_engagement_time || last_engagement_time >= now ||
+         (last_engagement_time < rebase_time && rebase_time < now));
+
+  // Cap |last_engagement_time| at |now| if it is in the future. This ensures
+  // that we use sane offsets when a user has adjusted their clock backwards and
+  // have a mix of scores prior to and after |now|.
+  if (last_engagement_time > now)
+    last_engagement_time = now;
+
   for (const auto& site : *engagement_settings) {
     GURL origin(site.primary_pattern.ToString());
 
     if (origin.is_valid()) {
       SiteEngagementScore score = CreateEngagementScore(origin);
       if (update_last_engagement_time) {
-        // Work out the offset between this score's last engagement time and the
-        // last time the service recorded any engagement. Set the score's last
-        // engagement time to rebase_time - offset to preserve its state,
-        // relative to the rebase date. This ensures that the score will decay
-        // the next time it is used, but will not decay too much.
-        DCHECK_LE(score.last_engagement_time(), rebase_time);
-        base::TimeDelta offset =
-            last_engagement_time - score.last_engagement_time();
-        base::Time rebase_score_time = rebase_time - offset;
-        score.set_last_engagement_time(rebase_score_time);
-        if (rebase_score_time > new_last_engagement_time)
-          new_last_engagement_time = rebase_score_time;
+        // Catch cases of users moving their clocks, or a potential race where
+        // a score content setting is written out to prefs, but the updated
+        // |last_engagement_time| was not written, as both are lossy
+        // preferences. |rebase_time| is strictly in the past, so any score with
+        // a last updated time in the future is caught by this branch.
+        if (score.last_engagement_time() > rebase_time) {
+          score.set_last_engagement_time(now);
+        } else if (score.last_engagement_time() > last_engagement_time) {
+          // This score is newer than |last_engagement_time|, but older than
+          // |rebase_time|. It should still be rebased with no offset as we
+          // don't accurately know what the offset should be.
+          score.set_last_engagement_time(rebase_time);
+        } else {
+          // Work out the offset between this score's last engagement time and
+          // the last time the service recorded any engagement. Set the score's
+          // last engagement time to rebase_time - offset to preserve its state,
+          // relative to the rebase date. This ensures that the score will decay
+          // the next time it is used, but will not decay too much.
+          base::TimeDelta offset =
+              last_engagement_time - score.last_engagement_time();
+          base::Time rebase_score_time = rebase_time - offset;
+          score.set_last_engagement_time(rebase_score_time);
+        }
 
+        if (score.last_engagement_time() > new_last_engagement_time)
+          new_last_engagement_time = score.last_engagement_time();
         score.Commit();
       }
 
@@ -434,9 +456,8 @@
                            : SiteEngagementScore::GetVisibleMediaPoints());
 
   RecordMetrics();
-  FOR_EACH_OBSERVER(
-      SiteEngagementObserver, observer_list_,
-      OnEngagementIncreased(web_contents, url, GetScore(url)));
+  for (SiteEngagementObserver& observer : observer_list_)
+    observer.OnEngagementIncreased(web_contents, url, GetScore(url));
 }
 
 void SiteEngagementService::HandleNavigation(content::WebContents* web_contents,
@@ -448,9 +469,8 @@
     AddPoints(url, SiteEngagementScore::GetNavigationPoints());
 
     RecordMetrics();
-    FOR_EACH_OBSERVER(
-        SiteEngagementObserver, observer_list_,
-        OnEngagementIncreased(web_contents, url, GetScore(url)));
+    for (SiteEngagementObserver& observer : observer_list_)
+      observer.OnEngagementIncreased(web_contents, url, GetScore(url));
   }
 }
 
@@ -462,19 +482,20 @@
   AddPoints(url, SiteEngagementScore::GetUserInputPoints());
 
   RecordMetrics();
-  FOR_EACH_OBSERVER(
-      SiteEngagementObserver, observer_list_,
-      OnEngagementIncreased(web_contents, url, GetScore(url)));
+  for (SiteEngagementObserver& observer : observer_list_)
+    observer.OnEngagementIncreased(web_contents, url, GetScore(url));
 }
 
 bool SiteEngagementService::IsLastEngagementStale() const {
-  // This only happens when Chrome is first run and the user has never recorded
-  // any engagement.
+  // Only happens on first run when no engagement has ever been recorded.
   base::Time last_engagement_time = GetLastEngagementTime();
   if (last_engagement_time.is_null())
     return false;
 
-  return (clock_->Now() - last_engagement_time) >= GetStalePeriod();
+  // Stale is either too *far* back, or any amount *forward* in time. This could
+  // occur due to a changed clock, or extended non-use of the browser.
+  return (clock_->Now() - last_engagement_time) >= GetStalePeriod() ||
+         (clock_->Now() < last_engagement_time);
 }
 
 void SiteEngagementService::OnURLsDeleted(
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index e7b463e9..4db77da 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -138,6 +138,10 @@
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, CheckHistograms);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, CleanupEngagementScores);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
+                           CleanupMovesScoreBackToNow);
+  FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
+                           CleanupMovesScoreBackToRebase);
+  FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
                            CleanupEngagementScoresProportional);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, ClearHistoryForURLs);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetMedianEngagement);
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index 96e3b9ab..3691cd6 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -1501,6 +1501,119 @@
   EXPECT_EQ(later_in_day, service->GetLastEngagementTime());
 }
 
+TEST_F(SiteEngagementServiceTest, CleanupMovesScoreBackToNow) {
+  base::SimpleTestClock* clock = new base::SimpleTestClock();
+  std::unique_ptr<SiteEngagementService> service(
+      new SiteEngagementService(profile(), base::WrapUnique(clock)));
+  base::Time last_engagement_time;
+
+  base::Time current_day = GetReferenceTime();
+  clock->SetNow(current_day);
+
+  GURL origin("http://www.google.com/");
+  service->AddPoints(origin, 1);
+  EXPECT_EQ(1, service->GetScore(origin));
+  EXPECT_EQ(current_day, service->GetLastEngagementTime());
+
+  // Send the clock back in time before the stale period and add engagement for
+  // a new origin. Ensure that the original origin has its last engagement time
+  // updated to now as a result.
+  base::Time before_stale_period =
+      clock->Now() - service->GetStalePeriod() - service->GetMaxDecayPeriod();
+  clock->SetNow(before_stale_period);
+
+  GURL origin1("http://maps.google.com/");
+  service->AddPoints(origin1, 1);
+
+  EXPECT_EQ(before_stale_period,
+            service->CreateEngagementScore(origin).last_engagement_time());
+  EXPECT_EQ(before_stale_period, service->GetLastEngagementTime());
+  EXPECT_EQ(1, service->GetScore(origin));
+  EXPECT_EQ(1, service->GetScore(origin1));
+
+  // Advance within a decay period and add points.
+  base::TimeDelta less_than_decay_period =
+      base::TimeDelta::FromHours(SiteEngagementScore::GetDecayPeriodInHours()) -
+      base::TimeDelta::FromSeconds(30);
+  base::Time origin1_last_updated = clock->Now() + less_than_decay_period;
+  clock->SetNow(origin1_last_updated);
+  service->AddPoints(origin, 1);
+  service->AddPoints(origin1, 5);
+  EXPECT_EQ(2, service->GetScore(origin));
+  EXPECT_EQ(6, service->GetScore(origin1));
+
+  clock->SetNow(clock->Now() + less_than_decay_period);
+  service->AddPoints(origin, 5);
+  EXPECT_EQ(7, service->GetScore(origin));
+
+  // Move forward to the max number of decays per score. This is within the
+  // stale period so no cleanup should be run.
+  for (int i = 0; i < SiteEngagementScore::GetMaxDecaysPerScore(); ++i) {
+    clock->SetNow(clock->Now() + less_than_decay_period);
+    service->AddPoints(origin, 5);
+    EXPECT_EQ(clock->Now(), service->GetLastEngagementTime());
+  }
+  EXPECT_EQ(12, service->GetScore(origin));
+  EXPECT_EQ(clock->Now(), service->GetLastEngagementTime());
+
+  // Move the clock back to precisely 1 decay period after origin1's last
+  // updated time. |last_engagement_time| is in the future, so AddPoints
+  // triggers a cleanup. Ensure that |last_engagement_time| is moved back
+  // appropriately, while origin1 is decayed correctly (once).
+  clock->SetNow(origin1_last_updated + less_than_decay_period +
+                base::TimeDelta::FromSeconds(30));
+  service->AddPoints(origin1, 1);
+
+  EXPECT_EQ(clock->Now(),
+            service->CreateEngagementScore(origin).last_engagement_time());
+  EXPECT_EQ(clock->Now(), service->GetLastEngagementTime());
+  EXPECT_EQ(12, service->GetScore(origin));
+  EXPECT_EQ(1, service->GetScore(origin1));
+}
+
+TEST_F(SiteEngagementServiceTest, CleanupMovesScoreBackToRebase) {
+  base::SimpleTestClock* clock = new base::SimpleTestClock();
+  std::unique_ptr<SiteEngagementService> service(
+      new SiteEngagementService(profile(), base::WrapUnique(clock)));
+  base::Time last_engagement_time;
+
+  base::Time current_day = GetReferenceTime();
+  clock->SetNow(current_day);
+
+  GURL origin("http://www.google.com/");
+  service->ResetScoreForURL(origin, 5);
+  service->AddPoints(origin, 5);
+  EXPECT_EQ(10, service->GetScore(origin));
+  EXPECT_EQ(current_day, service->GetLastEngagementTime());
+
+  // Send the clock back in time before the stale period and add engagement for
+  // a new origin.
+  base::Time before_stale_period =
+      clock->Now() - service->GetStalePeriod() - service->GetMaxDecayPeriod();
+  clock->SetNow(before_stale_period);
+
+  GURL origin1("http://maps.google.com/");
+  service->AddPoints(origin1, 1);
+
+  EXPECT_EQ(before_stale_period, service->GetLastEngagementTime());
+
+  // Set the clock such that |origin|'s last engagement time is between
+  // last_engagement_time and rebase_time.
+  clock->SetNow(current_day + service->GetStalePeriod() +
+                service->GetMaxDecayPeriod() -
+                base::TimeDelta::FromSeconds((30)));
+  base::Time rebased_time = clock->Now() - service->GetMaxDecayPeriod();
+  service->CleanupEngagementScores(true);
+
+  // Ensure that the original origin has its last engagement time updated to
+  // rebase_time, and it has decayed when we access the score.
+  EXPECT_EQ(rebased_time,
+            service->CreateEngagementScore(origin).last_engagement_time());
+  EXPECT_EQ(rebased_time, service->GetLastEngagementTime());
+  EXPECT_EQ(5, service->GetScore(origin));
+  EXPECT_EQ(0, service->GetScore(origin1));
+}
+
 TEST_F(SiteEngagementServiceTest, IncognitoEngagementService) {
   SiteEngagementService* service = SiteEngagementService::Get(profile());
   ASSERT_TRUE(service);
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
index 2b95e0e..82a2923 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
@@ -45,22 +45,12 @@
 // TODO(hcarmona): Investigate converting these tests to unittests.
 
 // TODO(crbug.com/643097) Disabled for flakiness.
-#if defined(OS_WIN)
-#define MAYBE_SaveAddress DISABLED_SaveAddress
-#else
-#define MAYBE_SaveAddress SaveAddress
-#endif  // defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_SaveAddress) {
+IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_SaveAddress) {
   EXPECT_TRUE(RunAutofillSubtest("saveAddress")) << message_;
 }
 
 // TODO(crbug.com/643097) Disabled for flakiness.
-#if defined(OS_WIN)
-#define MAYBE_GetCountryList DISABLED_GetCountryList
-#else
-#define MAYBE_GetCountryList GetCountryList
-#endif  // defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_GetCountryList) {
+IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_GetCountryList) {
   EXPECT_TRUE(RunAutofillSubtest("getCountryList")) << message_;
 }
 
@@ -69,22 +59,12 @@
 }
 
 // TODO(crbug.com/643097) Disabled for flakiness.
-#if defined(OS_WIN)
-#define MAYBE_SaveCreditCard DISABLED_SaveCreditCard
-#else
-#define MAYBE_SaveCreditCard SaveCreditCard
-#endif  // defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_SaveCreditCard) {
+IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_SaveCreditCard) {
   EXPECT_TRUE(RunAutofillSubtest("saveCreditCard")) << message_;
 }
 
 // TODO(crbug.com/643097) Disabled for flakiness.
-#if defined(OS_WIN)
-#define MAYBE_RemoveEntry DISABLED_RemoveEntry
-#else
-#define MAYBE_RemoveEntry RemoveEntry
-#endif  // defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_RemoveEntry) {
+IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_RemoveEntry) {
   EXPECT_TRUE(RunAutofillSubtest("removeEntry")) << message_;
 }
 
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store.cc b/chrome/browser/extensions/api/content_settings/content_settings_store.cc
index a53e603..dd3179d 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_store.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_store.cc
@@ -116,10 +116,9 @@
     }
   }
 
-  // Send notification that content settings changed.
-  // TODO(markusheintz): Notifications should only be sent if the set content
-  // setting is effective and not hidden by another setting of another
-  // extension installed more recently.
+  // Send notification that content settings changed. (Note: This is responsible
+  // for updating the pref store, so cannot be skipped even if the setting would
+  // be masked by another extension.)
   NotifyOfContentSettingChanged(ext_id,
                                 scope != kExtensionPrefsScopeRegular);
 }
@@ -320,6 +319,14 @@
     dict->GetString(keys::kContentSettingsTypeKey, &content_settings_type_str);
     ContentSettingsType content_settings_type =
         helpers::StringToContentSettingsType(content_settings_type_str);
+    if (content_settings_type == CONTENT_SETTINGS_TYPE_FULLSCREEN ||
+        content_settings_type == CONTENT_SETTINGS_TYPE_MOUSELOCK) {
+      // Fullscreen and mouselock are deprecated. Skip over settings of these
+      // types, effectively deleting them from the in-memory model. This will
+      // implicitly delete these old settings from the pref store when it is
+      // written back.
+      continue;
+    }
     DCHECK_NE(CONTENT_SETTINGS_TYPE_DEFAULT, content_settings_type);
 
     std::string resource_identifier;
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc b/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc
index 9986d4e..2d9412e 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc
@@ -8,6 +8,10 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h"
+#include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/browser/content_settings_rule.h"
 #include "components/content_settings/core/browser/content_settings_utils.h"
 #include "components/content_settings/core/test/content_settings_test_utils.h"
@@ -19,6 +23,8 @@
 
 namespace extensions {
 
+namespace keys = content_settings_api_constants;
+
 namespace {
 
 void CheckRule(const content_settings::Rule& rule,
@@ -255,4 +261,89 @@
   ASSERT_EQ(0u, rules.size());
 }
 
+TEST_F(ContentSettingsStoreTest, SetFromList) {
+  // Force creation of ContentSettingsRegistry, so that the string to content
+  // setting type lookup can succeed.
+  content_settings::ContentSettingsRegistry::GetInstance();
+
+  ::testing::StrictMock<MockContentSettingsStoreObserver> observer;
+  store()->AddObserver(&observer);
+
+  GURL url("http://www.youtube.com");
+
+  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
+            GetContentSettingFromStore(store(),
+                                       url,
+                                       url,
+                                       CONTENT_SETTINGS_TYPE_COOKIES,
+                                       std::string(),
+                                       false));
+
+  // Register first extension
+  std::string ext_id("my_extension");
+  RegisterExtension(ext_id);
+
+  // Set setting via a list
+  ContentSettingsPattern pattern =
+      ContentSettingsPattern::FromURL(GURL("http://www.youtube.com"));
+  EXPECT_CALL(observer, OnContentSettingChanged(ext_id, false));
+
+  // Build a preference list in JSON format.
+  base::ListValue pref_list;
+  // {"primaryPattern": pattern, "secondaryPattern": pattern, "type": "cookies",
+  //  "setting": "allow"}
+  auto dict_value = base::MakeUnique<base::DictionaryValue>();
+  dict_value->SetString(keys::kPrimaryPatternKey, pattern.ToString());
+  dict_value->SetString(keys::kSecondaryPatternKey, pattern.ToString());
+  dict_value->SetString(keys::kContentSettingsTypeKey, "cookies");
+  dict_value->SetString(keys::kContentSettingKey, "allow");
+  pref_list.Append(std::move(dict_value));
+  // Test content settings types that have been removed. Should be ignored.
+  // {"primaryPattern": pattern, "secondaryPattern": pattern,
+  //  "type": "fullscreen", "setting": "allow"}
+  dict_value = base::MakeUnique<base::DictionaryValue>();
+  dict_value->SetString(keys::kPrimaryPatternKey, pattern.ToString());
+  dict_value->SetString(keys::kSecondaryPatternKey, pattern.ToString());
+  dict_value->SetString(keys::kContentSettingsTypeKey, "fullscreen");
+  dict_value->SetString(keys::kContentSettingKey, "allow");
+  pref_list.Append(std::move(dict_value));
+  // {"primaryPattern": pattern, "secondaryPattern": pattern,
+  //  "type": "mouselock", "setting": "allow"}
+  dict_value = base::MakeUnique<base::DictionaryValue>();
+  dict_value->SetString(keys::kPrimaryPatternKey, pattern.ToString());
+  dict_value->SetString(keys::kSecondaryPatternKey, pattern.ToString());
+  dict_value->SetString(keys::kContentSettingsTypeKey, "mouselock");
+  dict_value->SetString(keys::kContentSettingKey, "allow");
+  pref_list.Append(std::move(dict_value));
+
+  store()->SetExtensionContentSettingFromList(ext_id, &pref_list,
+                                              kExtensionPrefsScopeRegular);
+  Mock::VerifyAndClear(&observer);
+
+  EXPECT_EQ(CONTENT_SETTING_ALLOW,
+            GetContentSettingFromStore(store(),
+                                       url,
+                                       url,
+                                       CONTENT_SETTINGS_TYPE_COOKIES,
+                                       std::string(),
+                                       false));
+  // The fullscreen and mouselock settings should have been ignored.
+  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
+            GetContentSettingFromStore(store(),
+                                       url,
+                                       url,
+                                       CONTENT_SETTINGS_TYPE_FULLSCREEN,
+                                       std::string(),
+                                       false));
+  EXPECT_EQ(CONTENT_SETTING_DEFAULT,
+            GetContentSettingFromStore(store(),
+                                       url,
+                                       url,
+                                       CONTENT_SETTINGS_TYPE_MOUSELOCK,
+                                       std::string(),
+                                       false));
+
+  store()->RemoveObserver(&observer);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/lifetime/keep_alive_registry.cc b/chrome/browser/lifetime/keep_alive_registry.cc
index 195956f..f61ef82 100644
--- a/chrome/browser/lifetime/keep_alive_registry.cc
+++ b/chrome/browser/lifetime/keep_alive_registry.cc
@@ -136,15 +136,15 @@
 void KeepAliveRegistry::OnKeepAliveStateChanged(bool new_keeping_alive) {
   DVLOG(1) << "Notifying KeepAliveStateObservers: KeepingAlive changed to: "
            << new_keeping_alive;
-  FOR_EACH_OBSERVER(KeepAliveStateObserver, observers_,
-                    OnKeepAliveStateChanged(new_keeping_alive));
+  for (KeepAliveStateObserver& observer : observers_)
+    observer.OnKeepAliveStateChanged(new_keeping_alive);
 }
 
 void KeepAliveRegistry::OnRestartAllowedChanged(bool new_restart_allowed) {
   DVLOG(1) << "Notifying KeepAliveStateObservers: Restart changed to: "
            << new_restart_allowed;
-  FOR_EACH_OBSERVER(KeepAliveStateObserver, observers_,
-                    OnKeepAliveRestartStateChanged(new_restart_allowed));
+  for (KeepAliveStateObserver& observer : observers_)
+    observer.OnKeepAliveRestartStateChanged(new_restart_allowed);
 }
 
 void KeepAliveRegistry::DecrementCount(KeepAliveOrigin origin,
diff --git a/chrome/browser/loader/safe_browsing_resource_throttle.cc b/chrome/browser/loader/safe_browsing_resource_throttle.cc
index b795ea1..545b9be 100644
--- a/chrome/browser/loader/safe_browsing_resource_throttle.cc
+++ b/chrome/browser/loader/safe_browsing_resource_throttle.cc
@@ -93,14 +93,15 @@
     : state_(STATE_NONE),
       defer_state_(DEFERRED_NONE),
       threat_type_(safe_browsing::SB_THREAT_TYPE_SAFE),
-      database_manager_(sb_service->database_manager()),
+      database_manager_(safe_browsing::V4FeatureList::IsV4HybridEnabled()
+                            ? sb_service->v4_local_database_manager()
+                            : sb_service->database_manager()),
       ui_manager_(sb_service->ui_manager()),
       request_(request),
       resource_type_(resource_type),
       net_log_with_source_(
           net::NetLogWithSource::Make(request->net_log().net_log(),
-                                      NetLogSourceType::SAFE_BROWSING)),
-      v4_local_database_manager_(sb_service->v4_local_database_manager()) {}
+                                      NetLogSourceType::SAFE_BROWSING)) {}
 
 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
   if (defer_state_ != DEFERRED_NONE) {
@@ -109,10 +110,6 @@
 
   if (state_ == STATE_CHECKING_URL) {
     database_manager_->CancelCheck(this);
-    if (safe_browsing::V4FeatureList::IsParallelCheckEnabled()) {
-      v4_local_database_manager_->CancelCheck(this);
-    }
-
     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
                    "request_canceled");
   }
@@ -372,21 +369,19 @@
   // To reduce aggregate latency on mobile, check only the most dangerous
   // resource types.
   if (!database_manager_->CanCheckResourceType(resource_type_)) {
+    // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType
+    // to be consistent with the other PVer4 metrics.
     UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Skipped", resource_type_,
                               content::RESOURCE_TYPE_LAST_TYPE);
     return true;
   }
 
-  bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
+  // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType to
+  // be consistent with the other PVer4 metrics.
   UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Checked", resource_type_,
                             content::RESOURCE_TYPE_LAST_TYPE);
 
-  if (safe_browsing::V4FeatureList::IsParallelCheckEnabled() &&
-      v4_local_database_manager_->CanCheckResourceType(resource_type_)) {
-    v4_local_database_manager_->CheckBrowseUrl(url, this);
-  }
-
-  if (succeeded_synchronously) {
+  if (database_manager_->CheckBrowseUrl(url, this)) {
     threat_type_ = safe_browsing::SB_THREAT_TYPE_SAFE;
     ui_manager_->LogPauseDelay(base::TimeDelta());  // No delay.
     return true;
@@ -411,9 +406,7 @@
   CHECK_EQ(state_, STATE_CHECKING_URL);
 
   database_manager_->CancelCheck(this);
-  if (safe_browsing::V4FeatureList::IsParallelCheckEnabled()) {
-    v4_local_database_manager_->CancelCheck(this);
-  }
+
   OnCheckBrowseUrlResult(url_being_checked_, safe_browsing::SB_THREAT_TYPE_SAFE,
                          safe_browsing::ThreatMetadata());
 }
diff --git a/chrome/browser/loader/safe_browsing_resource_throttle.h b/chrome/browser/loader/safe_browsing_resource_throttle.h
index e4c7344..17a93d71 100644
--- a/chrome/browser/loader/safe_browsing_resource_throttle.h
+++ b/chrome/browser/loader/safe_browsing_resource_throttle.h
@@ -183,8 +183,6 @@
   const net::URLRequest* request_;
   const content::ResourceType resource_type_;
   net::NetLogWithSource net_log_with_source_;
-  scoped_refptr<safe_browsing::V4LocalDatabaseManager>
-      v4_local_database_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingResourceThrottle);
 };
diff --git a/chrome/browser/local_discovery/service_discovery_client_mdns.cc b/chrome/browser/local_discovery/service_discovery_client_mdns.cc
index cb8ff2e..7e7ca7f 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mdns.cc
+++ b/chrome/browser/local_discovery/service_discovery_client_mdns.cc
@@ -426,7 +426,8 @@
 
   // Initialization is done, no need to delay tasks.
   need_dalay_mdns_tasks_ = false;
-  FOR_EACH_OBSERVER(Proxy, proxies_, OnNewMdnsReady());
+  for (Proxy& observer : proxies_)
+    observer.OnNewMdnsReady();
 }
 
 void ServiceDiscoveryClientMdns::ReportSuccess() {
@@ -438,7 +439,8 @@
 void ServiceDiscoveryClientMdns::OnBeforeMdnsDestroy() {
   need_dalay_mdns_tasks_ = true;
   weak_ptr_factory_.InvalidateWeakPtrs();
-  FOR_EACH_OBSERVER(Proxy, proxies_, OnMdnsDestroy());
+  for (Proxy& observer : proxies_)
+    observer.OnMdnsDestroy();
 }
 
 void ServiceDiscoveryClientMdns::DestroyMdns() {
diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc
index e761e81a..b9c1430 100644
--- a/chrome/browser/memory/tab_manager.cc
+++ b/chrome/browser/memory/tab_manager.cc
@@ -490,15 +490,14 @@
 
 void TabManager::OnDiscardedStateChange(content::WebContents* contents,
                                         bool is_discarded) {
-  FOR_EACH_OBSERVER(TabManagerObserver, observers_,
-                    OnDiscardedStateChange(contents, is_discarded));
+  for (TabManagerObserver& observer : observers_)
+    observer.OnDiscardedStateChange(contents, is_discarded);
 }
 
 void TabManager::OnAutoDiscardableStateChange(content::WebContents* contents,
                                               bool is_auto_discardable) {
-  FOR_EACH_OBSERVER(
-      TabManagerObserver, observers_,
-      OnAutoDiscardableStateChange(contents, is_auto_discardable));
+  for (TabManagerObserver& observer : observers_)
+    observer.OnAutoDiscardableStateChange(contents, is_auto_discardable);
 }
 
 // static
@@ -639,6 +638,7 @@
           contents->GetPageImportanceSignals().had_form_interaction;
       stats.discard_count = GetWebContentsData(contents)->DiscardCount();
       stats.last_active = contents->GetLastActiveTime();
+      stats.last_hidden = contents->GetLastHiddenTime();
       stats.render_process_host = contents->GetRenderProcessHost();
       stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle();
       stats.child_process_host_id = contents->GetRenderProcessHost()->GetID();
@@ -710,7 +710,7 @@
     // timers for simplicity, so PurgeAndSuspend is called even after the
     // renderer is purged and suspended once. This should be replaced with
     // timers if we want necessary and sufficient signals.
-    if (tab.last_active > purge_and_suspend_time_threshold)
+    if (tab.last_hidden > purge_and_suspend_time_threshold)
       continue;
     if (!CanSuspendBackgroundedRenderer(tab.child_process_host_id))
       continue;
diff --git a/chrome/browser/memory/tab_stats.h b/chrome/browser/memory/tab_stats.h
index c036f08..b2be60a 100644
--- a/chrome/browser/memory/tab_stats.h
+++ b/chrome/browser/memory/tab_stats.h
@@ -33,6 +33,7 @@
   bool has_form_entry;  // User has entered text in a form.
   int discard_count;
   base::TimeTicks last_active;
+  base::TimeTicks last_hidden;
   content::RenderProcessHost* render_process_host;
   base::ProcessHandle renderer_handle;
   int child_process_host_id;
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 921f477c..48fd529 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -317,20 +317,20 @@
 void MessageCenterSettingsController::OnIconImageUpdated(
     const message_center::NotifierId& id,
     const gfx::Image& image) {
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, observers_,
-                    UpdateIconImage(id, image));
+  for (message_center::NotifierSettingsObserver& observer : observers_)
+    observer.UpdateIconImage(id, image);
 }
 
 void MessageCenterSettingsController::OnNotifierEnabledChanged(
     const message_center::NotifierId& id,
     bool enabled) {
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, observers_,
-                    NotifierEnabledChanged(id, enabled));
+  for (message_center::NotifierSettingsObserver& observer : observers_)
+    observer.NotifierEnabledChanged(id, enabled);
 }
 
 void MessageCenterSettingsController::DispatchNotifierGroupChanged() {
-  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver, observers_,
-                    NotifierGroupChanged());
+  for (message_center::NotifierSettingsObserver& observer : observers_)
+    observer.NotifierGroupChanged();
 }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/permissions/permission_request_manager.cc b/chrome/browser/permissions/permission_request_manager.cc
index 40fdb50..3d58a7204 100644
--- a/chrome/browser/permissions/permission_request_manager.cc
+++ b/chrome/browser/permissions/permission_request_manager.cc
@@ -503,7 +503,8 @@
 }
 
 void PermissionRequestManager::NotifyBubbleAdded() {
-  FOR_EACH_OBSERVER(Observer, observer_list_, OnBubbleAdded());
+  for (Observer& observer : observer_list_)
+    observer.OnBubbleAdded();
 }
 
 void PermissionRequestManager::DoAutoResponseForTesting() {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index b50ff9e..8ca9e57 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -4190,7 +4190,8 @@
         std::unique_ptr<chromeos::SessionManagerClient>(
             fake_session_manager_client_));
 
-    auto service = base::MakeUnique<arc::ArcBridgeServiceImpl>();
+    // Inject FakeArcSession here so blocking task runner is not needed.
+    auto service = base::MakeUnique<arc::ArcBridgeServiceImpl>(nullptr);
     service->SetArcSessionFactoryForTesting(
         base::Bind(arc::FakeArcSession::Create));
     arc::ArcServiceManager::SetArcBridgeServiceForTesting(std::move(service));
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 2e023f2..1798adc 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -455,21 +455,24 @@
 
 void PrerenderContents::NotifyPrerenderStart() {
   DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
-  FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStart(this));
+  for (Observer& observer : observer_list_)
+    observer.OnPrerenderStart(this);
 }
 
 void PrerenderContents::NotifyPrerenderStopLoading() {
-  FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStopLoading(this));
+  for (Observer& observer : observer_list_)
+    observer.OnPrerenderStopLoading(this);
 }
 
 void PrerenderContents::NotifyPrerenderDomContentLoaded() {
-  FOR_EACH_OBSERVER(Observer, observer_list_,
-                    OnPrerenderDomContentLoaded(this));
+  for (Observer& observer : observer_list_)
+    observer.OnPrerenderDomContentLoaded(this);
 }
 
 void PrerenderContents::NotifyPrerenderStop() {
   DCHECK_NE(FINAL_STATUS_MAX, final_status_);
-  FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStop(this));
+  for (Observer& observer : observer_list_)
+    observer.OnPrerenderStop(this);
   observer_list_.Clear();
 }
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs
index e5bf761..4042722 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_util_test.extjs
@@ -42,7 +42,7 @@
 
   basicDoc: function() {/*!
     <p><a href='#'></a>hello</p>
-    <h1><ul><li>a</ul><div role="group"><button></button></div></h1>
+    <h1><ul><li>a</ul><button></h1>
   */},
 
   secondDoc: function() {/*!
@@ -72,7 +72,7 @@
     }
   });
 });
-
+  
 TEST_F('AutomationUtilE2ETest', 'GetUniqueAncestors', function() {
   this.runWithLoadedTree(this.basicDoc, function(root) {
     var leftmost = root, rightmost = root;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
index 584fd8064..f5e1520 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -261,7 +261,6 @@
   ], this.RANGE);
 });
 
-
 TEST_F('CursorsTest', 'LineRange', function() {
   this.runCursorMovesOnDocument(this.simpleDoc, [
         [LINE, FORWARD, {value: 'end', index: 0}, {value: 'end', index: 3}],
@@ -325,7 +324,8 @@
 
 TEST_F('CursorsTest', 'SingleDocSelection', function() {
   this.runWithLoadedTree(function() {/*!
-    <p><a href="google.com">google home page</a></p>
+    <span>start</span>
+    <a href="google.com">google home page</a>
     <p>some more text</p>
     <p>end of text</p>
   */},
diff --git a/chrome/browser/resources/print_preview/print_preview.html b/chrome/browser/resources/print_preview/print_preview.html
index 6294da7..abae8c1 100644
--- a/chrome/browser/resources/print_preview/print_preview.html
+++ b/chrome/browser/resources/print_preview/print_preview.html
@@ -16,6 +16,7 @@
   <link rel="stylesheet" href="settings/destination_settings.css">
   <link rel="stylesheet" href="settings/color_settings.css">
   <link rel="stylesheet" href="settings/copies_settings.css">
+  <link rel="stylesheet" href="settings/settings_box.css">
   <link rel="stylesheet" href="settings/page_settings.css">
   <link rel="stylesheet" href="settings/margin_settings.css">
   <link rel="stylesheet" href="settings/media_size_settings.css">
diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.css b/chrome/browser/resources/print_preview/settings/copies_settings.css
index e053e8b..ad11c6f7 100644
--- a/chrome/browser/resources/print_preview/settings/copies_settings.css
+++ b/chrome/browser/resources/print_preview/settings/copies_settings.css
@@ -2,64 +2,11 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-#copies-settings input.copies {
-  height: 29px;
-  position: relative;
-  width: 2.75em;
-}
-
-#copies-settings-box {
-  margin: 10px 0;
-}
-
-#copies-settings input.copies.invalid {
-  background: rgb(255, 240, 240);
-  color: rgb(140, 20, 20);
-}
-
-#copies-settings button.increment:focus,
-#copies-settings button.decrement:focus,
-#copies-settings:focus {
-  z-index: 1;
-}
-
 #copies-settings .collate-container {
  -webkit-padding-start: 16px;
   display: inline-block;
 }
 
-#copies-settings button.increment,
-#copies-settings button.decrement {
-  -webkit-padding-end: 0;
-  -webkit-padding-start: 0;
-  font-weight: 600;
-  height: 29px;
-  margin: 0;
-  min-width: 0;
-  position: relative;
-  width: 2em;
-}
-
-#copies-settings button.increment {
-  -webkit-margin-start: -5px;
-  border-radius: 0;
-}
-
-#copies-settings button.decrement {
-  -webkit-margin-start: -5px;
-  border-bottom-left-radius: 0;
-  border-bottom-right-radius: 3px;
-  border-top-left-radius: 0;
-  border-top-right-radius: 3px;
-}
-
-html[dir='rtl'] #copies-settings button.decrement {
-  border-bottom-left-radius: 3px;
-  border-bottom-right-radius: 0;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 0;
-}
-
 #copies-settings .collate-container label {
   padding-top: 6px;
 }
diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.html b/chrome/browser/resources/print_preview/settings/copies_settings.html
index 42c7bff0..b2c31e2 100644
--- a/chrome/browser/resources/print_preview/settings/copies_settings.html
+++ b/chrome/browser/resources/print_preview/settings/copies_settings.html
@@ -1,24 +1,19 @@
 <div id="copies-settings" class="two-column" hidden>
   <div class="left-column">
-    <h1 id="copies-label" i18n-content="copiesLabel"></h1>
+    <h1 id="copies-label">$i18n{copiesLabel}</h1>
   </div>
   <div class="right-column">
-    <div id="copies-settings-box">
-      <input class="copies" type="text" value="1" maxlength="3"
+    <div class="settings-box" id="copies-settings-box">
+      <input class="user-value" type="number" value="1" maxlength="3"
+          max="999" min="1"
           aria-labelledby="copies-label" aria-live="polite" id="copies">
-      <button class="increment"
-          i18n-values="title:incrementTitle;aria-label:incrementTitle"
-          aria-controls="copies">+</button>
-      <button class="decrement"
-          i18n-values="title:decrementTitle;aria-label:decrementTitle"
-          aria-controls="copies">–</button>
       <div class="collate-container checkbox" aria-live="polite" hidden><label>
         <input class="collate" type="checkbox" checked
                aria-labelledby="copies-collate-label">
-        <span id="copies-collate-label" i18n-content="optionCollate"></span>
+        <span id="copies-collate-label">$i18n{optionCollate}</span>
       </label></div>
     </div>
-    <span class="hint" i18n-content="copiesInstruction" aria-live="polite">
+    <span class="hint" aria-live="polite">$i18n{copiesInstruction}</span>
     </span>
   </div>
 </div>
diff --git a/chrome/browser/resources/print_preview/settings/copies_settings.js b/chrome/browser/resources/print_preview/settings/copies_settings.js
index ce5d5ef..1d23321 100644
--- a/chrome/browser/resources/print_preview/settings/copies_settings.js
+++ b/chrome/browser/resources/print_preview/settings/copies_settings.js
@@ -32,7 +32,7 @@
     this.collateTicketItem_ = collateTicketItem;
 
     /**
-     * Timeout used to delay processing of the copies input.
+     * Timeout used to delay processing of the copies input in ms
      * @type {?number}
      * @private
      */
@@ -44,6 +44,13 @@
      * @private
      */
     this.isEnabled_ = true;
+
+    /**
+     * The element for the user input value.
+     * @type {HTMLElement}
+     * @private
+     */
+    this.inputField_ = null;
   };
 
   /**
@@ -51,7 +58,7 @@
    * @type {number}
    * @private
    */
-  CopiesSettings.TEXTFIELD_DELAY_ = 250;
+  CopiesSettings.TEXTFIELD_DELAY_MS_ = 250;
 
   CopiesSettings.prototype = {
     __proto__: print_preview.SettingsSection.prototype,
@@ -68,41 +75,31 @@
 
     /** @override */
     set isEnabled(isEnabled) {
-      this.getChildElement('input.copies').disabled = !isEnabled;
+      this.inputField_.disabled = !isEnabled;
       this.getChildElement('input.collate').disabled = !isEnabled;
       this.isEnabled_ = isEnabled;
       if (isEnabled) {
         this.updateState_();
-      } else {
-        this.getChildElement('button.increment').disabled = true;
-        this.getChildElement('button.decrement').disabled = true;
       }
     },
 
     /** @override */
     enterDocument: function() {
+      this.inputField_ = this.getChildElement('input.user-value');
       print_preview.SettingsSection.prototype.enterDocument.call(this);
       this.tracker.add(
-          this.getChildElement('input.copies'),
+          this.inputField_,
           'keydown',
           this.onTextfieldKeyDown_.bind(this));
       this.tracker.add(
-          this.getChildElement('input.copies'),
+          this.inputField_,
           'input',
           this.onTextfieldInput_.bind(this));
       this.tracker.add(
-          this.getChildElement('input.copies'),
+          this.inputField_,
           'blur',
           this.onTextfieldBlur_.bind(this));
       this.tracker.add(
-          this.getChildElement('button.increment'),
-          'click',
-          this.onButtonClicked_.bind(this, 1));
-      this.tracker.add(
-          this.getChildElement('button.decrement'),
-          'click',
-          this.onButtonClicked_.bind(this, -1));
-      this.tracker.add(
           this.getChildElement('input.collate'),
           'click',
           this.onCollateCheckboxClick_.bind(this));
@@ -122,29 +119,18 @@
      */
     updateState_: function() {
       if (this.isAvailable()) {
-        if (this.getChildElement('input.copies').value !=
-            this.copiesTicketItem_.getValue()) {
-          this.getChildElement('input.copies').value =
-              this.copiesTicketItem_.getValue();
-        }
+        if (this.inputField_.value != this.copiesTicketItem_.getValue())
+          this.inputField_.value = this.copiesTicketItem_.getValue();
 
         var currentValueGreaterThan1 = false;
         if (this.copiesTicketItem_.isValid()) {
-          this.getChildElement('input.copies').classList.remove('invalid');
+          this.inputField_.classList.remove('invalid');
           fadeOutElement(this.getChildElement('.hint'));
           var currentValue = this.copiesTicketItem_.getValueAsNumber();
-          var currentValueGreaterThan1 = currentValue > 1;
-          this.getChildElement('button.increment').disabled =
-              !this.isEnabled_ ||
-              !this.copiesTicketItem_.wouldValueBeValid(currentValue + 1);
-          this.getChildElement('button.decrement').disabled =
-              !this.isEnabled_ ||
-              !this.copiesTicketItem_.wouldValueBeValid(currentValue - 1);
+          currentValueGreaterThan1 = currentValue > 1;
         } else {
-          this.getChildElement('input.copies').classList.add('invalid');
+          this.inputField_.classList.add('invalid');
           fadeInElement(this.getChildElement('.hint'));
-          this.getChildElement('button.increment').disabled = true;
-          this.getChildElement('button.decrement').disabled = true;
         }
 
         if (!(this.getChildElement('.collate-container').hidden =
@@ -158,25 +144,12 @@
     },
 
     /**
-     * Called whenever the increment/decrement buttons are clicked.
-     * @param {number} delta Must be 1 for an increment button click and -1 for
-     *     a decrement button click.
-     * @private
-     */
-    onButtonClicked_: function(delta) {
-      // Assumes text field has a valid number.
-      var newValue =
-          parseInt(this.getChildElement('input.copies').value, 10) + delta;
-      this.copiesTicketItem_.updateValue(newValue + '');
-    },
-
-    /**
      * Called after a timeout after user input into the textfield.
      * @private
      */
     onTextfieldTimeout_: function() {
       this.textfieldTimeout_ = null;
-      var copiesVal = this.getChildElement('input.copies').value;
+      var copiesVal = this.inputField_.value;
       if (copiesVal != '') {
         this.copiesTicketItem_.updateValue(copiesVal);
       }
@@ -188,12 +161,12 @@
      * @private
      */
     onTextfieldKeyDown_: function(event) {
-      if (event.keyCode == 13 /*enter*/) {
-        if (this.textfieldTimeout_) {
-          clearTimeout(this.textfieldTimeout_);
-        }
-        this.onTextfieldTimeout_();
-      }
+      if (event.keyCode != 'Enter')
+        return;
+
+      if (this.textfieldTimeout_)
+        clearTimeout(this.textfieldTimeout_);
+      this.onTextfieldTimeout_();
     },
 
     /**
@@ -206,7 +179,8 @@
         clearTimeout(this.textfieldTimeout_);
       }
       this.textfieldTimeout_ = setTimeout(
-          this.onTextfieldTimeout_.bind(this), CopiesSettings.TEXTFIELD_DELAY_);
+          this.onTextfieldTimeout_.bind(this),
+          CopiesSettings.TEXTFIELD_DELAY_MS_);
     },
 
     /**
@@ -215,7 +189,7 @@
      * @private
      */
     onTextfieldBlur_: function() {
-      if (this.getChildElement('input.copies').value == '') {
+      if (this.inputField_.value == '') {
         // Do it asynchronously to avoid moving focus to Print button in
         // PrintHeader.onTicketChange_.
         setTimeout((function() {
diff --git a/chrome/browser/resources/print_preview/settings/settings_box.css b/chrome/browser/resources/print_preview/settings/settings_box.css
new file mode 100644
index 0000000..cf48b061
--- /dev/null
+++ b/chrome/browser/resources/print_preview/settings/settings_box.css
@@ -0,0 +1,8 @@
+/* Copyright (c) 2016 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+.settings-box input.user-value.invalid {
+  background: rgb(255, 240, 240);
+  color: rgb(140, 20, 20);
+}
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html
index adfd8074..59bec7f 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.html
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -14,7 +14,6 @@
     </div>
     <paper-checkbox class="settings-box continuation"
         id="timeZoneDetectionCheckbox"
-        hidden="[[hideTimeZoneDetection_]]"
         on-change="onTimeZoneDetectionCheckboxChange_">
       $i18n{timeZoneGeolocation}
     </paper-checkbox>
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chrome/browser/resources/settings/date_time_page/date_time_page.js
index 75ad8eb..0b774990 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.js
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.js
@@ -74,20 +74,6 @@
             null;
       },
     },
-
-    /**
-     * Hides the time zone auto-detection feature when the
-     * --disable-timezone-tracking-option flag is set.
-     * @private
-     */
-    hideTimeZoneDetection_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.valueExists('hideTimeZoneDetection') &&
-               loadTimeData.getBoolean('hideTimeZoneDetection');
-      },
-      readOnly: true,
-    },
   },
 
   observers: [
@@ -112,10 +98,6 @@
                                    systemTimeZoneManaged,
                                    systemTimeZoneDetectionManaged,
                                    systemTimeZoneDetectionPolicyValue) {
-    // Do nothing if the feature is disabled by a flag.
-    if (this.hideTimeZoneDetection_)
-      return;
-
     var checkbox = this.$.timeZoneDetectionCheckbox;
 
     // Time zone auto-detection is disabled when the time zone is managed.
diff --git a/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp b/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
index 0c54600..34f3298 100644
--- a/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp
@@ -120,10 +120,12 @@
       'target_name': 'site_list',
       'dependencies': [
         '../compiled_resources2.gyp:route',
+        '../compiled_resources2.gyp:settings_action_menu',
+        'constants',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
         '<(EXTERNS_GYP):settings_private',
-        'constants',
         'site_settings_behavior',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index d4da811..4772d79 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -1,12 +1,12 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="/i18n_setup.html">
 <link rel="import" href="/icons.html">
 <link rel="import" href="/route.html">
+<link rel="import" href="/settings_action_menu.html">
 <link rel="import" href="/settings_shared_css.html">
 <link rel="import" href="/site_settings/add_site_dialog.html">
 <link rel="import" href="/site_settings/constants.html">
@@ -37,6 +37,26 @@
         </paper-button>
       </div>
 
+      <dialog is="settings-action-menu">
+        <button class="dropdown-item" role="option" id="allow"
+            on-tap="onAllowTap_" hidden$="[[!showAllowAction_]]">
+          $i18n{siteSettingsActionAllow}
+        </button>
+        <button class="dropdown-item" role="option" id="block"
+            on-tap="onBlockTap_" hidden$="[[!showBlockAction_]]">
+          $i18n{siteSettingsActionBlock}
+        </button>
+        <button class="dropdown-item" role="option" id="sessionOnly"
+            on-tap="onSessionOnlyTap_"
+            hidden$="[[!showSessionOnlyActionForSite_(actionMenuSite_)]]">
+          $i18n{siteSettingsActionSessionOnly}
+        </button>
+        <button class="dropdown-item" role="option" id="reset"
+            on-tap="onResetTap_">
+          $i18n{siteSettingsActionReset}
+        </button>
+      </dialog>
+
       <div class="list-frame menu-content vertical-list" id="listContainer">
         <template is="dom-repeat" items="[[sites]]">
           <div class="list-item">
@@ -58,34 +78,10 @@
               <iron-icon icon="[[computeIconControlledBy_(item)]]"></iron-icon>
             </template>
 
-            <paper-icon-button id="dots" icon="cr:more-vert" toggles
-                  active="{{item.menuOpened}}"
-                  hidden="[[isExceptionControlled_(item.source)]]">
+            <paper-icon-button id="dots" icon="cr:more-vert"
+                hidden="[[isExceptionControlled_(item.source)]]"
+                on-tap="onShowActionMenuTap_">
             </paper-icon-button>
-            <template is="dom-if" if="[[item.menuOpened]]">
-              <iron-dropdown vertical-align="auto" horizontal-align="right"
-                  opened="{{item.menuOpened}}">
-                <div class="dropdown-content">
-                  <button class="dropdown-item" role="option" id="allow"
-                      on-tap="onAllowTap_" hidden$="[[!showAllowAction_]]">
-                    $i18n{siteSettingsActionAllow}
-                  </button>
-                  <button class="dropdown-item" role="option" id="block"
-                      on-tap="onBlockTap_" hidden$="[[!showBlockAction_]]">
-                    $i18n{siteSettingsActionBlock}
-                  </button>
-                  <button class="dropdown-item" role="option" id="sessionOnly"
-                      on-tap="onSessionOnlyTap_"
-                      hidden$="[[!showSessionOnlyActionForSite_(item)]]">
-                    $i18n{siteSettingsActionSessionOnly}
-                  </button>
-                  <button class="dropdown-item" role="option" id="reset"
-                      on-tap="onResetTap_">
-                    $i18n{siteSettingsActionReset}
-                  </button>
-                </div>
-              </iron-dropdown>
-            </template>
             <template is="dom-if" if="[[enableSiteSettings_]]">
               <div on-tap="onOriginTap_" actionable>
                 <button class="subpage-arrow" is="paper-icon-button-light">
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js
index d7d0a698..dd82a11c 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -44,6 +44,12 @@
     },
 
     /**
+     * The site serving as the model for the currenly open action menu.
+     * @private {?SiteException}
+     */
+    actionMenuSite_: Object,
+
+    /**
      * Array of sites to display in the widget.
      * @type {!Array<SiteException>}
      */
@@ -363,15 +369,15 @@
   },
 
   /**
-   * Whether to show the Session Only menu item for a given site.
-   * @param {SiteException} site The site in question.
-   * @return {boolean} Whether to show the menu item.
+   * @return {boolean} Whether to show the "Session Only" menu item for the
+   *     currently active site.
+   * @private
    */
-  showSessionOnlyActionForSite_: function(site) {
+  showSessionOnlyActionForSite_: function() {
     // It makes no sense to show "clear on exit" for exceptions that only apply
     // to incognito. It gives the impression that they might under some
     // circumstances not be cleared on exit, which isn't true.
-    if (site.incognito)
+    if (!this.actionMenuSite_ || this.actionMenuSite_.incognito)
       return false;
 
     return this.showSessionOnlyAction_;
@@ -379,6 +385,7 @@
 
   /**
    * A handler for selecting a site (by clicking on the origin).
+   * @param {!{model: !{item: !SiteException}}} event
    * @private
    */
   onOriginTap_: function(event) {
@@ -391,15 +398,14 @@
 
   /**
    * A handler for activating one of the menu action items.
-   * @param {!{model: !{item: !{origin: string}}}} event
    * @param {string} action The permission to set (Allow, Block, SessionOnly,
    *     etc).
    * @private
    */
-  onActionMenuActivate_: function(event, action) {
-    var origin = event.model.item.origin;
-    var incognito = event.model.item.incognito;
-    var embeddingOrigin = event.model.item.embeddingOrigin;
+  onActionMenuActivate_: function(action) {
+    var origin = this.actionMenuSite_.origin;
+    var incognito = this.actionMenuSite_.incognito;
+    var embeddingOrigin = this.actionMenuSite_.embeddingOrigin;
     if (action == settings.PermissionValues.DEFAULT) {
       this.browserProxy.resetCategoryPermissionForOrigin(
           origin, embeddingOrigin, this.category, incognito);
@@ -410,23 +416,27 @@
   },
 
   /** @private */
-  onAllowTap_: function(event) {
-    this.onActionMenuActivate_(event, settings.PermissionValues.ALLOW);
+  onAllowTap_: function() {
+    this.onActionMenuActivate_(settings.PermissionValues.ALLOW);
+    this.closeActionMenu_();
   },
 
   /** @private */
-  onBlockTap_: function(event) {
-    this.onActionMenuActivate_(event, settings.PermissionValues.BLOCK);
+  onBlockTap_: function() {
+    this.onActionMenuActivate_(settings.PermissionValues.BLOCK);
+    this.closeActionMenu_();
   },
 
   /** @private */
-  onSessionOnlyTap_: function(event) {
-    this.onActionMenuActivate_(event, settings.PermissionValues.SESSION_ONLY);
+  onSessionOnlyTap_: function() {
+    this.onActionMenuActivate_(settings.PermissionValues.SESSION_ONLY);
+    this.closeActionMenu_();
   },
 
   /** @private */
-  onResetTap_: function(event) {
-    this.onActionMenuActivate_(event, settings.PermissionValues.DEFAULT);
+  onResetTap_: function() {
+    this.onActionMenuActivate_(settings.PermissionValues.DEFAULT);
+    this.closeActionMenu_();
   },
 
   /**
@@ -482,4 +492,23 @@
 
     return toggleState;
   },
+
+  /**
+   * @param {!{model: !{item: !SiteException}}} e
+   * @private
+   */
+  onShowActionMenuTap_: function(e) {
+    this.actionMenuSite_ = e.model.item;
+    /** @type {!SettingsActionMenuElement} */ (
+        this.$$('dialog[is=settings-action-menu]')).showAt(
+            /** @type {!Element} */ (
+                Polymer.dom(/** @type {!Event} */ (e)).localTarget));
+  },
+
+  /** @private */
+  closeActionMenu_: function() {
+    this.actionMenuSite_ = null;
+    /** @type {!SettingsActionMenuElement} */ (
+        this.$$('dialog[is=settings-action-menu]')).close();
+  },
 });
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc
index 8f53be1..08bff13 100644
--- a/chrome/browser/safe_browsing/ui_manager.cc
+++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -249,7 +249,8 @@
   }
 
   if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
-    FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingHit(resource));
+    for (Observer& observer : observer_list_)
+      observer.OnSafeBrowsingHit(resource);
   }
   AddToWhitelistUrlSet(resource, true /* A decision is now pending */);
   SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 62cb5fe..6fae8855 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -199,8 +199,8 @@
   if (!theme_info_) {
     OnThemeChanged();
   } else {
-    FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
-                      ThemeInfoChanged(*theme_info_));
+    for (InstantServiceObserver& observer : observers_)
+      observer.ThemeInfoChanged(*theme_info_);
   }
 #endif  // defined(ENABLE_THEMES)
 }
@@ -280,8 +280,8 @@
 }
 
 void InstantService::NotifyAboutMostVisitedItems() {
-  FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
-                    MostVisitedItemsChanged(most_visited_items_));
+  for (InstantServiceObserver& observer : observers_)
+    observer.MostVisitedItemsChanged(most_visited_items_);
 }
 
 #if defined(ENABLE_THEMES)
@@ -400,8 +400,8 @@
         theme_provider.HasCustomImage(IDR_THEME_NTP_ATTRIBUTION);
   }
 
-  FOR_EACH_OBSERVER(InstantServiceObserver, observers_,
-                    ThemeInfoChanged(*theme_info_));
+  for (InstantServiceObserver& observer : observers_)
+    observer.ThemeInfoChanged(*theme_info_);
 }
 #endif  // defined(ENABLE_THEMES)
 
@@ -432,9 +432,8 @@
 
   if (default_search_provider_changed || google_base_url_domain_changed) {
     ResetInstantSearchPrerenderer();
-    FOR_EACH_OBSERVER(
-        InstantServiceObserver, observers_,
-        DefaultSearchProviderChanged(google_base_url_domain_changed));
+    for (InstantServiceObserver& observer : observers_)
+      observer.DefaultSearchProviderChanged(google_base_url_domain_changed);
   }
 }
 
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index efd6e379..8daee119 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -1465,8 +1465,9 @@
   new_browser->tab_strip_model()->ActivateTabAt(1, true);
 }
 
-// PRE_CorrectLoadingOrder is flaky on ChromeOS MSAN. https://crbug.com/582323.
-#if defined (OS_CHROMEOS) && defined(MEMORY_SANITIZER)
+// PRE_CorrectLoadingOrder is flaky on ChromeOS MSAN: https://crbug.com/582323
+// And Mac: https://crbug.com/656687
+#if (defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)) || defined(OS_MACOSX)
 #define MAYBE_CorrectLoadingOrder DISABLED_CorrectLoadingOrder
 #else
 #define MAYBE_CorrectLoadingOrder CorrectLoadingOrder
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
index 63d4b30..ed77bc7 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -425,7 +425,8 @@
   Apply(dictionary_change);
   Sync(dictionary_change);
   is_loaded_ = true;
-  FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryLoaded());
+  for (Observer& observer : observers_)
+    observer.OnCustomDictionaryLoaded();
   if (!result->is_valid_file) {
     // Save cleaned up data only after startup.
     fix_invalid_file_.Reset(
@@ -522,7 +523,6 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!IsLoaded() || dictionary_change.empty())
     return;
-  FOR_EACH_OBSERVER(Observer,
-                    observers_,
-                    OnCustomDictionaryChanged(dictionary_change));
+  for (Observer& observer : observers_)
+    observer.OnCustomDictionaryChanged(dictionary_change);
 }
diff --git a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
index bd49e1f..1b219b8 100644
--- a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
@@ -247,8 +247,8 @@
   DCHECK(request_context_getter_);
 
   download_status_ = DOWNLOAD_IN_PROGRESS;
-  FOR_EACH_OBSERVER(Observer, observers_,
-                    OnHunspellDictionaryDownloadBegin(language_));
+  for (Observer& observer : observers_)
+    observer.OnHunspellDictionaryDownloadBegin(language_);
 
   fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this);
   data_use_measurement::DataUseUserData::AttachToFetcher(
@@ -360,9 +360,8 @@
 
   if (dictionary_saved) {
     download_status_ = DOWNLOAD_NONE;
-    FOR_EACH_OBSERVER(Observer,
-                      observers_,
-                      OnHunspellDictionaryDownloadSuccess(language_));
+    for (Observer& observer : observers_)
+      observer.OnHunspellDictionaryDownloadSuccess(language_);
     Load();
   } else {
     InformListenersOfDownloadFailure();
@@ -371,13 +370,12 @@
 }
 
 void SpellcheckHunspellDictionary::InformListenersOfInitialization() {
-  FOR_EACH_OBSERVER(Observer, observers_,
-                    OnHunspellDictionaryInitialized(language_));
+  for (Observer& observer : observers_)
+    observer.OnHunspellDictionaryInitialized(language_);
 }
 
 void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() {
   download_status_ = DOWNLOAD_FAILED;
-  FOR_EACH_OBSERVER(Observer,
-                    observers_,
-                    OnHunspellDictionaryDownloadFailure(language_));
+  for (Observer& observer : observers_)
+    observer.OnHunspellDictionaryDownloadFailure(language_);
 }
diff --git a/chrome/browser/task_manager/task_manager_interface.cc b/chrome/browser/task_manager/task_manager_interface.cc
index 9cdecf1e..c4a32857 100644
--- a/chrome/browser/task_manager/task_manager_interface.cc
+++ b/chrome/browser/task_manager/task_manager_interface.cc
@@ -115,29 +115,30 @@
 }
 
 void TaskManagerInterface::NotifyObserversOnTaskAdded(TaskId id) {
-  FOR_EACH_OBSERVER(TaskManagerObserver, observers_, OnTaskAdded(id));
+  for (TaskManagerObserver& observer : observers_)
+    observer.OnTaskAdded(id);
 }
 
 void TaskManagerInterface::NotifyObserversOnTaskToBeRemoved(TaskId id) {
-  FOR_EACH_OBSERVER(TaskManagerObserver, observers_, OnTaskToBeRemoved(id));
+  for (TaskManagerObserver& observer : observers_)
+    observer.OnTaskToBeRemoved(id);
 }
 
 void TaskManagerInterface::NotifyObserversOnRefresh(
     const TaskIdList& task_ids) {
-  FOR_EACH_OBSERVER(TaskManagerObserver,
-                    observers_,
-                    OnTasksRefreshed(task_ids));
+  for (TaskManagerObserver& observer : observers_)
+    observer.OnTasksRefreshed(task_ids);
 }
 
 void TaskManagerInterface::NotifyObserversOnRefreshWithBackgroundCalculations(
       const TaskIdList& task_ids) {
-  FOR_EACH_OBSERVER(TaskManagerObserver,
-                    observers_,
-                    OnTasksRefreshedWithBackgroundCalculations(task_ids));
+  for (TaskManagerObserver& observer : observers_)
+    observer.OnTasksRefreshedWithBackgroundCalculations(task_ids);
 }
 
 void TaskManagerInterface::NotifyObserversOnTaskUnresponsive(TaskId id) {
-  FOR_EACH_OBSERVER(TaskManagerObserver, observers_, OnTaskUnresponsive(id));
+  for (TaskManagerObserver& observer : observers_)
+    observer.OnTaskUnresponsive(id);
 }
 
 base::TimeDelta TaskManagerInterface::GetCurrentRefreshTime() const {
diff --git a/chrome/browser/ui/android/usb_chooser_dialog_android.cc b/chrome/browser/ui/android/usb_chooser_dialog_android.cc
index e6e15359..19bba9c 100644
--- a/chrome/browser/ui/android/usb_chooser_dialog_android.cc
+++ b/chrome/browser/ui/android/usb_chooser_dialog_android.cc
@@ -211,10 +211,7 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jstring> device_guid =
       base::android::ConvertUTF8ToJavaString(env, device->guid());
-  base::android::ScopedJavaLocalRef<jstring> device_name =
-      base::android::ConvertUTF16ToJavaString(env, device->product_string());
-  Java_UsbChooserDialog_removeDevice(env, java_dialog_, device_guid,
-                                     device_name);
+  Java_UsbChooserDialog_removeDevice(env, java_dialog_, device_guid);
 }
 
 void UsbChooserDialogAndroid::OpenUrl(const std::string& url) {
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc
index 18f8127a..412ba6b 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -15,7 +15,6 @@
 #include "content/public/browser/navigation_handle.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/animation/ink_drop_host_view.h"
 #include "ui/views/border.h"
@@ -99,13 +98,7 @@
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
   IntentPickerBubbleView* delegate =
       new IntentPickerBubbleView(app_info, intent_picker_cb, web_contents);
-  // TODO(djacobo): Remove the left and right insets when
-  // http://crbug.com/656662 gets fixed.
-  // Add a 1-pixel extra boundary left and right when using secondary UI.
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-    delegate->set_margins(gfx::Insets(16, 1, 0, 1));
-  else
-    delegate->set_margins(gfx::Insets(16, 0, 0, 0));
+  delegate->set_margins(gfx::Insets(16, 0, 0, 0));
   delegate->set_parent_window(browser_view->GetNativeWindow());
   views::Widget* widget =
       views::BubbleDialogDelegateView::CreateBubble(delegate);
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 212aaba..277d5d3 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -719,12 +719,8 @@
       "showWakeOnWifi",
       chromeos::WakeOnWifiManager::Get()->WakeOnWifiSupported() &&
       chromeos::switches::WakeOnWifiEnabled());
-  const bool have_disable_time_zone_tracking_option_switch =
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kDisableTimeZoneTrackingOption);
   values->SetBoolean("enableTimeZoneTrackingOption",
-                     !have_disable_time_zone_tracking_option_switch &&
-                         !chromeos::system::HasSystemTimezonePolicy());
+                     !chromeos::system::HasSystemTimezonePolicy());
   values->SetBoolean("resolveTimezoneByGeolocationInitialValue",
                      Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
                          prefs::kResolveTimezoneByGeolocation));
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 234e499..9a281df 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -260,10 +260,6 @@
                              IDS_PRINT_PREVIEW_PAGE_RANGE_SYNTAX_INSTRUCTION);
   source->AddLocalizedString("copiesInstruction",
                              IDS_PRINT_PREVIEW_COPIES_INSTRUCTION);
-  source->AddLocalizedString("incrementTitle",
-                             IDS_PRINT_PREVIEW_INCREMENT_TITLE);
-  source->AddLocalizedString("decrementTitle",
-                             IDS_PRINT_PREVIEW_DECREMENT_TITLE);
   source->AddLocalizedString("printPagesLabel",
                              IDS_PRINT_PREVIEW_PRINT_PAGES_LABEL);
   source->AddLocalizedString("optionsLabel", IDS_PRINT_PREVIEW_OPTIONS_LABEL);
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
index 0e72575..0965633 100644
--- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
@@ -60,11 +60,6 @@
         GetSystemTimezoneAutomaticDetectionPolicyValue());
   }
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kDisableTimeZoneTrackingOption)) {
-    html_source->AddBoolean("hideTimeZoneDetection", true);
-  }
-
   return new DateTimeHandler;
 }
 
diff --git a/chrome/browser/win/enumerate_modules_model.cc b/chrome/browser/win/enumerate_modules_model.cc
index 7d301ca..f2a0c29 100644
--- a/chrome/browser/win/enumerate_modules_model.cc
+++ b/chrome/browser/win/enumerate_modules_model.cc
@@ -787,7 +787,8 @@
 
   if (!conflict_notification_acknowledged_) {
     conflict_notification_acknowledged_ = true;
-    FOR_EACH_OBSERVER(Observer, observers_, OnConflictsAcknowledged());
+    for (Observer& observer : observers_)
+      observer.OnConflictsAcknowledged();
   }
 }
 
@@ -844,7 +845,8 @@
   // observers that the scan is complete. At this point |enumerated_modules_| is
   // safe to access as no potentially racing blocking pool task can exist.
   if (!enumerated_modules_.empty()) {
-    FOR_EACH_OBSERVER(Observer, observers_, OnScanCompleted());
+    for (Observer& observer : observers_)
+      observer.OnScanCompleted();
     return;
   }
 
@@ -988,5 +990,6 @@
                            confirmed_bad_modules_detected_);
 
   // Forward the callback to any registered observers.
-  FOR_EACH_OBSERVER(Observer, observers_, OnScanCompleted());
+  for (Observer& observer : observers_)
+    observer.OnScanCompleted();
 }
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 7d45ac0..345c5c5 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -194,7 +194,7 @@
     "//components/nacl/common:switches",
     "//components/offline_pages:switches",
     "//components/omnibox/common",
-    "//components/password_manager/content/public/interfaces",
+    "//components/password_manager/content/common:mojo_interfaces",
     "//components/password_manager/core/common",
     "//components/policy:generated",
     "//components/policy/core/common",
diff --git a/chrome/test/data/android/payments/contact_details.js b/chrome/test/data/android/payments/contact_details.js
index 36e3fb8..32cac65 100644
--- a/chrome/test/data/android/payments/contact_details.js
+++ b/chrome/test/data/android/payments/contact_details.js
@@ -14,14 +14,15 @@
     new PaymentRequest(
         [{supportedMethods: ['visa']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}},
-        {requestPayerEmail: true, requestPayerPhone: true})
+        {requestPayerName: true, requestPayerEmail: true,
+         requestPayerPhone: true})
         .show()
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
                 print(
-                    resp.payerEmail + '<br>' + resp.payerPhone + '<br>' +
-                    resp.methodName + '<br>' +
+                    resp.payerName + '<br>' + resp.payerEmail + '<br>' +
+                    resp.payerPhone + '<br>' + resp.methodName + '<br>' +
                     JSON.stringify(resp.details, undefined, 2));
               })
               .catch(function(error) {
diff --git a/chrome/test/data/android/payments/contact_details_and_free_shipping.js b/chrome/test/data/android/payments/contact_details_and_free_shipping.js
index c5fc1be..ea336fc 100644
--- a/chrome/test/data/android/payments/contact_details_and_free_shipping.js
+++ b/chrome/test/data/android/payments/contact_details_and_free_shipping.js
@@ -23,15 +23,15 @@
             selected: true
           }]
         },
-        {requestPayerEmail: true, requestPayerPhone: true,
-         requestShipping: true});
+        {requestPayerName: true, requestPayerEmail: true,
+         requestPayerPhone: true, requestShipping: true});
     request.show()
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
                 print(
-                    resp.payerEmail + '<br>' + resp.payerPhone + '<br>' +
-                    resp.shippingOption + '<br>' +
+                    resp.payerName + '<br>' + resp.payerEmail + '<br>' +
+                    resp.payerPhone + '<br>' + resp.shippingOption + '<br>' +
                     JSON.stringify(
                         toDictionary(resp.shippingAddress), undefined, 2) +
                     '<br>' + resp.methodName + '<br>' +
diff --git a/chrome/test/data/android/payments/name.js b/chrome/test/data/android/payments/name.js
new file mode 100644
index 0000000..0e3265b
--- /dev/null
+++ b/chrome/test/data/android/payments/name.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* global PaymentRequest:false */
+
+/*
+ * Launches the PaymentRequest UI that requests payer name.
+ */
+function buy() {  // eslint-disable-line no-unused-vars
+  try {
+    new PaymentRequest(
+        [{supportedMethods: ['visa']}],
+        {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}},
+        {requestPayerName: true})
+        .show()
+        .then(function(resp) {
+          resp.complete('success')
+              .then(function() {
+                print(
+                    resp.payerName + '<br>' + resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
+              })
+              .catch(function(error) {
+                print(error);
+              });
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
diff --git a/chrome/test/data/android/payments/name_and_free_shipping.js b/chrome/test/data/android/payments/name_and_free_shipping.js
new file mode 100644
index 0000000..1f3823d
--- /dev/null
+++ b/chrome/test/data/android/payments/name_and_free_shipping.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* global PaymentRequest:false */
+/* global toDictionary:false */
+
+/**
+ * Launches the PaymentRequest UI that request a payer name and offers free
+ * shipping worldwide.
+ */
+function buy() {  // eslint-disable-line no-unused-vars
+  try {
+    var request = new PaymentRequest(
+        [{supportedMethods: ['visa']}], {
+          total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
+          shippingOptions: [{
+            id: 'freeShippingOption',
+            label: 'Free global shipping',
+            amount: {currency: 'USD', value: '0'},
+            selected: true
+          }]
+        },
+        {requestPayerName: true, requestShipping: true});
+    request.show()
+        .then(function(resp) {
+          resp.complete('success')
+              .then(function() {
+                print(
+                    resp.payerName + '<br>' + resp.shippingOption + '<br>' +
+                    JSON.stringify(
+                        toDictionary(resp.shippingAddress), undefined, 2) +
+                    '<br>' + resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
+              })
+              .catch(function(error) {
+                print(error);
+              });
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
diff --git a/chrome/test/data/android/payments/payment_request_name_and_free_shipping_test.html b/chrome/test/data/android/payments/payment_request_name_and_free_shipping_test.html
new file mode 100644
index 0000000..70b9841c
--- /dev/null
+++ b/chrome/test/data/android/payments/payment_request_name_and_free_shipping_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<html>
+<head>
+<title>Name and Free Shipping Test</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+<button onclick="buy()" id="buy">Name and Free Shipping Test</button><br>
+<pre id="result"></pre>
+<script src="util.js"></script>
+<script src="name_and_free_shipping.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/android/payments/payment_request_name_test.html b/chrome/test/data/android/payments/payment_request_name_test.html
new file mode 100644
index 0000000..3e47ec1f
--- /dev/null
+++ b/chrome/test/data/android/payments/payment_request_name_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<!--
+Copyright 2016 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<html>
+<head>
+<title>Name Test</title>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+<link rel="stylesheet" type="text/css" href="style.css">
+</head>
+<body>
+<button onclick="buy()" id="buy">Name Test</button>
+<pre id="result"></pre>
+<script src="util.js"></script>
+<script src="name.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js
index 4f0d98e..a686ded9 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js
@@ -9,6 +9,7 @@
 var main;
 var p2;
 var p3;
+var anonGroup;
 var okButton;
 var cancelButton;
 
@@ -35,13 +36,16 @@
   p3 = main.lastChild;
   assertEq(RoleType.paragraph, p3.role);
 
-  okButton = rootNode.children[2];
+  anonGroup = rootNode.lastChild;
+  assertEq(RoleType.group, anonGroup.role);
+
+  okButton = anonGroup.firstChild;
   assertEq(RoleType.button, okButton.role);
   assertEq('Ok', okButton.name);
   assertTrue(StateType.disabled in okButton.state);
   assertTrue(okButton.state.disabled);
 
-  cancelButton = rootNode.children[3];
+  cancelButton = anonGroup.lastChild;
   assertEq(RoleType.button, cancelButton.role);
   assertEq('Cancel', cancelButton.name);
   assertFalse(StateType.disabled in cancelButton.state);
@@ -73,6 +77,13 @@
     assertEq(p2, main.find({ role: RoleType.paragraph }));
     assertEq([p2, p3], main.findAll({ role: RoleType.paragraph }));
 
+    // Unlike querySelector, can search from an anonymous group without
+    // unexpected results.
+    assertEq(okButton, anonGroup.find({ role: RoleType.button }));
+    assertEq([okButton, cancelButton],
+             anonGroup.findAll({ role: RoleType.button }));
+    assertEq(null, anonGroup.find({ role: RoleType.heading }));
+
     chrome.test.succeed();
   },
 
@@ -90,6 +101,12 @@
     assertEq([okButton], rootNode.findAll({ role: RoleType.button,
                                             state: { disabled: true }}));
 
+    // Find disabled buttons within a portion of the tree.
+    assertEq(okButton, anonGroup.find({ role: RoleType.button,
+                                       state: { disabled: true }}));
+    assertEq([okButton], anonGroup.findAll({ role: RoleType.button,
+                                            state: { disabled: true }}));
+
     // Find enabled buttons.
     assertEq(cancelButton, rootNode.find({ role: RoleType.button,
                                            state: { disabled: false }}));
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
index a4e48a5..0c583fa 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
@@ -5,8 +5,7 @@
 var allTests = [
   function testLocation() {
     function assertOkButtonLocation(event) {
-      var okButton = rootNode.find({ role: RoleType.button,
-                                     attributes: { name: 'Ok' }});
+      var okButton = rootNode.firstChild.firstChild;
       assertTrue('location' in okButton);
 
       // We can't assert the left and top positions because they're
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/queryselector.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/queryselector.js
index 2794068..65489e3 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/queryselector.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/queryselector.js
@@ -5,7 +5,7 @@
 var allTests = [
   // Basic query from root node.
   function testQuerySelector() {
-    var cancelButton = rootNode.children[3];
+    var cancelButton = rootNode.lastChild.lastChild;
     function assertCorrectResult(queryResult) {
       assertEq(queryResult, cancelButton);
       chrome.test.succeed();
@@ -39,7 +39,7 @@
   // Demonstrates that a query for an element which is ignored for accessibility
   // returns its nearest ancestor.
   function testQuerySelectorForSpanInsideButtonReturnsButton() {
-    var okButton = rootNode.children[2];
+    var okButton = rootNode.lastChild.firstChild;
     function assertCorrectResult(queryResult) {
       assertEq(queryResult, okButton);
       chrome.test.succeed();
@@ -47,6 +47,18 @@
     rootNode.domQuerySelector('#span-in-button', assertCorrectResult);
   },
 
+  // Demonstrates that querying from an anonymous node may have unexpected
+  // results.
+  function testQuerySelectorFromAnonymousGroup() {
+    var h1 = rootNode.firstChild.firstChild;
+    var group = rootNode.lastChild;
+    function assertCorrectResult(queryResult) {
+      assertEq(h1, queryResult);
+      chrome.test.succeed();
+    }
+    group.domQuerySelector('h1', assertCorrectResult);
+  },
+
   function testQuerySelectorFromRemovedNode() {
     var group = rootNode.firstChild;
     function assertCorrectResult(queryResult) {
diff --git a/chrome/test/data/webui/media_router/media_router_elements_browsertest.js b/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
index 38d7453..6be1d6e 100644
--- a/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
+++ b/chrome/test/data/webui/media_router/media_router_elements_browsertest.js
@@ -116,7 +116,7 @@
 });
 
 TEST_F('MediaRouterElementsBrowserTest',
-    'MediaRouterContainerFilter',
+    'DISABLED_MediaRouterContainerFilter',
     function() {
   media_router_container_filter.registerTests();
   mocha.run();
diff --git a/chrome/test/data/webui/print_preview.js b/chrome/test/data/webui/print_preview.js
index bf411ed8..286a6f8 100644
--- a/chrome/test/data/webui/print_preview.js
+++ b/chrome/test/data/webui/print_preview.js
@@ -573,7 +573,7 @@
   checkSectionVisible($('copies-settings'), true);
   expectEquals(
       printPresetOptions.copies,
-      parseInt($('copies-settings').querySelector('.copies').value));
+      parseInt($('copies-settings').querySelector('.user-value').value));
 
   this.waitForAnimationToEnd('other-options-collapsible');
 });
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js
index 13e6d8f3..62fa0528 100644
--- a/chrome/test/data/webui/settings/site_list_tests.js
+++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -319,15 +319,17 @@
         document.body.appendChild(testElement);
       });
 
+      teardown(function() {
+        closeActionMenu();
+      });
+
       /**
-       * Fetch the non-hidden menu items from the list.
-       * @param {!HTMLElement} parentElement
-       * @param {number} index The index of the child element (which site) to
-       *     fetch.
+       * Fetch the non-hidden menu items from the action menu.
        */
-      function getMenuItems(listContainer, index) {
-        return listContainer.children[index].querySelectorAll(
-            'iron-dropdown .dropdown-item:not([hidden])');
+      function getMenuItems() {
+        var menu = testElement.$$('dialog[is=settings-action-menu]');
+        assertTrue(!!menu);
+        return menu.querySelectorAll('button:not([hidden])');
       }
 
       /**
@@ -342,14 +344,19 @@
         Polymer.dom.flush();
       }
 
+      /** Closes the action menu. */
+      function closeActionMenu() {
+        var menu = testElement.$$('dialog[is=settings-action-menu]');
+        if (menu.open)
+          menu.close();
+      }
+
       /**
        * Asserts the menu looks as expected.
        * @param {Array<string>} items The items expected to show in the menu.
-       * @param {!HTMLElement} parentElement The parent node to start looking
-       *     in.
        */
-      function assertMenu(items, parentElement) {
-        var menuItems = getMenuItems(parentElement.$.listContainer, 0);
+      function assertMenu(items) {
+        var menuItems = getMenuItems();
         assertEquals(items.length, menuItems.length);
         for (var i = 0; i < items.length; i++)
           assertEquals(items[i], menuItems[i].textContent.trim());
@@ -515,7 +522,7 @@
               assertMenu(['Allow', 'Clear on exit', 'Remove'], testElement);
 
               // Select 'Remove from menu'.
-              var menuItems = getMenuItems(testElement.$.listContainer, 0);
+              var menuItems = getMenuItems();
               assertTrue(!!menuItems);
               MockInteractions.tap(menuItems[2]);
               return browserProxy.whenCalled(
@@ -548,10 +555,11 @@
               openActionMenu(0);
               // 'Clear on exit' is hidden for incognito items.
               assertMenu(['Block', 'Remove'], testElement);
+              closeActionMenu();
 
               // Select 'Remove' from menu on 'foo.com'.
               openActionMenu(1);
-              var menuItems = getMenuItems(testElement.$.listContainer, 1);
+              var menuItems = getMenuItems();
               assertTrue(!!menuItems);
               MockInteractions.tap(menuItems[1]);
               return browserProxy.whenCalled(
@@ -776,7 +784,7 @@
             contentType) {
           Polymer.dom.flush();
           openActionMenu(0);
-          var menuItems = getMenuItems(testElement.$.listContainer, 0);
+          var menuItems = getMenuItems();
           assertTrue(!!menuItems);
           MockInteractions.tap(menuItems[0]);
           return browserProxy.whenCalled('setCategoryPermissionForOrigin');
@@ -792,7 +800,7 @@
           openActionMenu(0);
           assertMenu(['Allow', 'Remove'], testElement);
 
-          var menuItems = getMenuItems(testElement.$.listContainer, 0);
+          var menuItems = getMenuItems();
           assertTrue(!!menuItems);
           MockInteractions.tap(menuItems[0]);  // Action: Allow.
           return browserProxy.whenCalled('setCategoryPermissionForOrigin');
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index fedc4eb..718fe5c4 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-8916.0.0
\ No newline at end of file
+8917.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 11a8d53..564105c 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -200,10 +200,6 @@
 const char kDisableSystemTimezoneAutomaticDetectionPolicy[] =
     "disable-system-timezone-automatic-detection";
 
-// Disables automatic timezone update.
-const char kDisableTimeZoneTrackingOption[] =
-    "disable-timezone-tracking-option";
-
 // Disables volume adjust sound.
 const char kDisableVolumeAdjustSound[] = "disable-volume-adjust-sound";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 95e3d2c3..cf3d424 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -71,7 +71,6 @@
 CHROMEOS_EXPORT extern const char kDisableRollbackOption[];
 CHROMEOS_EXPORT extern const char
     kDisableSystemTimezoneAutomaticDetectionPolicy[];
-CHROMEOS_EXPORT extern const char kDisableTimeZoneTrackingOption[];
 CHROMEOS_EXPORT extern const char kDisableVolumeAdjustSound[];
 CHROMEOS_EXPORT extern const char kDisableWakeOnWifi[];
 CHROMEOS_EXPORT extern const char kEafePath[];
diff --git a/components/OWNERS b/components/OWNERS
index ea72779..de8e8fa6 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -4,246 +4,27 @@
 sdefresne@chromium.org
 
 # Note: Best not to use globs (like autofill*) due to crbug.com/397984
-
-per-file app_modal.gypi=file://components/app_modal/OWNERS
 per-file app_modal_strings.grdp=file://components/app_modal/OWNERS
-
-per-file arc.gypi=file://components/arc/OWNERS
-
-per-file autofill.gypi=file://components/autofill/OWNERS
 per-file autofill_strings.grdp=file://components/autofill/OWNERS
-
 per-file bookmark_bar_strings.grdp=file://components/bookmarks/OWNERS
-per-file bookmarks.gypi=file://components/bookmarks/OWNERS
-
-per-file browser_sync.gypi=file://components/browser_sync/OWNERS
-
 per-file browsing_data_strings.grdp=file://components/browsing_data/OWNERS
-per-file browsing_data.gypi=file://components/browsing_data/OWNERS
-
-per-file bubble.gypi=file://components/bubble/OWNERS
-
-per-file cast_certificate.gypi=file://components/cast_certificate/OWNERS
-
-per-file cdm.gypi=file://components/cdm/OWNERS
-
-per-file certificate_transparency.gypi=file://components/certificate_transparency/OWNERS
-
-per-file chrome_apps.gypi=file://components/chrome_apps/OWNERS
-
-per-file cloud_devices.gypi=file://components/cloud_devices/OWNERS
-
-per-file component_updater.gypi=file://components/component_updater/OWNERS
-
-per-file constrained_window.gypi=file://components/constrained_window/OWNERS
-
-per-file content_settings.gypi=file://components/content_settings/OWNERS
-
-per-file contextual_search.gypi=file://components/contextual_search/OWNERS
-
-per-file crash.gypi=file://components/crash/OWNERS
 per-file crash_strings.grdp=file://components/crash/OWNERS
-
-per-file data_reduction_proxy.gypi=file://components/data_reduction_proxy/OWNERS
-
-per-file data_usage.gypi=file://components/data_usage/OWNERS
-
-per-file data_use_measurement.gypi=file://components/data_use_measurement/OWNERS
-
-per-file device_event_log.gypi=file://components/device_event_log/OWNERS
-
-per-file display_compositor.gypi=file://components/display_compositor/OWNERS
-
-per-file dom_distiller.gypi=file://components/dom_distiller/OWNERS
 per-file dom_distiller_strings.grdp=file://components/dom_distiller/OWNERS
-
-per-file domain_reliability.gypi=file://components/domain_reliability/OWNERS
-
-per-file drive.gypi=file://components/drive/OWNERS
-
-per-file error_page.gypi=file://components/error_page/OWNERS
 per-file error_page_strings.grdp=file://components/error_page/OWNERS
-
-per-file exo.gypi=file://components/exo/OWNERS
-
-per-file favicon.gypi=file://components/favicon/OWNERS
-per-file favicon_base.gypi=file://components/favicon_base/OWNERS
-
-per-file feedback.gypi=file://components/feedback/OWNERS
-
-per-file gcm_driver.gypi=file://components/gcm_driver/OWNERS
-
-per-file google.gypi=file://components/google/OWNERS
-
-per-file guest_view.gypi=file://components/guest_view/OWNERS
-
-per-file handoff.gypi=file://components/handoff/OWNERS
-
-per-file history.gypi=file://components/history/OWNERS
-
-per-file image_fetcher.gypi=file://components/image_fetcher/OWNERS
-
-per-file infobars.gypi=file://components/infobars/OWNERS
-
-per-file invalidation.gypi=file://components/invalidation/OWNERS
-
-per-file json_schema.gypi=file://components/json_schema/OWNERS
-
-per-file keyed_service.gypi=file://components/keyed_service/OWNERS
-
-per-file leveldb_proto.gypi=file://components/leveldb_proto/OWNERS
-
-per-file login.gypi=file://components/login/OWNERS
-
-per-file memory_pressure.gypi=file://components/memory_pressure/OWNERS
-
-per-file metrics.gypi=file://components/metrics/OWNERS
-per-file metrics_services_manager.gypi=file://components/metrics_services_manager/OWNERS
-
-per-file nacl.gyp=file://components/nacl/OWNERS
 per-file nacl_helper_nonsfi_unittests.isolate=file://components/nacl/OWNERS
 per-file nacl_loader_unittests.isolate=file://components/nacl/OWNERS
-per-file nacl_nonsfi.gyp=file://components/nacl/OWNERS
-
-per-file navigation_interception.gypi=file://components/navigation_interception/OWNERS
-
-per-file network_hints.gypi=file://components/network_hints/OWNERS
-
-per-file network_session_configurator.gypi=file://components/network_session_configurator/OWNERS
-
-per-file network_time.gypi=file://components/network_time/OWNERS
-
-per-file ntp_snippets.gypi=file://components/ntp_snippets/OWNERS
 per-file ntp_snippets_strings.grdp=file://components/ntp_snippets/OWNERS
-
-per-file ntp_tiles.gypi=file://components/ntp_tiles/OWNERS
-
-per-file offline_pages.gypi=file://components/offline_pages/OWNERS
-
-per-file omnibox.gypi=file://components/omnibox/OWNERS
 per-file omnibox_strings.grdp=file://components/omnibox/OWNERS
-
-per-file onc.gypi=file://components/onc/OWNERS
-
-per-file open_from_clipboard.gypi=file://components/open_from_clipboard/OWNERS
-
-per-file os_crypt.gypi=file://components/os_crypt/OWNERS
-
-per-file ownership.gypi=file://components/ownership/OWNERS
-
-per-file packed_ct_ev_whitelist.gypi=file://components/packed_ct_ev_whitelist/OWNERS
-
-per-file pairing.gypi=file://components/pairing/OWNERS
-
-per-file password_manager.gypi=file://components/password_manager/OWNERS
 per-file password_manager_strings.grdp=file://components/password_manager/OWNERS
-
-per-file pdf.gypi=file://components/pdf/OWNERS
 per-file pdf_strings.grdp=raymes@chromium.org
 per-file pdf_strings.grdp=tsergeant@chromium.org
-
-per-file plugins.gypi=file://components/plugins/OWNERS
-
-per-file policy.gypi=file://components/policy/OWNERS
 per-file policy_strings.grdp=file://components/policy/OWNERS
-
-per-file precache.gypi=file://components/precache/OWNERS
-
-per-file previews.gypi=file://components/previews/OWNERS
-
-per-file printing.gypi=file://components/printing/OWNERS
-
-per-file profile_metrics.gypi=file://components/profile_metrics/OWNERS
-
-per-file proximity_auth.gypi=file://components/proximity_auth/OWNERS
-
-per-file proxy_config.gypi=file://components/proxy_config/OWNERS
-
-per-file query_parser.gypi=file://components/query_parser/OWNERS
-
-per-file quirks.gypi=file://components/quirks/OWNERS
-
-per-file rappor.gypi=file://components/rappor/OWNERS
-
-per-file renderer_context_menu.gypi=file://components/renderer_context_menu/OWNERS
-
-per-file safe_browsing_db.gypi=file://components/safe_browsing_db/OWNERS
-
-per-file safe_json.gypi=file://components/safe_json/OWNERS
-
-per-file search.gypi=file://components/search/OWNERS
-
-per-file search_engines.gypi=file://components/search_engines/OWNERS
-
-per-file search_provider_logos.gypi=file://components/search_provider_logos/OWNERS
-
-per-file security_interstitials.gypi=file://components/security_interstitials/OWNERS
 per-file security_interstitials_strings.grdp=file://components/security_interstitials/OWNERS
-
-per-file session_manager.gypi=file://components/session_manager/OWNERS
-
-per-file sessions.gypi=file://components/sessions/OWNERS
-
-per-file signin.gypi=file://components/signin/OWNERS
-
-per-file spellcheck.gypi=file://components/spellcheck/OWNERS
-
-per-file ssl_errors.gypi=file://components/ssl_errors/OWNERS
 per-file ssl_errors_strings.grdp=file://components/ssl_errors/OWNERS
-
-per-file startup_metric_utils.gypi=file://components/startup_metric_utils/OWNERS
-
-per-file storage_monitor.gypi=file://components/storage_monitor/OWNERS
-
-per-file subresource_filter.gypi=file://components/subresource_filter/OWNERS
-
-per-file suggestions.gypi=file://components/suggestions/OWNERS
-
-per-file supervised_user_error_page.gypi=file://components/supervised_user_error_page/OWNERS
 per-file supervised_user_error_page_strings.grdp=file://components/supervised_user_error_page/OWNERS
-
-per-file sync.gyp=file://components/sync/OWNERS
-
-per-file sync_sessions.gypi=file://components/sync_sessions/OWNERS
-
 per-file sync_ui_strings.grdp=file://components/sync/OWNERS
-
-per-file timers.gypi=file://components/timers/OWNERS
-
-per-file tracing.gyp=file://components/tracing/OWNERS
-per-file tracing_nacl.gyp=file://components/tracing/OWNERS
-
-per-file translate.gypi=file://components/translate/OWNERS
 per-file translate_strings.grdp=file://components/translate/OWNERS
-
-per-file undo.gypi=file://components/undo/OWNERS
 per-file undo_strings.grdp=file://components/undo/OWNERS
-
-per-file update_client.gypi=file://components/update_client/OWNERS
-
-per-file url_formatter.gypi=file://components/url_formatter/OWNERS
-
-per-file user_manager.gypi=file://components/user_manager/OWNERS
-
-per-file user_prefs.gypi=file://components/user_prefs/OWNERS
-
-per-file variations.gypi=file://components/variations/OWNERS
-
-per-file version_ui.gypi=file://components/version_ui/OWNERS
-
-per-file web_contents_delegate_android.gypi=file://components/web_contents_delegate_android/OWNERS
-
-per-file web_modal.gypi=file://components/web_modal/OWNERS
-
-per-file web_resource.gypi=file://components/web_resource/OWNERS
-
-per-file web_restrictions.gypi=file://components/web_restrictions/OWNERS
-
-per-file webdata.gypi=file://components/webdata/OWNERS
-per-file webdata_services.gypi=file://components/webdata_services/OWNERS
-
-per-file wifi.gypi=file://components/wifi/OWNERS
-
 per-file *.isolate=maruel@chromium.org
 per-file *.isolate=tandrii@chromium.org
 per-file *.isolate=vadimsh@chromium.org
@@ -251,4 +32,3 @@
 # These are for the common case of adding or removing tests. If you're making
 # structural changes, please get a review from one of the overall components
 # OWNERS.
-per-file components_tests.gyp=*
diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h
index 93f0767..6ab39fa1 100644
--- a/components/arc/arc_bridge_service.h
+++ b/components/arc/arc_bridge_service.h
@@ -103,11 +103,18 @@
   // HandleStartup() should be called upon profile startup.  This will only
   // launch an instance if the instance is enabled.
   // This can only be called on the thread that this class was created on.
-  virtual void HandleStartup() = 0;
 
-  // Shutdown() should be called when the browser is shutting down. This can
-  // only be called on the thread that this class was created on.
-  virtual void Shutdown() = 0;
+  // Starts the ARC service, then it will connect the Mojo channel. When the
+  // bridge becomes ready, OnBridgeReady() is called.
+  virtual void RequestStart() = 0;
+
+  // Stops the ARC service.
+  virtual void RequestStop() = 0;
+
+  // OnShutdown() should be called when the browser is shutting down. This can
+  // only be called on the thread that this class was created on. We assume that
+  // when this function is called, MessageLoop is no longer exists.
+  virtual void OnShutdown() = 0;
 
   // Adds or removes observers. This can only be called on the thread that this
   // class was created on. RemoveObserver does nothing if |observer| is not in
@@ -244,9 +251,10 @@
   friend class ArcBridgeTest;
   FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Basic);
   FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Prerequisites);
-  FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, ShutdownMidStartup);
+  FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, StopMidStartup);
   FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Restart);
   FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, OnBridgeStopped);
+  FRIEND_TEST_ALL_PREFIXES(ArcBridgeTest, Shutdown);
 
   base::ObserverList<Observer> observer_list_;
 
diff --git a/components/arc/arc_bridge_service_impl.cc b/components/arc/arc_bridge_service_impl.cc
index 968511b..d426b63 100644
--- a/components/arc/arc_bridge_service_impl.cc
+++ b/components/arc/arc_bridge_service_impl.cc
@@ -28,9 +28,10 @@
 constexpr int64_t kReconnectDelayInSeconds = 5;
 }  // namespace
 
-ArcBridgeServiceImpl::ArcBridgeServiceImpl()
+ArcBridgeServiceImpl::ArcBridgeServiceImpl(
+    const scoped_refptr<base::TaskRunner>& blocking_task_runner)
     : session_started_(false),
-      factory_(base::Bind(ArcSession::Create)),
+      factory_(base::Bind(ArcSession::Create, blocking_task_runner)),
       weak_factory_(this) {
   DCHECK(!g_arc_bridge_service);
   g_arc_bridge_service = this;
@@ -44,7 +45,7 @@
   g_arc_bridge_service = nullptr;
 }
 
-void ArcBridgeServiceImpl::HandleStartup() {
+void ArcBridgeServiceImpl::RequestStart() {
   DCHECK(CalledOnValidThread());
   if (session_started_)
     return;
@@ -53,7 +54,7 @@
   PrerequisitesChanged();
 }
 
-void ArcBridgeServiceImpl::Shutdown() {
+void ArcBridgeServiceImpl::RequestStop() {
   DCHECK(CalledOnValidThread());
   if (!session_started_)
     return;
@@ -62,13 +63,23 @@
   PrerequisitesChanged();
 }
 
+void ArcBridgeServiceImpl::OnShutdown() {
+  DCHECK(CalledOnValidThread());
+  VLOG(1) << "OnShutdown";
+  if (!session_started_)
+    return;
+  session_started_ = false;
+  reconnect_ = false;
+  if (arc_session_)
+    arc_session_->OnShutdown();
+}
+
 void ArcBridgeServiceImpl::SetArcSessionFactoryForTesting(
     const ArcSessionFactory& factory) {
   DCHECK(!factory.is_null());
   factory_ = factory;
 }
 
-
 void ArcBridgeServiceImpl::DisableReconnectDelayForTesting() {
   use_delay_before_reconnecting_ = false;
 }
diff --git a/components/arc/arc_bridge_service_impl.h b/components/arc/arc_bridge_service_impl.h
index 7f92c68..8d89e32 100644
--- a/components/arc/arc_bridge_service_impl.h
+++ b/components/arc/arc_bridge_service_impl.h
@@ -12,6 +12,8 @@
 #include "base/files/scoped_file.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_session.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -31,12 +33,14 @@
   // for testing purpose.
   using ArcSessionFactory = base::Callback<std::unique_ptr<ArcSession>()>;
 
-  ArcBridgeServiceImpl();
+  explicit ArcBridgeServiceImpl(
+      const scoped_refptr<base::TaskRunner>& blocking_task_runner);
   ~ArcBridgeServiceImpl() override;
 
-  void HandleStartup() override;
-
-  void Shutdown() override;
+  // ArcBridgeService overrides:
+  void RequestStart() override;
+  void RequestStop() override;
+  void OnShutdown() override;
 
   // Inject a factory to create ArcSession instance for testing purpose.
   // |factory| must not be null.
diff --git a/components/arc/arc_bridge_service_unittest.cc b/components/arc/arc_bridge_service_unittest.cc
index 8bc3de78..e0ab45d 100644
--- a/components/arc/arc_bridge_service_unittest.cc
+++ b/components/arc/arc_bridge_service_unittest.cc
@@ -75,7 +75,8 @@
     state_ = ArcBridgeService::State::STOPPED;
     stop_reason_ = ArcBridgeService::StopReason::SHUTDOWN;
 
-    service_.reset(new ArcBridgeServiceImpl());
+    // We inject FakeArcSession here so we do not need task_runner.
+    service_.reset(new ArcBridgeServiceImpl(nullptr));
     service_->SetArcSessionFactoryForTesting(
         base::Bind(FakeArcSession::Create));
     service_->AddObserver(this);
@@ -101,25 +102,25 @@
   ASSERT_FALSE(ready());
   ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
 
-  service_->HandleStartup();
+  service_->RequestStart();
   ASSERT_EQ(ArcBridgeService::State::READY, state());
 
-  service_->Shutdown();
+  service_->RequestStop();
   ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
 }
 
 // If the ArcBridgeService is shut down, it should be stopped, even
 // mid-startup.
-TEST_F(ArcBridgeTest, ShutdownMidStartup) {
+TEST_F(ArcBridgeTest, StopMidStartup) {
   ASSERT_FALSE(ready());
 
   service_->SetArcSessionFactoryForTesting(
       base::Bind(ArcBridgeTest::CreateSuspendedArcSession));
-  service_->HandleStartup();
+  service_->RequestStart();
   ASSERT_FALSE(service_->stopped());
   ASSERT_FALSE(service_->ready());
 
-  service_->Shutdown();
+  service_->RequestStop();
   ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
 }
 
@@ -131,7 +132,7 @@
   service_->SetArcSessionFactoryForTesting(
       base::Bind(ArcBridgeTest::CreateBootFailureArcSession,
                  ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE));
-  service_->HandleStartup();
+  service_->RequestStart();
   EXPECT_EQ(ArcBridgeService::StopReason::GENERIC_BOOT_FAILURE, stop_reason_);
   ASSERT_TRUE(service_->stopped());
 }
@@ -140,7 +141,7 @@
 TEST_F(ArcBridgeTest, Restart) {
   ASSERT_FALSE(ready());
 
-  service_->HandleStartup();
+  service_->RequestStart();
   ASSERT_EQ(ArcBridgeService::State::READY, state());
 
   // Simulate a connection loss.
@@ -149,7 +150,7 @@
   arc_session()->StopWithReason(ArcBridgeService::StopReason::CRASH);
   ASSERT_TRUE(service_->ready());
 
-  service_->Shutdown();
+  service_->RequestStop();
   ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
 }
 
@@ -158,7 +159,7 @@
   ASSERT_FALSE(ready());
 
   service_->DisableReconnectDelayForTesting();
-  service_->HandleStartup();
+  service_->RequestStart();
   ASSERT_EQ(ArcBridgeService::State::READY, state());
 
   // Simulate boot failure.
@@ -174,8 +175,21 @@
   EXPECT_EQ(ArcBridgeService::StopReason::CRASH, stop_reason_);
   ASSERT_TRUE(service_->ready());
 
-  // Graceful shutdown.
-  service_->Shutdown();
+  // Graceful stop.
+  service_->RequestStop();
+  ASSERT_EQ(ArcBridgeService::StopReason::SHUTDOWN, stop_reason_);
+  ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
+}
+
+TEST_F(ArcBridgeTest, Shutdown) {
+  ASSERT_FALSE(ready());
+
+  service_->DisableReconnectDelayForTesting();
+  service_->RequestStart();
+  ASSERT_EQ(ArcBridgeService::State::READY, state());
+
+  // Simulate shutdown.
+  service_->OnShutdown();
   ASSERT_EQ(ArcBridgeService::StopReason::SHUTDOWN, stop_reason_);
   ASSERT_EQ(ArcBridgeService::State::STOPPED, state());
 }
diff --git a/components/arc/arc_service_manager.cc b/components/arc/arc_service_manager.cc
index 0e47eb5..d01482f 100644
--- a/components/arc/arc_service_manager.cc
+++ b/components/arc/arc_service_manager.cc
@@ -51,7 +51,7 @@
     arc_bridge_service_.reset(g_arc_bridge_service_for_testing);
     g_arc_bridge_service_for_testing = nullptr;
   } else {
-    arc_bridge_service_.reset(new ArcBridgeServiceImpl());
+    arc_bridge_service_.reset(new ArcBridgeServiceImpl(blocking_task_runner));
   }
 
   AddService(base::MakeUnique<ArcAudioBridge>(arc_bridge_service()));
@@ -107,6 +107,7 @@
   icon_loader_ = nullptr;
   activity_resolver_ = nullptr;
   services_.clear();
+  arc_bridge_service_->OnShutdown();
 }
 
 // static
diff --git a/components/arc/arc_session.cc b/components/arc/arc_session.cc
index b40f703c..7d85e56 100644
--- a/components/arc/arc_session.cc
+++ b/components/arc/arc_session.cc
@@ -21,7 +21,6 @@
 #include "base/task_runner_util.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "base/threading/worker_pool.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -132,7 +131,7 @@
   // NOT_STARTED:
   //   Do nothing. Immediately transition to the STOPPED state.
   // CREATING_SOCKET:
-  //   The main task of the phase runs on WorkerPool thread. So, Stop() just
+  //   The main task of the phase runs on BlockingPool thread. So, Stop() just
   //   sets the flag and return. On the main task completion, a callback
   //   will run on the main (practically UI) thread, and the flag is checked
   //   at the beginning of them. This should work under the assumption that
@@ -145,7 +144,7 @@
   //   SessionManager. Its completion will be notified via ArcInstanceStopped.
   //   Otherwise, it just turns into STOPPED state.
   // CONNECTING_MOJO:
-  //   The main task runs on WorkerPool thread, but it is blocking call.
+  //   The main task runs on BlockingPool thread, but it is blocking call.
   //   So, Stop() sends a request to cancel the blocking by closing the pipe
   //   whose read side is also polled. Then, in its callback, similar to
   //   STARTING_INSTANCE, a request to stop the ARC instance is sent to
@@ -166,7 +165,7 @@
   //   STOPPED, then ArcInstanceStopped() is called. Do nothing in that case.
   // CONNECTING_MOJO:
   //   Similar to Stop() case above, ArcInstanceStopped() also notifies to
-  //   WorkerPool() thread to cancel it to unblock the thread. In
+  //   BlockingPool thread to cancel it to unblock the thread. In
   //   OnMojoConnected(), similar to OnInstanceStarted(), check if |state_| is
   //   STOPPED, then do nothing.
   // RUNNING:
@@ -199,12 +198,14 @@
     STOPPED,
   };
 
-  ArcSessionImpl();
+  explicit ArcSessionImpl(
+      const scoped_refptr<base::TaskRunner>& blocking_task_runner);
   ~ArcSessionImpl() override;
 
   // ArcSession overrides:
   void Start() override;
   void Stop() override;
+  void OnShutdown() override;
 
  private:
   // Creates the UNIX socket on a worker pool and then processes its file
@@ -231,6 +232,13 @@
   // Completes the termination procedure.
   void OnStopped(ArcBridgeService::StopReason reason);
 
+  // Checks whether a function runs on the thread where the instance is
+  // created.
+  base::ThreadChecker thread_checker_;
+
+  // Task runner to run a blocking tasks.
+  scoped_refptr<base::TaskRunner> blocking_task_runner_;
+
   // The state of the session.
   State state_ = State::NOT_STARTED;
 
@@ -244,8 +252,6 @@
   // Mojo endpoint.
   std::unique_ptr<mojom::ArcBridgeHost> arc_bridge_host_;
 
-  base::ThreadChecker thread_checker_;
-
   // WeakPtrFactory to use callbacks.
   base::WeakPtrFactory<ArcSessionImpl> weak_factory_;
 
@@ -253,7 +259,9 @@
   DISALLOW_COPY_AND_ASSIGN(ArcSessionImpl);
 };
 
-ArcSessionImpl::ArcSessionImpl() : weak_factory_(this) {
+ArcSessionImpl::ArcSessionImpl(
+    const scoped_refptr<base::TaskRunner>& blocking_task_runner)
+    : blocking_task_runner_(blocking_task_runner), weak_factory_(this) {
   chromeos::SessionManagerClient* client = GetSessionManagerClient();
   if (client == nullptr)
     return;
@@ -262,8 +270,7 @@
 
 ArcSessionImpl::~ArcSessionImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  // TODO(hidehiko): CHECK if |state_| is in NOT_STARTED or STOPPED.
-  // Currently, specifically on shutdown, the state_ can be any value.
+  DCHECK(state_ == State::NOT_STARTED || state_ == State::STOPPED);
   chromeos::SessionManagerClient* client = GetSessionManagerClient();
   if (client == nullptr)
     return;
@@ -278,7 +285,7 @@
 
   state_ = State::CREATING_SOCKET;
   base::PostTaskAndReplyWithResult(
-      base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
+      blocking_task_runner_.get(), FROM_HERE,
       base::Bind(&ArcSessionImpl::CreateSocket),
       base::Bind(&ArcSessionImpl::OnSocketCreated, weak_factory_.GetWeakPtr()));
 }
@@ -397,7 +404,7 @@
   }
 
   base::PostTaskAndReplyWithResult(
-      base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE,
+      blocking_task_runner_.get(), FROM_HERE,
       base::Bind(&ArcSessionImpl::ConnectMojo, base::Passed(&socket_fd),
                  base::Passed(&cancel_fd)),
       base::Bind(&ArcSessionImpl::OnMojoConnected, weak_factory_.GetWeakPtr()));
@@ -514,10 +521,9 @@
       return;
 
     case State::CONNECTING_MOJO:
-      // Mojo connection is being waited on a WorkerPool thread.
+      // Mojo connection is being waited on a BlockingPool thread.
       // Request to cancel it. Following stopping procedure will run
       // in its callback.
-      DCHECK(accept_cancel_pipe_.get());
       accept_cancel_pipe_.reset();
       return;
 
@@ -551,7 +557,7 @@
           << (clean ? "cleanly" : "uncleanly");
 
   // In case that crash happens during before the Mojo channel is connected,
-  // unlock the WorkerPool thread.
+  // unlock the BlockingPool thread.
   accept_cancel_pipe_.reset();
 
   ArcBridgeService::StopReason reason;
@@ -582,6 +588,31 @@
     observer.OnStopped(reason);
 }
 
+void ArcSessionImpl::OnShutdown() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  stop_requested_ = true;
+  if (state_ == State::STOPPED)
+    return;
+
+  // Here, the message loop is already stopped, and the Chrome will be soon
+  // shutdown. Thus, it is not necessary to take care about restarting case.
+  // If ArcSession is waiting for mojo connection, cancels it. The BlockingPool
+  // will be joined later.
+  accept_cancel_pipe_.reset();
+
+  // Stops the ARC instance to let it graceful shutdown.
+  // Note that this may fail if ARC container is not actually running, but
+  // ignore an error as described below.
+  if (state_ == State::STARTING_INSTANCE ||
+      state_ == State::CONNECTING_MOJO || state_ == State::RUNNING)
+    StopArcInstance();
+
+  // Directly set to the STOPPED stateby OnStopped(). Note that calling
+  // StopArcInstance() may not work well. At least, because the UI thread is
+  // already stopped here, ArcInstanceStopped() callback cannot be invoked.
+  OnStopped(ArcBridgeService::StopReason::SHUTDOWN);
+}
+
 }  // namespace
 
 ArcSession::ArcSession() = default;
@@ -596,8 +627,9 @@
 }
 
 // static
-std::unique_ptr<ArcSession> ArcSession::Create() {
-  return base::MakeUnique<ArcSessionImpl>();
+std::unique_ptr<ArcSession> ArcSession::Create(
+    const scoped_refptr<base::TaskRunner>& blocking_task_runner) {
+  return base::MakeUnique<ArcSessionImpl>(blocking_task_runner);
 }
 
 }  // namespace arc
diff --git a/components/arc/arc_session.h b/components/arc/arc_session.h
index 0e6e34b9..9d82e776 100644
--- a/components/arc/arc_session.h
+++ b/components/arc/arc_session.h
@@ -8,9 +8,11 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task_runner.h"
 #include "components/arc/arc_bridge_service.h"
 
 namespace arc {
@@ -41,7 +43,8 @@
   };
 
   // Creates a default instance of ArcSession.
-  static std::unique_ptr<ArcSession> Create();
+  static std::unique_ptr<ArcSession> Create(
+      const scoped_refptr<base::TaskRunner>& blocking_task_runner);
   virtual ~ArcSession();
 
   // Starts and bootstraps a connection with the instance. The Observer's
@@ -53,6 +56,10 @@
   // The completion is notified via OnStopped() of the Delegate.
   virtual void Stop() = 0;
 
+  // Called when Chrome is in shutdown state. This is called when the message
+  // loop is already stopped, and the instance will soon be deleted.
+  virtual void OnShutdown() = 0;
+
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
diff --git a/components/arc/test/fake_arc_bridge_service.cc b/components/arc/test/fake_arc_bridge_service.cc
index 00ec0c4..c6a8524 100644
--- a/components/arc/test/fake_arc_bridge_service.cc
+++ b/components/arc/test/fake_arc_bridge_service.cc
@@ -19,11 +19,15 @@
   SetStopped();
 }
 
-void FakeArcBridgeService::HandleStartup() {
+void FakeArcBridgeService::RequestStart() {
   SetReady();
 }
 
-void FakeArcBridgeService::Shutdown() {
+void FakeArcBridgeService::RequestStop() {
+  SetStopped();
+}
+
+void FakeArcBridgeService::OnShutdown() {
   SetStopped();
 }
 
diff --git a/components/arc/test/fake_arc_bridge_service.h b/components/arc/test/fake_arc_bridge_service.h
index 963836c8..c218112 100644
--- a/components/arc/test/fake_arc_bridge_service.h
+++ b/components/arc/test/fake_arc_bridge_service.h
@@ -18,9 +18,10 @@
   FakeArcBridgeService();
   ~FakeArcBridgeService() override;
 
-  // ArcBridgeService
-  void HandleStartup() override;
-  void Shutdown() override;
+  // ArcBridgeService overrides:
+  void RequestStart() override;
+  void RequestStop() override;
+  void OnShutdown() override;
 
   void SetReady();
 
diff --git a/components/arc/test/fake_arc_session.cc b/components/arc/test/fake_arc_session.cc
index 486068e..5ebc1e0 100644
--- a/components/arc/test/fake_arc_session.cc
+++ b/components/arc/test/fake_arc_session.cc
@@ -29,6 +29,10 @@
   StopWithReason(ArcBridgeService::StopReason::SHUTDOWN);
 }
 
+void FakeArcSession::OnShutdown() {
+  StopWithReason(ArcBridgeService::StopReason::SHUTDOWN);
+}
+
 void FakeArcSession::StopWithReason(ArcBridgeService::StopReason reason) {
   for (auto& observer : observer_list_)
     observer.OnStopped(reason);
diff --git a/components/arc/test/fake_arc_session.h b/components/arc/test/fake_arc_session.h
index a8f6ed04..fb56229c 100644
--- a/components/arc/test/fake_arc_session.h
+++ b/components/arc/test/fake_arc_session.h
@@ -21,6 +21,7 @@
   // ArcSession overrides:
   void Start() override;
   void Stop() override;
+  void OnShutdown() override;
 
   // To emulate unexpected stop, such as crash.
   void StopWithReason(ArcBridgeService::StopReason reason);
diff --git a/components/bubble/bubble_manager.cc b/components/bubble/bubble_manager.cc
index dc94dc2..acb9e7f3 100644
--- a/components/bubble/bubble_manager.cc
+++ b/components/bubble/bubble_manager.cc
@@ -33,8 +33,8 @@
       controllers_.push_back(std::move(controller));
       break;
     case NO_MORE_BUBBLES:
-      FOR_EACH_OBSERVER(BubbleManagerObserver, observers_,
-                        OnBubbleNeverShown(controller->AsWeakPtr()));
+      for (auto& observer : observers_)
+        observer.OnBubbleNeverShown(controller->AsWeakPtr());
       break;
     default:
       NOTREACHED();
@@ -125,8 +125,8 @@
   for (auto* controller : close_queue) {
     controller->DoClose(reason);
 
-    FOR_EACH_OBSERVER(BubbleManagerObserver, observers_,
-                      OnBubbleClosed(controller->AsWeakPtr(), reason));
+    for (auto& observer : observers_)
+      observer.OnBubbleClosed(controller->AsWeakPtr(), reason);
   }
 
   return !close_queue.empty();
diff --git a/components/offline_pages/background/BUILD.gn b/components/offline_pages/background/BUILD.gn
index 6084ba3a..2b6c9322 100644
--- a/components/offline_pages/background/BUILD.gn
+++ b/components/offline_pages/background/BUILD.gn
@@ -11,6 +11,8 @@
     "change_requests_state_task.cc",
     "change_requests_state_task.h",
     "device_conditions.h",
+    "mark_attempt_aborted_task.cc",
+    "mark_attempt_aborted_task.h",
     "mark_attempt_started_task.cc",
     "mark_attempt_started_task.h",
     "offliner.h",
@@ -35,6 +37,8 @@
     "save_page_request.cc",
     "save_page_request.h",
     "scheduler.h",
+    "update_request_task.cc",
+    "update_request_task.h",
   ]
 
   deps = [
@@ -52,6 +56,7 @@
   testonly = true
   sources = [
     "change_requests_state_task_unittest.cc",
+    "mark_attempt_aborted_task_unittest.cc",
     "mark_attempt_started_task_unittest.cc",
     "remove_requests_task_unittest.cc",
     "request_coordinator_event_logger_unittest.cc",
diff --git a/components/offline_pages/background/mark_attempt_aborted_task.cc b/components/offline_pages/background/mark_attempt_aborted_task.cc
new file mode 100644
index 0000000..150baac4
--- /dev/null
+++ b/components/offline_pages/background/mark_attempt_aborted_task.cc
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/background/mark_attempt_aborted_task.h"
+
+#include "base/bind.h"
+
+namespace offline_pages {
+
+MarkAttemptAbortedTask::MarkAttemptAbortedTask(
+    RequestQueueStore* store,
+    int64_t request_id,
+    const RequestQueueStore::UpdateCallback& callback)
+    : UpdateRequestTask(store, request_id, callback) {}
+
+MarkAttemptAbortedTask::~MarkAttemptAbortedTask() {}
+
+void MarkAttemptAbortedTask::UpdateRequestImpl(
+    std::unique_ptr<UpdateRequestsResult> read_result) {
+  if (!ValidateReadResult(read_result.get())) {
+    CompleteWithResult(std::move(read_result));
+    return;
+  }
+
+  // It is perfectly fine to reuse the read_result->updated_items collection, as
+  // it is owned by this callback and will be destroyed when out of scope.
+  read_result->updated_items[0].MarkAttemptAborted();
+  store()->UpdateRequests(
+      read_result->updated_items,
+      base::Bind(&MarkAttemptAbortedTask::CompleteWithResult, GetWeakPtr()));
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/background/mark_attempt_aborted_task.h b/components/offline_pages/background/mark_attempt_aborted_task.h
new file mode 100644
index 0000000..80d6367d
--- /dev/null
+++ b/components/offline_pages/background/mark_attempt_aborted_task.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_MARK_ATTEMPT_ABORTED_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_MARK_ATTEMPT_ABORTED_TASK_H_
+
+#include <stdint.h>
+
+#include "components/offline_pages/background/request_queue_store.h"
+#include "components/offline_pages/background/update_request_task.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+class MarkAttemptAbortedTask : public UpdateRequestTask {
+ public:
+  MarkAttemptAbortedTask(RequestQueueStore* store,
+                         int64_t request_id,
+                         const RequestQueueStore::UpdateCallback& callback);
+  ~MarkAttemptAbortedTask() override;
+
+ protected:
+  // UpdateRequestTask implementation:
+  void UpdateRequestImpl(std::unique_ptr<UpdateRequestsResult> result) override;
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_BACKGROUND_MARK_ATTEMPT_ABORTED_TASK_H_
diff --git a/components/offline_pages/background/mark_attempt_aborted_task_unittest.cc b/components/offline_pages/background/mark_attempt_aborted_task_unittest.cc
new file mode 100644
index 0000000..fc35d20
--- /dev/null
+++ b/components/offline_pages/background/mark_attempt_aborted_task_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/background/mark_attempt_aborted_task.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/background/mark_attempt_started_task.h"
+#include "components/offline_pages/background/request_queue_in_memory_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+namespace {
+const int64_t kRequestId1 = 42;
+const int64_t kRequestId2 = 44;
+const GURL kUrl1("http://example.com");
+const ClientId kClientId1("download", "1234");
+}  // namespace
+
+class MarkAttemptAbortedTaskTest : public testing::Test {
+ public:
+  MarkAttemptAbortedTaskTest();
+  ~MarkAttemptAbortedTaskTest() override;
+
+  void PumpLoop();
+
+  void AddItemToStore(RequestQueueStore* store);
+
+  void AddRequestDone(ItemActionStatus status);
+
+  void ChangeRequestsStateCallback(
+      std::unique_ptr<UpdateRequestsResult> result);
+
+  void ClearResults();
+
+  UpdateRequestsResult* last_result() const { return result_.get(); }
+
+ private:
+  std::unique_ptr<UpdateRequestsResult> result_;
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
+};
+
+MarkAttemptAbortedTaskTest::MarkAttemptAbortedTaskTest()
+    : task_runner_(new base::TestSimpleTaskRunner),
+      task_runner_handle_(task_runner_) {}
+
+MarkAttemptAbortedTaskTest::~MarkAttemptAbortedTaskTest() {}
+
+void MarkAttemptAbortedTaskTest::PumpLoop() {
+  task_runner_->RunUntilIdle();
+}
+
+void MarkAttemptAbortedTaskTest::AddItemToStore(RequestQueueStore* store) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
+                            true);
+  store->AddRequest(request_1,
+                    base::Bind(&MarkAttemptAbortedTaskTest::AddRequestDone,
+                               base::Unretained(this)));
+  PumpLoop();
+}
+
+void MarkAttemptAbortedTaskTest::AddRequestDone(ItemActionStatus status) {
+  ASSERT_EQ(ItemActionStatus::SUCCESS, status);
+}
+
+void MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback(
+    std::unique_ptr<UpdateRequestsResult> result) {
+  result_ = std::move(result);
+}
+
+void MarkAttemptAbortedTaskTest::ClearResults() {
+  result_.reset(nullptr);
+}
+
+TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenStoreEmpty) {
+  RequestQueueInMemoryStore store;
+  MarkAttemptAbortedTask task(
+      &store, kRequestId1,
+      base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+                 base::Unretained(this)));
+  task.Run();
+  PumpLoop();
+  ASSERT_TRUE(last_result());
+  EXPECT_EQ(1UL, last_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+  EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+            last_result()->item_statuses.at(0).second);
+  EXPECT_EQ(0UL, last_result()->updated_items.size());
+}
+
+TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenExists) {
+  RequestQueueInMemoryStore store;
+  AddItemToStore(&store);
+
+  // First mark attempt started.
+  MarkAttemptStartedTask start_request_task(
+      &store, kRequestId1,
+      base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+                 base::Unretained(this)));
+  start_request_task.Run();
+  PumpLoop();
+  ClearResults();
+
+  MarkAttemptAbortedTask task(
+      &store, kRequestId1,
+      base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+                 base::Unretained(this)));
+
+  task.Run();
+  PumpLoop();
+  ASSERT_TRUE(last_result());
+  EXPECT_EQ(1UL, last_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId1, last_result()->item_statuses.at(0).first);
+  EXPECT_EQ(ItemActionStatus::SUCCESS,
+            last_result()->item_statuses.at(0).second);
+  EXPECT_EQ(1UL, last_result()->updated_items.size());
+  EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE,
+            last_result()->updated_items.at(0).request_state());
+}
+
+TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenItemMissing) {
+  RequestQueueInMemoryStore store;
+  AddItemToStore(&store);
+  MarkAttemptAbortedTask task(
+      &store, kRequestId2,
+      base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+                 base::Unretained(this)));
+  task.Run();
+  PumpLoop();
+  ASSERT_TRUE(last_result());
+  EXPECT_EQ(1UL, last_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId2, last_result()->item_statuses.at(0).first);
+  EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+            last_result()->item_statuses.at(0).second);
+  EXPECT_EQ(0UL, last_result()->updated_items.size());
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/background/mark_attempt_started_task.cc b/components/offline_pages/background/mark_attempt_started_task.cc
index ecd0507..f1a82ac8 100644
--- a/components/offline_pages/background/mark_attempt_started_task.cc
+++ b/components/offline_pages/background/mark_attempt_started_task.cc
@@ -4,8 +4,6 @@
 
 #include "components/offline_pages/background/mark_attempt_started_task.h"
 
-#include <vector>
-
 #include "base/bind.h"
 #include "base/time/time.h"
 
@@ -15,29 +13,13 @@
     RequestQueueStore* store,
     int64_t request_id,
     const RequestQueueStore::UpdateCallback& callback)
-    : store_(store),
-      request_id_(request_id),
-      callback_(callback),
-      weak_ptr_factory_(this) {}
+    : UpdateRequestTask(store, request_id, callback) {}
 
 MarkAttemptStartedTask::~MarkAttemptStartedTask() {}
 
-void MarkAttemptStartedTask::Run() {
-  ReadRequest();
-}
-
-void MarkAttemptStartedTask::ReadRequest() {
-  std::vector<int64_t> request_ids{request_id_};
-  store_->GetRequestsByIds(
-      request_ids, base::Bind(&MarkAttemptStartedTask::MarkAttemptStarted,
-                              weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MarkAttemptStartedTask::MarkAttemptStarted(
+void MarkAttemptStartedTask::UpdateRequestImpl(
     std::unique_ptr<UpdateRequestsResult> read_result) {
-  if (read_result->store_state != StoreState::LOADED ||
-      read_result->item_statuses.front().second != ItemActionStatus::SUCCESS ||
-      read_result->updated_items.size() != 1) {
+  if (!ValidateReadResult(read_result.get())) {
     CompleteWithResult(std::move(read_result));
     return;
   }
@@ -45,15 +27,9 @@
   // It is perfectly fine to reuse the read_result->updated_items collection, as
   // it is owned by this callback and will be destroyed when out of scope.
   read_result->updated_items[0].MarkAttemptStarted(base::Time::Now());
-  store_->UpdateRequests(read_result->updated_items,
-                         base::Bind(&MarkAttemptStartedTask::CompleteWithResult,
-                                    weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MarkAttemptStartedTask::CompleteWithResult(
-    std::unique_ptr<UpdateRequestsResult> result) {
-  callback_.Run(std::move(result));
-  TaskComplete();
+  store()->UpdateRequests(
+      read_result->updated_items,
+      base::Bind(&MarkAttemptStartedTask::CompleteWithResult, GetWeakPtr()));
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/mark_attempt_started_task.h b/components/offline_pages/background/mark_attempt_started_task.h
index c01df65..8afaef8e 100644
--- a/components/offline_pages/background/mark_attempt_started_task.h
+++ b/components/offline_pages/background/mark_attempt_started_task.h
@@ -7,44 +7,22 @@
 
 #include <stdint.h>
 
-#include <memory>
-#include <unordered_set>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
 #include "components/offline_pages/background/request_queue_store.h"
-#include "components/offline_pages/background/save_page_request.h"
+#include "components/offline_pages/background/update_request_task.h"
 #include "components/offline_pages/core/task.h"
 
 namespace offline_pages {
 
-class MarkAttemptStartedTask : public Task {
+class MarkAttemptStartedTask : public UpdateRequestTask {
  public:
   MarkAttemptStartedTask(RequestQueueStore* store,
                          int64_t request_id,
                          const RequestQueueStore::UpdateCallback& callback);
   ~MarkAttemptStartedTask() override;
 
-  // TaskQueue::Task implementation.
-  void Run() override;
-
- private:
-  // Step 1. Reading the requests.
-  void ReadRequest();
-  // Step 2. Verifies item exists, marks started and saves.
-  void MarkAttemptStarted(std::unique_ptr<UpdateRequestsResult> result);
-  // Step 3. Completes once update is done.
-  void CompleteWithResult(std::unique_ptr<UpdateRequestsResult> result);
-
-  // Store that this task updates. Not owned.
-  RequestQueueStore* store_;
-  // Request ID of the request to be started.
-  int64_t request_id_;
-  // Callback to complete the task.
-  RequestQueueStore::UpdateCallback callback_;
-
-  base::WeakPtrFactory<MarkAttemptStartedTask> weak_ptr_factory_;
-  DISALLOW_COPY_AND_ASSIGN(MarkAttemptStartedTask);
+ protected:
+  // UpdateRequestTask implementation:
+  void UpdateRequestImpl(std::unique_ptr<UpdateRequestsResult> result) override;
 };
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc
index 88caef0..90ab7d2 100644
--- a/components/offline_pages/background/request_coordinator.cc
+++ b/components/offline_pages/background/request_coordinator.cc
@@ -247,7 +247,6 @@
 }
 
 void RequestCoordinator::AbortRequestAttempt(SavePageRequest* request) {
-  request->MarkAttemptAborted();
   if (request->started_attempt_count() >= policy_->GetMaxStartedTries()) {
     const BackgroundSavePageResult result(
         BackgroundSavePageResult::START_COUNT_EXCEEDED);
@@ -255,10 +254,11 @@
                                                result, request->request_id());
     RemoveAttemptedRequest(*request, result);
   } else {
-    queue_->UpdateRequest(
-        *request,
-        base::Bind(&RequestCoordinator::UpdateRequestCallback,
-                   weak_ptr_factory_.GetWeakPtr(), request->client_id()));
+    queue_->MarkAttemptAborted(
+        request->request_id(),
+        base::Bind(&RequestCoordinator::MarkAttemptAbortedDone,
+                   weak_ptr_factory_.GetWeakPtr(), request->request_id(),
+                   request->client_id()));
   }
 }
 
@@ -273,6 +273,25 @@
   RecordAttemptCount(request, result);
 }
 
+void RequestCoordinator::MarkAttemptAbortedDone(
+    int64_t request_id,
+    const ClientId& client_id,
+    std::unique_ptr<UpdateRequestsResult> result) {
+  // If the request succeeded, nothing to do.  If it failed, we can't really do
+  // much, so just log it.
+  if (result->store_state != StoreState::LOADED ||
+      result->item_statuses.size() != 1 ||
+      result->item_statuses.at(0).first != request_id ||
+      result->item_statuses.at(0).second != ItemActionStatus::SUCCESS) {
+    DVLOG(1) << "Failed to mark request aborted: " << request_id;
+    event_logger_.RecordUpdateRequestFailed(
+        client_id.name_space,
+        result->store_state != StoreState::LOADED
+            ? RequestQueue::UpdateRequestResult::STORE_FAILURE
+            : RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST);
+  }
+}
+
 void RequestCoordinator::RemoveRequests(
     const std::vector<int64_t>& request_ids,
     const RemoveRequestsCallback& callback) {
diff --git a/components/offline_pages/background/request_coordinator.h b/components/offline_pages/background/request_coordinator.h
index 780fd40..8ab2385 100644
--- a/components/offline_pages/background/request_coordinator.h
+++ b/components/offline_pages/background/request_coordinator.h
@@ -311,6 +311,11 @@
   void RemoveAttemptedRequest(const SavePageRequest& request,
                               BackgroundSavePageResult status);
 
+  // Completes aborting the request, reports an error if it fails.
+  void MarkAttemptAbortedDone(int64_t request_id,
+                              const ClientId& client_id,
+                              std::unique_ptr<UpdateRequestsResult> result);
+
   // Returns the appropriate offliner to use, getting a new one from the factory
   // if needed.
   void GetOffliner();
diff --git a/components/offline_pages/background/request_queue.cc b/components/offline_pages/background/request_queue.cc
index d3f48d2..542b1f4 100644
--- a/components/offline_pages/background/request_queue.cc
+++ b/components/offline_pages/background/request_queue.cc
@@ -8,6 +8,7 @@
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/offline_pages/background/change_requests_state_task.h"
+#include "components/offline_pages/background/mark_attempt_aborted_task.h"
 #include "components/offline_pages/background/mark_attempt_started_task.h"
 #include "components/offline_pages/background/remove_requests_task.h"
 #include "components/offline_pages/background/request_queue_store.h"
@@ -167,6 +168,13 @@
   task_queue_.AddTask(std::move(task));
 }
 
+void RequestQueue::MarkAttemptAborted(int64_t request_id,
+                                      const UpdateCallback& callback) {
+  std::unique_ptr<Task> task(
+      new MarkAttemptAbortedTask(store_.get(), request_id, callback));
+  task_queue_.AddTask(std::move(task));
+}
+
 void RequestQueue::PurgeRequests(const PurgeRequestsCallback& callback) {}
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/request_queue.h b/components/offline_pages/background/request_queue.h
index b08908c..7ad0e49 100644
--- a/components/offline_pages/background/request_queue.h
+++ b/components/offline_pages/background/request_queue.h
@@ -99,6 +99,10 @@
   // |callback|.
   void MarkAttemptStarted(int64_t request_id, const UpdateCallback& callback);
 
+  // Marks attempt with |request_id| as aborted. Results are returned through
+  // |callback|.
+  void MarkAttemptAborted(int64_t request_id, const UpdateCallback& callback);
+
   void GetForUpdateDone(
       const RequestQueue::UpdateRequestCallback& update_callback,
       const SavePageRequest& update_request,
diff --git a/components/offline_pages/background/request_queue_unittest.cc b/components/offline_pages/background/request_queue_unittest.cc
index 857245bb..9018999 100644
--- a/components/offline_pages/background/request_queue_unittest.cc
+++ b/components/offline_pages/background/request_queue_unittest.cc
@@ -53,6 +53,8 @@
   void UpdateRequestDone(UpdateRequestResult result);
   void UpdateRequestsDone(std::unique_ptr<UpdateRequestsResult> result);
 
+  void ClearResults();
+
   RequestQueue* queue() { return queue_.get(); }
 
   AddRequestResult last_add_result() const { return last_add_result_; }
@@ -129,6 +131,15 @@
   update_requests_result_ = std::move(result);
 }
 
+void RequestQueueTest::ClearResults() {
+  last_add_result_ = AddRequestResult::STORE_FAILURE;
+  last_update_result_ = UpdateRequestResult::STORE_FAILURE;
+  last_get_requests_result_ = GetRequestsResult::STORE_FAILURE;
+  last_added_request_.reset(nullptr);
+  update_requests_result_.reset(nullptr);
+  last_requests_.clear();
+}
+
 TEST_F(RequestQueueTest, GetRequestsEmpty) {
   queue()->GetRequests(
       base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
@@ -440,4 +451,52 @@
   EXPECT_EQ(0ul, update_requests_result()->updated_items.size());
 }
 
+TEST_F(RequestQueueTest, MarkAttemptAborted) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
+                          kUserRequested);
+  queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
+                                          base::Unretained(this)));
+  PumpLoop();
+
+  // Start request.
+  queue()->MarkAttemptStarted(kRequestId,
+                              base::Bind(&RequestQueueTest::UpdateRequestsDone,
+                                         base::Unretained(this)));
+  PumpLoop();
+  ClearResults();
+
+  queue()->MarkAttemptAborted(kRequestId,
+                              base::Bind(&RequestQueueTest::UpdateRequestsDone,
+                                         base::Unretained(this)));
+  PumpLoop();
+
+  ASSERT_TRUE(update_requests_result());
+  EXPECT_EQ(1UL, update_requests_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+  EXPECT_EQ(ItemActionStatus::SUCCESS,
+            update_requests_result()->item_statuses.at(0).second);
+  EXPECT_EQ(1UL, update_requests_result()->updated_items.size());
+  EXPECT_EQ(SavePageRequest::RequestState::AVAILABLE,
+            update_requests_result()->updated_items.at(0).request_state());
+}
+
+TEST_F(RequestQueueTest, MarkAttemptAbortedRequestNotPresent) {
+  // First add a request.  Retry count will be set to 0.
+  base::Time creation_time = base::Time::Now();
+  // This request is never put into the queue.
+  SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
+                           kUserRequested);
+
+  queue()->MarkAttemptAborted(kRequestId,
+                              base::Bind(&RequestQueueTest::UpdateRequestsDone,
+                                         base::Unretained(this)));
+  PumpLoop();
+  ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
+  EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+            update_requests_result()->item_statuses.at(0).second);
+  EXPECT_EQ(0ul, update_requests_result()->updated_items.size());
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/update_request_task.cc b/components/offline_pages/background/update_request_task.cc
new file mode 100644
index 0000000..08ccf1cb
--- /dev/null
+++ b/components/offline_pages/background/update_request_task.cc
@@ -0,0 +1,50 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/background/update_request_task.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/time/time.h"
+
+namespace offline_pages {
+
+UpdateRequestTask::UpdateRequestTask(
+    RequestQueueStore* store,
+    int64_t request_id,
+    const RequestQueueStore::UpdateCallback& callback)
+    : store_(store),
+      request_id_(request_id),
+      callback_(callback),
+      weak_ptr_factory_(this) {}
+
+UpdateRequestTask::~UpdateRequestTask() {}
+
+void UpdateRequestTask::Run() {
+  ReadRequest();
+}
+
+void UpdateRequestTask::ReadRequest() {
+  std::vector<int64_t> request_ids{request_id_};
+  store_->GetRequestsByIds(request_ids,
+                           base::Bind(&UpdateRequestTask::UpdateRequestImpl,
+                                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+void UpdateRequestTask::CompleteWithResult(
+    std::unique_ptr<UpdateRequestsResult> result) {
+  callback_.Run(std::move(result));
+  TaskComplete();
+}
+
+bool UpdateRequestTask::ValidateReadResult(UpdateRequestsResult* result) {
+  return result->store_state == StoreState::LOADED &&
+         result->item_statuses.at(0).first == request_id() &&
+         result->item_statuses.at(0).second == ItemActionStatus::SUCCESS &&
+         result->updated_items.size() == 1 &&
+         result->updated_items.at(0).request_id() == request_id();
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/background/update_request_task.h b/components/offline_pages/background/update_request_task.h
new file mode 100644
index 0000000..ad332bd9
--- /dev/null
+++ b/components/offline_pages/background/update_request_task.h
@@ -0,0 +1,66 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_UPDATE_REQUEST_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_UPDATE_REQUEST_TASK_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/background/request_queue_store.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+
+// Base class for update requests that only work on a single save page request.
+// Derived classes should implement appropriate functionality by overloading
+// |UpdateRequestImpl| method.
+class UpdateRequestTask : public Task {
+ public:
+  UpdateRequestTask(RequestQueueStore* store,
+                    int64_t request_id,
+                    const RequestQueueStore::UpdateCallback& callback);
+  ~UpdateRequestTask() override;
+
+  // TaskQueue::Task implementation.
+  void Run() override;
+
+ protected:
+  // Step 1. Reading the requests.
+  void ReadRequest();
+  // Step 2. Work is done in the implementation step.
+  virtual void UpdateRequestImpl(
+      std::unique_ptr<UpdateRequestsResult> result) = 0;
+  // Step 3. Completes once update is done.
+  void CompleteWithResult(std::unique_ptr<UpdateRequestsResult> result);
+
+  // Function to uniformly validate read request call for store errors and
+  // presence of the request.
+  bool ValidateReadResult(UpdateRequestsResult* result);
+
+  RequestQueueStore* store() const { return store_; }
+
+  int64_t request_id() const { return request_id_; }
+
+  base::WeakPtr<UpdateRequestTask> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ private:
+  // Store that this task updates. Not owned.
+  RequestQueueStore* store_;
+  // Request ID of the request to be started.
+  int64_t request_id_;
+  // Callback to complete the task.
+  RequestQueueStore::UpdateCallback callback_;
+
+  base::WeakPtrFactory<UpdateRequestTask> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(UpdateRequestTask);
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_BACKGROUND_UPDATE_REQUEST_TASK_H_
diff --git a/components/password_manager/content/browser/BUILD.gn b/components/password_manager/content/browser/BUILD.gn
index 6624d81..a0c5cc3 100644
--- a/components/password_manager/content/browser/BUILD.gn
+++ b/components/password_manager/content/browser/BUILD.gn
@@ -22,7 +22,7 @@
     "//components/autofill/content/common:mojo_interfaces",
     "//components/autofill/core/common",
     "//components/keyed_service/content",
-    "//components/password_manager/content/public/interfaces",
+    "//components/password_manager/content/common:mojo_interfaces",
     "//components/password_manager/core/browser",
     "//components/password_manager/core/common",
     "//components/prefs",
diff --git a/components/password_manager/content/browser/credential_manager_impl.h b/components/password_manager/content/browser/credential_manager_impl.h
index a72a1b0..3b78c69 100644
--- a/components/password_manager/content/browser/credential_manager_impl.h
+++ b/components/password_manager/content/browser/credential_manager_impl.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
+#include "components/password_manager/content/common/credential_manager.mojom.h"
 #include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
 #include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
 #include "components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h"
diff --git a/components/password_manager/content/public/interfaces/BUILD.gn b/components/password_manager/content/common/BUILD.gn
similarity index 92%
rename from components/password_manager/content/public/interfaces/BUILD.gn
rename to components/password_manager/content/common/BUILD.gn
index 66d988d..0fafcea 100644
--- a/components/password_manager/content/public/interfaces/BUILD.gn
+++ b/components/password_manager/content/common/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//mojo/public/tools/bindings/mojom.gni")
 
-mojom("interfaces") {
+mojom("mojo_interfaces") {
   sources = [
     "credential_manager.mojom",
   ]
diff --git a/components/password_manager/content/common/OWNERS b/components/password_manager/content/common/OWNERS
new file mode 100644
index 0000000..1544352
--- /dev/null
+++ b/components/password_manager/content/common/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/components/password_manager/content/public/interfaces/credential_manager.mojom b/components/password_manager/content/common/credential_manager.mojom
similarity index 100%
rename from components/password_manager/content/public/interfaces/credential_manager.mojom
rename to components/password_manager/content/common/credential_manager.mojom
diff --git a/components/password_manager/content/public/cpp/credential_manager.typemap b/components/password_manager/content/common/credential_manager.typemap
similarity index 64%
rename from components/password_manager/content/public/cpp/credential_manager.typemap
rename to components/password_manager/content/common/credential_manager.typemap
index 19d3c47..180b081 100644
--- a/components/password_manager/content/public/cpp/credential_manager.typemap
+++ b/components/password_manager/content/common/credential_manager.typemap
@@ -2,12 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-mojom = "//components/password_manager/content/public/interfaces/credential_manager.mojom"
+mojom = "//components/password_manager/content/common/credential_manager.mojom"
 public_headers =
     [ "//components/password_manager/core/common/credential_manager_types.h" ]
-traits_headers = [ "//components/password_manager/content/public/cpp/credential_manager_struct_traits.h" ]
+traits_headers = [ "//components/password_manager/content/common/credential_manager_struct_traits.h" ]
 sources = [
-  "//components/password_manager/content/public/cpp/credential_manager_struct_traits.cc",
+  "//components/password_manager/content/common/credential_manager_struct_traits.cc",
 ]
 deps = [
   "//base",
diff --git a/components/password_manager/content/public/cpp/credential_manager_struct_traits.cc b/components/password_manager/content/common/credential_manager_struct_traits.cc
similarity index 94%
rename from components/password_manager/content/public/cpp/credential_manager_struct_traits.cc
rename to components/password_manager/content/common/credential_manager_struct_traits.cc
index 1b780069..315ebaf 100644
--- a/components/password_manager/content/public/cpp/credential_manager_struct_traits.cc
+++ b/components/password_manager/content/common/credential_manager_struct_traits.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/password_manager/content/public/cpp/credential_manager_struct_traits.h"
+#include "components/password_manager/content/common/credential_manager_struct_traits.h"
 
 #include "url/mojo/origin_struct_traits.h"
 #include "url/mojo/url_gurl_struct_traits.h"
diff --git a/components/password_manager/content/public/cpp/credential_manager_struct_traits.h b/components/password_manager/content/common/credential_manager_struct_traits.h
similarity index 81%
rename from components/password_manager/content/public/cpp/credential_manager_struct_traits.h
rename to components/password_manager/content/common/credential_manager_struct_traits.h
index b8415b2..cf8c5a7 100644
--- a/components/password_manager/content/public/cpp/credential_manager_struct_traits.h
+++ b/components/password_manager/content/common/credential_manager_struct_traits.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
-#define COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
+#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
+#define COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
 
 #include "base/strings/string16.h"
-#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
+#include "components/password_manager/content/common/credential_manager.mojom.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "mojo/public/cpp/bindings/struct_traits.h"
 
@@ -57,4 +57,4 @@
 
 }  // namespace mojo
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
+#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_STRUCT_TRAITS_H_
diff --git a/components/password_manager/content/public/cpp/OWNERS b/components/password_manager/content/public/cpp/OWNERS
deleted file mode 100644
index bb65116..0000000
--- a/components/password_manager/content/public/cpp/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/components/password_manager/content/public/interfaces/OWNERS b/components/password_manager/content/public/interfaces/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/components/password_manager/content/public/interfaces/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/password_manager/content/renderer/BUILD.gn b/components/password_manager/content/renderer/BUILD.gn
index ff053f3..15db432 100644
--- a/components/password_manager/content/renderer/BUILD.gn
+++ b/components/password_manager/content/renderer/BUILD.gn
@@ -10,7 +10,7 @@
 
   deps = [
     "//base",
-    "//components/password_manager/content/public/interfaces",
+    "//components/password_manager/content/common:mojo_interfaces",
     "//components/password_manager/core/common",
     "//components/strings",
     "//content/public/common",
diff --git a/components/password_manager/content/renderer/credential_manager_client.h b/components/password_manager/content/renderer/credential_manager_client.h
index 867105e..ded86d62 100644
--- a/components/password_manager/content/renderer/credential_manager_client.h
+++ b/components/password_manager/content/renderer/credential_manager_client.h
@@ -7,7 +7,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
+#include "components/password_manager/content/common/credential_manager.mojom.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerClient.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerError.h"
diff --git a/components/safe_browsing_db/v4_feature_list.cc b/components/safe_browsing_db/v4_feature_list.cc
index a8435ed..68e43b5 100644
--- a/components/safe_browsing_db/v4_feature_list.cc
+++ b/components/safe_browsing_db/v4_feature_list.cc
@@ -14,17 +14,18 @@
     "SafeBrowsingV4LocalDatabaseManagerEnabled",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kParallelCheckEnabled{"SafeBrowingV4ParallelCheckEnabled",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kV4HybridEnabled{"SafeBrowingV4HybridEnabled",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace
 
 bool IsLocalDatabaseManagerEnabled() {
-  return IsParallelCheckEnabled() ||
-         base::FeatureList::IsEnabled(kLocalDatabaseManagerEnabled);
+  return base::FeatureList::IsEnabled(kLocalDatabaseManagerEnabled) ||
+         IsV4HybridEnabled();
 }
 
-bool IsParallelCheckEnabled() {
-  return base::FeatureList::IsEnabled(kParallelCheckEnabled);
+bool IsV4HybridEnabled() {
+  return base::FeatureList::IsEnabled(kV4HybridEnabled);
 }
 
 }  // namespace V4FeatureList
diff --git a/components/safe_browsing_db/v4_feature_list.h b/components/safe_browsing_db/v4_feature_list.h
index b305541..5bb67483 100644
--- a/components/safe_browsing_db/v4_feature_list.h
+++ b/components/safe_browsing_db/v4_feature_list.h
@@ -11,11 +11,12 @@
 // through Finch.
 namespace V4FeatureList {
 
-// Is the Pver4 database manager enabled?
+// Is the PVer4 database manager enabled?
 bool IsLocalDatabaseManagerEnabled();
 
-// Is the Pver4 database manager doing resource checks in paralled with PVer3?
-bool IsParallelCheckEnabled();
+// Is the PVer4 database being checked for resource reputation? If this returns
+// true, use PVer4 database for CheckBrowseUrl, otherwise use PVer3.
+bool IsV4HybridEnabled();
 
 }  // namespace V4FeatureList
 
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc
index 9ef9f9d..5798bf2 100644
--- a/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -462,11 +462,16 @@
 }
 
 void V4LocalDatabaseManager::RespondToClient(
-    std::unique_ptr<PendingCheck> pending_check) {
-  DCHECK(pending_check.get());
-  DCHECK_EQ(ClientCallbackType::CHECK_BROWSE_URL,
-            pending_check->client_callback_type);
-  // TODO(vakh): Implement this skeleton.
+    std::unique_ptr<PendingCheck> check) {
+  DCHECK(check.get());
+  DCHECK_GT(ClientCallbackType::CHECK_MAX, check->client_callback_type);
+
+  if (check->client_callback_type == ClientCallbackType::CHECK_BROWSE_URL) {
+    check->client->OnCheckBrowseUrlResult(check->url, check->result_threat_type,
+                                          check->url_metadata);
+  } else {
+    NOTREACHED() << "Unexpected client_callback_type encountered";
+  }
 }
 
 void V4LocalDatabaseManager::SetupDatabase() {
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index d70f30f..f095c85c 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -210,9 +210,22 @@
   std::set<const SyncedWindowDelegate*> windows =
       synced_window_delegates_getter()->GetSyncedWindowDelegates();
 
+  if (option == RELOAD_TABS) {
+    UMA_HISTOGRAM_COUNTS("Sync.SessionWindows", windows.size());
+  }
+  if (windows.size() == 0) {
+    // Assume that the window hasn't loaded. Attempting to associate now would
+    // clobber any old windows, so just return.
+    LOG(ERROR) << "No windows present, see crbug.com/639009";
+    return;
+  }
   for (std::set<const SyncedWindowDelegate*>::const_iterator i =
            windows.begin();
        i != windows.end(); ++i) {
+    if (option == RELOAD_TABS) {
+      UMA_HISTOGRAM_COUNTS("Sync.SessionTabs", (*i)->GetTabCount());
+    }
+
     // Make sure the window has tabs and a viewable window. The viewable window
     // check is necessary because, for example, when a browser is closed the
     // destructor is not necessarily run immediately. This means its possible
diff --git a/components/test_runner/mock_web_midi_accessor.cc b/components/test_runner/mock_web_midi_accessor.cc
index e14e084..e6f95de 100644
--- a/components/test_runner/mock_web_midi_accessor.cc
+++ b/components/test_runner/mock_web_midi_accessor.cc
@@ -14,6 +14,7 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/modules/webmidi/WebMIDIAccessorClient.h"
 
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 namespace test_runner {
@@ -27,18 +28,12 @@
 
 void MockWebMIDIAccessor::startSession() {
   // Add a mock input and output port.
-  blink::WebMIDIAccessorClient::MIDIPortState state =
-      blink::WebMIDIAccessorClient::MIDIPortStateConnected;
-  client_->didAddInputPort("MockInputID",
-                           "MockInputManufacturer",
-                           "MockInputName",
-                           "MockInputVersion",
-                           state);
-  client_->didAddOutputPort("MockOutputID",
-                            "MockOutputManufacturer",
-                            "MockOutputName",
-                            "MockOutputVersion",
-                            state);
+  client_->didAddInputPort("MockInputID", "MockInputManufacturer",
+                           "MockInputName", "MockInputVersion",
+                           PortState::CONNECTED);
+  client_->didAddOutputPort("MockOutputID", "MockOutputManufacturer",
+                            "MockOutputName", "MockOutputVersion",
+                            PortState::CONNECTED);
   interfaces_->GetDelegate()->PostTask(base::Bind(
       &MockWebMIDIAccessor::ReportStartedSession, weak_factory_.GetWeakPtr(),
       interfaces_->GetTestRunner()->midiAccessorResult()));
diff --git a/components/translate/content/browser/content_translate_driver.cc b/components/translate/content/browser/content_translate_driver.cc
index 9860c30..54a862d 100644
--- a/components/translate/content/browser/content_translate_driver.cc
+++ b/components/translate/content/browser/content_translate_driver.cc
@@ -94,14 +94,14 @@
 
 void ContentTranslateDriver::OnTranslateEnabledChanged() {
   content::WebContents* web_contents = navigation_controller_->GetWebContents();
-  FOR_EACH_OBSERVER(
-      Observer, observer_list_, OnTranslateEnabledChanged(web_contents));
+  for (auto& observer : observer_list_)
+    observer.OnTranslateEnabledChanged(web_contents);
 }
 
 void ContentTranslateDriver::OnIsPageTranslatedChanged() {
   content::WebContents* web_contents = navigation_controller_->GetWebContents();
-  FOR_EACH_OBSERVER(Observer, observer_list_,
-                    OnIsPageTranslatedChanged(web_contents));
+  for (auto& observer : observer_list_)
+    observer.OnIsPageTranslatedChanged(web_contents);
 }
 
 void ContentTranslateDriver::TranslatePage(int page_seq_no,
@@ -238,7 +238,8 @@
   if (web_contents())
     translate_manager_->InitiateTranslation(details.adopted_language);
 
-  FOR_EACH_OBSERVER(Observer, observer_list_, OnLanguageDetermined(details));
+  for (auto& observer : observer_list_)
+    observer.OnLanguageDetermined(details);
 }
 
 void ContentTranslateDriver::OnPageTranslated(
@@ -251,10 +252,8 @@
 
   translate_manager_->PageTranslated(
       original_lang, translated_lang, error_type);
-  FOR_EACH_OBSERVER(
-      Observer,
-      observer_list_,
-      OnPageTranslated(original_lang, translated_lang, error_type));
+  for (auto& observer : observer_list_)
+    observer.OnPageTranslated(original_lang, translated_lang, error_type);
 }
 
 }  // namespace translate
diff --git a/components/typemaps.gni b/components/typemaps.gni
index ec96c87..da1f6d9 100644
--- a/components/typemaps.gni
+++ b/components/typemaps.gni
@@ -4,7 +4,7 @@
 
 typemaps = [
   "//components/autofill/content/common/autofill_types.typemap",
-  "//components/password_manager/content/public/cpp/credential_manager.typemap",
+  "//components/password_manager/content/common/credential_manager.typemap",
   "//components/safe_json/public/interfaces/safe_json.typemap",
   "//components/translate/content/common/translate.typemap",
 ]
diff --git a/components/url_formatter/url_formatter.cc b/components/url_formatter/url_formatter.cc
index 4455db3..2b82c0c 100644
--- a/components/url_formatter/url_formatter.cc
+++ b/components/url_formatter/url_formatter.cc
@@ -428,9 +428,9 @@
   // section at
   // http://www.unicode.org/Public/security/latest/xidmodifications.txt) are
   // are added to the allowed set. The list has to be updated when a new
-  // version of Unicode is released. The current version is 8.0.0 and ICU 58
-  // will have Unicode 9.0 data.
-#if U_ICU_VERSION_MAJOR_NUM < 58
+  // version of Unicode is released. The current version is 9.0.0 and ICU 60
+  // will have Unicode 10.0 data.
+#if U_ICU_VERSION_MAJOR_NUM < 60
   const icu::UnicodeSet aspirational_scripts(
       icu::UnicodeString(
           // Unified Canadian Syllabics
@@ -444,13 +444,13 @@
           // Yi
           "\\uA000-\\uA48C"
           // Miao
-          "\\U00016F00-\\U00016F44\\U00016F50-\\U00016F7F"
+          "\\U00016F00-\\U00016F44\\U00016F50-\\U00016F7E"
           "\\U00016F8F-\\U00016F9F]",
           -1, US_INV),
       *status);
   allowed_set.addAll(aspirational_scripts);
 #else
-#error "Update aspirational_scripts per Unicode 9.0"
+#error "Update aspirational_scripts per Unicode 10.0"
 #endif
 
   // U+0338 is included in the recommended set, while U+05F4 and U+2027 are in
diff --git a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index 7d9f004..cba1d0c 100644
--- a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -128,7 +128,11 @@
   const ui::AXNode* para = live_region->ChildAtIndex(0);
   EXPECT_EQ(ui::AX_ROLE_PARAGRAPH, para->data().role);
 
-  const ui::AXNode* button = root->ChildAtIndex(1);
+  const ui::AXNode* button_container = root->ChildAtIndex(1);
+  EXPECT_EQ(ui::AX_ROLE_GROUP, button_container->data().role);
+  ASSERT_EQ(1, button_container->child_count());
+
+  const ui::AXNode* button = button_container->ChildAtIndex(0);
   EXPECT_EQ(ui::AX_ROLE_BUTTON, button->data().role);
 }
 
diff --git a/content/browser/accessibility/accessibility_tree_formatter.cc b/content/browser/accessibility/accessibility_tree_formatter.cc
index 1b67e306..c5c60391 100644
--- a/content/browser/accessibility/accessibility_tree_formatter.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter.cc
@@ -78,12 +78,6 @@
   if (line.find(base::ASCIIToUTF16(kSkipString)) != base::string16::npos)
     return;
 
-  // Replace literal newlines with "<newline>"
-  base::ReplaceChars(line,
-                     base::ASCIIToUTF16("\n"),
-                     base::ASCIIToUTF16("<newline>"),
-                     &line);
-
   *contents += line + base::ASCIIToUTF16("\n");
   if (line.find(base::ASCIIToUTF16(kSkipChildren)) != base::string16::npos)
     return;
diff --git a/content/browser/accessibility/android_granularity_movement_browsertest.cc b/content/browser/accessibility/android_granularity_movement_browsertest.cc
index 9ece9acc..a12e18a4 100644
--- a/content/browser/accessibility/android_granularity_movement_browsertest.cc
+++ b/content/browser/accessibility/android_granularity_movement_browsertest.cc
@@ -149,9 +149,7 @@
   GURL url("data:text/html,"
            "<body>"
            "<p>One, two, three!</p>"
-           "<p>"
            "<button aria-label='Seven, eight, nine!'>Four, five, six!</button>"
-           "</p>"
            "</body></html>");
   BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
   ASSERT_EQ(2U, root->PlatformChildCount());
@@ -177,9 +175,7 @@
   GURL url("data:text/html,"
            "<body>"
            "<p>One, two, three!</p>"
-           "<p>"
            "<button aria-label='Seven, eight, nine!'>Four, five, six!</button>"
-           "</p>"
            "</body></html>");
   BrowserAccessibility* root = LoadUrlAndGetAccessibilityRoot(url);
   ASSERT_EQ(2U, root->PlatformChildCount());
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 66b3cf63f..fd13b95 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -197,6 +197,12 @@
 
   NavigateToURL(shell(), GURL(url::kAboutBlankURL));
 
+  // Output the test path to help anyone who encounters a failure and needs
+  // to know where to look.
+  LOG(INFO) << "Testing: " << file_path.LossyDisplayName()
+            << (is_blink_pass_ ? " (internal Blink accessibility tree)"
+                : " (native accessibility tree for this platform)");
+
   std::string html_contents;
   base::FilePath expected_file;
   std::string expected_contents_raw;
@@ -223,13 +229,6 @@
     base::ReadFileToString(expected_file, &expected_contents_raw);
   }
 
-  // Output the test path to help anyone who encounters a failure and needs
-  // to know where to look.
-  LOG(INFO) << "Testing: "
-            << file_path.NormalizePathSeparatorsTo('/').LossyDisplayName();
-  LOG(INFO) << "Expected output: "
-            << expected_file.NormalizePathSeparatorsTo('/').LossyDisplayName();
-
   // Tolerate Windows-style line endings (\r\n) in the expected file:
   // normalize by deleting all \r from the file (if any) to leave only \n.
   std::string expected_contents;
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index bcb8464..461081dc 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/pickle.h"
 #include "base/strings/utf_string_conversions.h"
@@ -217,7 +218,7 @@
     return;
   current_tooltip_text_ = tooltip_text;
 
-  SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
+  SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_SetTooltipText>(
       browser_plugin_instance_id_, tooltip_text));
 }
 
@@ -393,8 +394,8 @@
 }
 
 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
-  SendMessageToEmbedder(
-      new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
+  SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_SetMouseLock>(
+      browser_plugin_instance_id(), allow));
 }
 
 void BrowserPluginGuest::SetChildFrameSurface(
@@ -403,7 +404,7 @@
     float scale_factor,
     const cc::SurfaceSequence& sequence) {
   has_attached_since_surface_set_ = false;
-  SendMessageToEmbedder(new BrowserPluginMsg_SetChildFrameSurface(
+  SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_SetChildFrameSurface>(
       browser_plugin_instance_id(), surface_id, frame_size, scale_factor,
       sequence));
 }
@@ -492,7 +493,8 @@
   return screen_pos;
 }
 
-void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
+void BrowserPluginGuest::SendMessageToEmbedder(
+    std::unique_ptr<IPC::Message> msg) {
   // During tests, attache() may be true when there is no owner_web_contents_;
   // in this case just queue any messages we receive.
   if (!attached() || !owner_web_contents_) {
@@ -501,10 +503,10 @@
     // As a result, we must save all these IPCs until attachment and then
     // forward them so that the embedder gets a chance to see and process
     // the load events.
-    pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
+    pending_messages_.push_back(std::move(msg));
     return;
   }
-  owner_web_contents_->Send(msg);
+  owner_web_contents_->Send(msg.release());
 }
 
 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
@@ -555,12 +557,12 @@
 // TODO(wjmaclean): Replace this approach with ones based on std::function
 // as in https://codereview.chromium.org/1404353004/ once all Chrome platforms
 // support this. https://crbug.com/544212
-IPC::Message* BrowserPluginGuest::UpdateInstanceIdIfNecessary(
-    IPC::Message* msg) const {
-  DCHECK(msg);
+std::unique_ptr<IPC::Message> BrowserPluginGuest::UpdateInstanceIdIfNecessary(
+    std::unique_ptr<IPC::Message> msg) const {
+  DCHECK(msg.get());
 
   int msg_browser_plugin_instance_id = browser_plugin::kInstanceIDNone;
-  base::PickleIterator iter(*msg);
+  base::PickleIterator iter(*msg.get());
   if (!iter.ReadInt(&msg_browser_plugin_instance_id) ||
       msg_browser_plugin_instance_id != browser_plugin::kInstanceIDNone) {
     return msg;
@@ -588,8 +590,7 @@
   CHECK(write_success)
       << "Unexpected failure writing remaining IPC::Message payload.";
 
-  delete msg;
-  return new_msg.release();
+  return new_msg;
 }
 
 void BrowserPluginGuest::SendQueuedMessages() {
@@ -597,10 +598,10 @@
     return;
 
   while (!pending_messages_.empty()) {
-    linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
+    std::unique_ptr<IPC::Message> message_ptr =
+        std::move(pending_messages_.front());
     pending_messages_.pop_front();
-    SendMessageToEmbedder(
-        UpdateInstanceIdIfNecessary(message_ptr.release()));
+    SendMessageToEmbedder(UpdateInstanceIdIfNecessary(std::move(message_ptr)));
   }
 }
 
@@ -643,8 +644,8 @@
   // associated BrowserPlugin know. We only need to send this if we're attached,
   // as guest_crashed_ is cleared automatically on attach anyways.
   if (attached()) {
-    SendMessageToEmbedder(
-        new BrowserPluginMsg_GuestReady(browser_plugin_instance_id()));
+    SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_GuestReady>(
+        browser_plugin_instance_id()));
   }
 
   RenderWidgetHostImpl::From(rvh->GetWidget())
@@ -653,8 +654,8 @@
 }
 
 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
-  SendMessageToEmbedder(
-      new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
+  SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_GuestGone>(
+      browser_plugin_instance_id()));
   switch (status) {
 #if defined(OS_CHROMEOS)
     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
@@ -955,8 +956,8 @@
 }
 
 void BrowserPluginGuest::OnUnlockMouse() {
-  SendMessageToEmbedder(
-      new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
+  SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_SetMouseLock>(
+      browser_plugin_instance_id(), false));
 }
 
 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
@@ -978,7 +979,7 @@
 
 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
   SendMessageToEmbedder(
-      new BrowserPluginMsg_ShouldAcceptTouchEvents(
+      base::MakeUnique<BrowserPluginMsg_ShouldAcceptTouchEvents>(
           browser_plugin_instance_id(), accept));
 }
 
@@ -1007,8 +1008,8 @@
 }
 
 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
-  SendMessageToEmbedder(
-      new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
+  SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_AdvanceFocus>(
+      browser_plugin_instance_id(), reverse));
 }
 
 void BrowserPluginGuest::OnTextInputStateChanged(const TextInputState& params) {
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index b99654e..fa184a6 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -21,11 +21,11 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <queue>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -202,7 +202,7 @@
 
   // Helper to send messages to embedder. If this guest is not yet attached,
   // then IPCs will be queued until attachment.
-  void SendMessageToEmbedder(IPC::Message* msg);
+  void SendMessageToEmbedder(std::unique_ptr<IPC::Message> msg);
 
   // Returns whether the guest is attached to an embedder.
   bool attached() const { return attached_; }
@@ -381,7 +381,8 @@
   // the input was created with browser_plugin::kInstanceIdNone, else it returns
   // the input message unmodified. If no current browser_plugin_instance_id()
   // is set, or anything goes wrong, the input message is returned.
-  IPC::Message* UpdateInstanceIdIfNecessary(IPC::Message* msg) const;
+  std::unique_ptr<IPC::Message> UpdateInstanceIdIfNecessary(
+      std::unique_ptr<IPC::Message> msg) const;
 
   // Forwards all messages from the |pending_messages_| queue to the embedder.
   void SendQueuedMessages();
@@ -447,7 +448,7 @@
 
   // This is a queue of messages that are destined to be sent to the embedder
   // once the guest is attached to a particular embedder.
-  std::deque<linked_ptr<IPC::Message> > pending_messages_;
+  std::deque<std::unique_ptr<IPC::Message>> pending_messages_;
 
   BrowserPluginGuestDelegate* const delegate_;
 
diff --git a/content/browser/download/base_file.h b/content/browser/download/base_file.h
index b247057e..8351c49 100644
--- a/content/browser/download/base_file.h
+++ b/content/browser/download/base_file.h
@@ -16,7 +16,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/download_interrupt_reasons.h"
diff --git a/content/browser/frame_host/render_widget_host_view_guest.cc b/content/browser/frame_host/render_widget_host_view_guest.cc
index 6454b58..2c924c1 100644
--- a/content/browser/frame_host/render_widget_host_view_guest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest.cc
@@ -406,7 +406,7 @@
     if (rwhvb)
       rwhvb->UpdateCursor(cursor);
   } else {
-    guest_->SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(
+    guest_->SendMessageToEmbedder(base::MakeUnique<BrowserPluginMsg_SetCursor>(
         guest_->browser_plugin_instance_id(), cursor));
   }
 }
diff --git a/content/browser/media/midi_host.cc b/content/browser/media/midi_host.cc
index af57a91..ed01c71 100644
--- a/content/browser/media/midi_host.cc
+++ b/content/browser/media/midi_host.cc
@@ -39,6 +39,7 @@
 using midi::MidiPortInfo;
 using midi::kSysExByte;
 using midi::kEndOfSysExByte;
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 MidiHost::MidiHost(int renderer_process_id,
@@ -161,13 +162,11 @@
   Send(new MidiMsg_AddOutputPort(info));
 }
 
-void MidiHost::SetInputPortState(uint32_t port,
-                                 midi::MidiPortState state) {
+void MidiHost::SetInputPortState(uint32_t port, PortState state) {
   Send(new MidiMsg_SetInputPortState(port, state));
 }
 
-void MidiHost::SetOutputPortState(uint32_t port,
-                                  midi::MidiPortState state) {
+void MidiHost::SetOutputPortState(uint32_t port, PortState state) {
   Send(new MidiMsg_SetOutputPortState(port, state));
 }
 
diff --git a/content/browser/media/midi_host.h b/content/browser/media/midi_host.h
index 993a06c..95e69031f 100644
--- a/content/browser/media/midi_host.h
+++ b/content/browser/media/midi_host.h
@@ -45,10 +45,8 @@
   void CompleteStartSession(midi::mojom::Result result) override;
   void AddInputPort(const midi::MidiPortInfo& info) override;
   void AddOutputPort(const midi::MidiPortInfo& info) override;
-  void SetInputPortState(uint32_t port,
-                         midi::MidiPortState state) override;
-  void SetOutputPortState(uint32_t port,
-                          midi::MidiPortState state) override;
+  void SetInputPortState(uint32_t port, midi::mojom::PortState state) override;
+  void SetOutputPortState(uint32_t port, midi::mojom::PortState state) override;
   void ReceiveMidiData(uint32_t port,
                        const uint8_t* data,
                        size_t length,
diff --git a/content/browser/media/midi_host_unittest.cc b/content/browser/media/midi_host_unittest.cc
index b880d82..866d4469 100644
--- a/content/browser/media/midi_host_unittest.cc
+++ b/content/browser/media/midi_host_unittest.cc
@@ -19,6 +19,8 @@
 namespace content {
 namespace {
 
+using midi::mojom::PortState;
+
 const uint8_t kNoteOn[] = {0x90, 0x3c, 0x7f};
 const int kRenderProcessId = 0;
 
@@ -90,7 +92,7 @@
     const std::string manufacturer("yukatan");
     const std::string name("doki-doki-pi-pine");
     const std::string version("3.14159265359");
-    midi::MidiPortState state = midi::MIDI_PORT_CONNECTED;
+    PortState state = PortState::CONNECTED;
     midi::MidiPortInfo info(id, manufacturer, name, version, state);
 
     host_->AddOutputPort(info);
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h
index 4b8d5bcb..865b29f 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -30,7 +30,6 @@
       int compositor_frame_sink_id,
       bool is_swap_ack,
       const cc::ReturnedResourceArray& resources) = 0;
-  virtual void BrowserCompositorMacOnLostCompositorResources() = 0;
   virtual void BrowserCompositorMacSendBeginFrame(
       const cc::BeginFrameArgs& args) = 0;
 };
@@ -110,7 +109,6 @@
       int compositor_frame_sink_id,
       bool is_swap_ack,
       const cc::ReturnedResourceArray& resources) override;
-  void DelegatedFrameHostOnLostCompositorResources() override;
   void SetBeginFrameSource(cc::BeginFrameSource* source) override;
   bool IsAutoResizeEnabled() const override;
 
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index 3ec7423..923853af 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -445,10 +445,6 @@
       compositor_frame_sink_id, is_swap_ack, resources);
 }
 
-void BrowserCompositorMac::DelegatedFrameHostOnLostCompositorResources() {
-  client_->BrowserCompositorMacOnLostCompositorResources();
-}
-
 void BrowserCompositorMac::SetBeginFrameSource(cc::BeginFrameSource* source) {
   if (begin_frame_source_ && needs_begin_frames_)
     begin_frame_source_->RemoveObserver(this);
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 413b7da..3fe2150 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -825,8 +825,6 @@
     EvictDelegatedFrame();
   idle_frame_subscriber_textures_.clear();
   yuv_readback_pipeline_.reset();
-
-  client_->DelegatedFrameHostOnLostCompositorResources();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index e217220..10c5f77 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -72,7 +72,6 @@
       int compositor_frame_sink_id,
       bool is_swap_ack,
       const cc::ReturnedResourceArray& resources) = 0;
-  virtual void DelegatedFrameHostOnLostCompositorResources() = 0;
 
   virtual void SetBeginFrameSource(cc::BeginFrameSource* source) = 0;
   virtual bool IsAutoResizeEnabled() const = 0;
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 918630c..daaa731 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -520,9 +520,9 @@
 void VideoCaptureManager::OnDeviceStarted(
     int serial_id,
     std::unique_ptr<VideoCaptureDevice> device) {
+  DVLOG(3) << __func__;
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(serial_id, device_start_queue_.begin()->serial_id());
-  DVLOG(3) << __func__;
   if (device_start_queue_.front().abort_start()) {
     // |device| can be null if creation failed in
     // DoStartDeviceCaptureOnDeviceThread.
@@ -549,14 +549,14 @@
       MaybePostDesktopCaptureWindowId(session_id);
     }
 
-    auto request = photo_request_queue_.begin();
-    while(request != photo_request_queue_.end()) {
+    auto it = photo_request_queue_.begin();
+    while (it != photo_request_queue_.end()) {
+      auto request = it++;
       DeviceEntry* maybe_entry = GetDeviceEntryBySessionId(request->first);
       if (maybe_entry && maybe_entry->video_capture_device()) {
         request->second.Run(maybe_entry->video_capture_device());
         photo_request_queue_.erase(request);
       }
-      ++request;
     }
   }
 
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 83afa13..a89e9453 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -14,7 +14,6 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner_helpers.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 042a935..1eaac44 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -2956,10 +2956,6 @@
       host_->GetRoutingID(), compositor_frame_sink_id, is_swap_ack, resources));
 }
 
-void RenderWidgetHostViewAura::DelegatedFrameHostOnLostCompositorResources() {
-  host_->ScheduleComposite();
-}
-
 void RenderWidgetHostViewAura::SetBeginFrameSource(
     cc::BeginFrameSource* source) {
   if (begin_frame_source_ && added_frame_observer_) {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 84b07cf..4db4a27 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -17,7 +17,6 @@
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
@@ -462,7 +461,6 @@
       int compositor_frame_sink_id,
       bool is_swap_ack,
       const cc::ReturnedResourceArray& resources) override;
-  void DelegatedFrameHostOnLostCompositorResources() override;
   void SetBeginFrameSource(cc::BeginFrameSource* source) override;
   bool IsAutoResizeEnabled() const override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index a4b400f..ccb3e90 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -458,7 +458,6 @@
       int compositor_frame_sink_id,
       bool is_swap_ack,
       const cc::ReturnedResourceArray& resources) override;
-  void BrowserCompositorMacOnLostCompositorResources() override;
   void BrowserCompositorMacSendBeginFrame(
       const cc::BeginFrameArgs& args) override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 8a400e7..cc31931f 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -410,10 +410,6 @@
       is_swap_ack, resources));
 }
 
-void RenderWidgetHostViewMac::BrowserCompositorMacOnLostCompositorResources() {
-  render_widget_host_->ScheduleComposite();
-}
-
 void RenderWidgetHostViewMac::BrowserCompositorMacSendBeginFrame(
     const cc::BeginFrameArgs& args) {
   needs_flush_input_ = false;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 8fafdaeb..fb769b94 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1324,6 +1324,10 @@
   last_active_time_ = last_active_time;
 }
 
+base::TimeTicks WebContentsImpl::GetLastHiddenTime() const {
+  return last_hidden_time_;
+}
+
 void WebContentsImpl::WasShown() {
   controller_.SetActive(true);
 
@@ -1364,6 +1368,8 @@
     SendPageMessage(new PageMsg_WasHidden(MSG_ROUTING_NONE));
   }
 
+  last_hidden_time_ = base::TimeTicks::Now();
+
   for (auto& observer : observers_)
     observer.WasHidden();
 
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 3afb1aa..000a931 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -327,6 +327,7 @@
   void NotifyNavigationStateChanged(InvalidateTypes changed_flags) override;
   base::TimeTicks GetLastActiveTime() const override;
   void SetLastActiveTime(base::TimeTicks last_active_time) override;
+  base::TimeTicks GetLastHiddenTime() const override;
   void WasShown() override;
   void WasHidden() override;
   bool NeedToFireBeforeUnload() override;
@@ -1270,6 +1271,10 @@
   // the WebContents creation time.
   base::TimeTicks last_active_time_;
 
+  // The time that this WebContents was last made hidden. The initial value is
+  // zero.
+  base::TimeTicks last_hidden_time_;
+
   // See description above setter.
   bool closed_by_user_gesture_;
 
diff --git a/content/common/media/midi_messages.h b/content/common/media/midi_messages.h
index 886adbe0d..4882b37 100644
--- a/content/common/media/midi_messages.h
+++ b/content/common/media/midi_messages.h
@@ -23,8 +23,7 @@
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
 #define IPC_MESSAGE_START MidiMsgStart
 
-IPC_ENUM_TRAITS_MAX_VALUE(midi::MidiPortState,
-                          midi::MIDI_PORT_STATE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(midi::mojom::PortState, midi::mojom::PortState::LAST)
 
 IPC_STRUCT_TRAITS_BEGIN(midi::MidiPortInfo)
   IPC_STRUCT_TRAITS_MEMBER(id)
@@ -58,11 +57,11 @@
 
 IPC_MESSAGE_CONTROL2(MidiMsg_SetInputPortState,
                      uint32_t /* port */,
-                     midi::MidiPortState /* state */)
+                     midi::mojom::PortState /* state */)
 
 IPC_MESSAGE_CONTROL2(MidiMsg_SetOutputPortState,
                      uint32_t /* port */,
-                     midi::MidiPortState /* state */)
+                     midi::mojom::PortState /* state */)
 
 IPC_MESSAGE_CONTROL1(MidiMsg_SessionStarted, midi::mojom::Result /* result */)
 
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 697ea3ae..7eaa252 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -402,6 +402,9 @@
   virtual base::TimeTicks GetLastActiveTime() const = 0;
   virtual void SetLastActiveTime(base::TimeTicks last_active_time) = 0;
 
+  // Get the last time that the WebContents was made hidden.
+  virtual base::TimeTicks GetLastHiddenTime() const = 0;
+
   // Invoked when the WebContents becomes shown/hidden.
   virtual void WasShown() = 0;
   virtual void WasHidden() = 0;
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc
index 8cc551e7..1c615f5 100644
--- a/content/public/test/test_launcher.cc
+++ b/content/public/test/test_launcher.cc
@@ -20,7 +20,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
index 040268d3..ebf2f51 100644
--- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
+++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -268,4 +268,75 @@
   EXPECT_EQ(3, CountAccessibilityNodesSentToBrowser());
 }
 
+TEST_F(RenderAccessibilityImplTest, DetachAccessibilityObject) {
+  // Test RenderAccessibilityImpl and make sure it sends the
+  // proper event to the browser when an object in the tree
+  // is detached, but its children are not. This can happen when
+  // a layout occurs and an anonymous render block is no longer needed.
+  std::string html =
+      "<body aria-label='Body'>"
+      "<span>1</span><span style='display:block'>2</span>"
+      "</body>";
+  LoadHTML(html.c_str());
+
+  std::unique_ptr<TestRenderAccessibilityImpl> accessibility(
+      new TestRenderAccessibilityImpl(frame()));
+  accessibility->SendPendingAccessibilityEvents();
+  EXPECT_EQ(7, CountAccessibilityNodesSentToBrowser());
+
+  // Initially, the accessibility tree looks like this:
+  //
+  //   Document
+  //   +--Body
+  //      +--Anonymous Block
+  //         +--Static Text "1"
+  //            +--Inline Text Box "1"
+  //      +--Static Text "2"
+  //         +--Inline Text Box "2"
+  WebDocument document = view()->GetWebView()->mainFrame()->document();
+  WebAXObject root_obj = document.accessibilityObject();
+  WebAXObject body = root_obj.childAt(0);
+  WebAXObject anonymous_block = body.childAt(0);
+  WebAXObject text_1 = anonymous_block.childAt(0);
+  WebAXObject text_2 = body.childAt(1);
+
+  // Change the display of the second 'span' back to inline, which causes the
+  // anonymous block to be destroyed.
+  ExecuteJavaScriptForTests(
+      "document.querySelectorAll('span')[1].style.display = 'inline';");
+  // Force layout now.
+  ExecuteJavaScriptForTests("document.body.offsetLeft;");
+
+  // Send a childrenChanged on the body.
+  sink_->ClearMessages();
+  accessibility->HandleAXEvent(
+      body,
+      ui::AX_EVENT_CHILDREN_CHANGED);
+
+  accessibility->SendPendingAccessibilityEvents();
+
+  // Afterwards, the accessibility tree looks like this:
+  //
+  //   Document
+  //   +--Body
+  //      +--Static Text "1"
+  //         +--Inline Text Box "1"
+  //      +--Static Text "2"
+  //         +--Inline Text Box "2"
+  //
+  // We just assert that there are now four nodes in the
+  // accessibility tree and that only three nodes needed
+  // to be updated (the body, the static text 1, and
+  // the static text 2).
+
+  AccessibilityHostMsg_EventParams event;
+  GetLastAccEvent(&event);
+  ASSERT_EQ(5U, event.update.nodes.size());
+
+  EXPECT_EQ(body.axID(), event.update.nodes[0].id);
+  EXPECT_EQ(text_1.axID(), event.update.nodes[1].id);
+  // The third event is to update text_2, but its id changes
+  // so we don't have a test expectation for it.
+}
+
 }  // namespace content
diff --git a/content/renderer/gpu/stream_texture_host_android.cc b/content/renderer/gpu/stream_texture_host_android.cc
index 208385d..e03a16d 100644
--- a/content/renderer/gpu/stream_texture_host_android.cc
+++ b/content/renderer/gpu/stream_texture_host_android.cc
@@ -4,6 +4,7 @@
 
 #include "content/renderer/gpu/stream_texture_host_android.h"
 
+#include "base/unguessable_token.h"
 #include "content/renderer/render_thread_impl.h"
 #include "gpu/ipc/client/gpu_channel_host.h"
 #include "gpu/ipc/common/gpu_messages.h"
@@ -11,8 +12,9 @@
 
 namespace content {
 
-StreamTextureHost::StreamTextureHost(scoped_refptr<gpu::GpuChannelHost> channel)
-    : stream_id_(0),
+StreamTextureHost::StreamTextureHost(scoped_refptr<gpu::GpuChannelHost> channel,
+                                     int32_t route_id)
+    : route_id_(route_id),
       listener_(NULL),
       channel_(std::move(channel)),
       weak_ptr_factory_(this) {
@@ -20,17 +22,15 @@
 }
 
 StreamTextureHost::~StreamTextureHost() {
-  if (channel_.get() && stream_id_)
-    channel_->RemoveRoute(stream_id_);
+  if (channel_.get() && route_id_)
+    channel_->RemoveRoute(route_id_);
 }
 
-bool StreamTextureHost::BindToCurrentThread(int32_t stream_id,
-                                            Listener* listener) {
+bool StreamTextureHost::BindToCurrentThread(Listener* listener) {
   listener_ = listener;
-  if (channel_.get() && stream_id && !stream_id_) {
-    stream_id_ = stream_id;
-    channel_->AddRoute(stream_id, weak_ptr_factory_.GetWeakPtr());
-    channel_->Send(new GpuStreamTextureMsg_StartListening(stream_id));
+  if (channel_.get() && route_id_) {
+    channel_->AddRoute(route_id_, weak_ptr_factory_.GetWeakPtr());
+    channel_->Send(new GpuStreamTextureMsg_StartListening(route_id_));
     return true;
   }
 
@@ -56,4 +56,24 @@
     listener_->OnFrameAvailable();
 }
 
+void StreamTextureHost::EstablishPeer(int player_id, int frame_id) {
+  if (route_id_) {
+    channel_->Send(
+        new GpuStreamTextureMsg_EstablishPeer(route_id_, frame_id, player_id));
+  }
+}
+
+void StreamTextureHost::SetStreamTextureSize(const gfx::Size& size) {
+  if (route_id_)
+    channel_->Send(new GpuStreamTextureMsg_SetSize(route_id_, size));
+}
+
+void StreamTextureHost::ForwardStreamTextureForSurfaceRequest(
+    const base::UnguessableToken& request_token) {
+  if (route_id_) {
+    channel_->Send(new GpuStreamTextureMsg_ForwardForSurfaceRequest(
+        route_id_, request_token));
+  }
+}
+
 }  // namespace content
diff --git a/content/renderer/gpu/stream_texture_host_android.h b/content/renderer/gpu/stream_texture_host_android.h
index 06fcf0f3..6dc480b0 100644
--- a/content/renderer/gpu/stream_texture_host_android.h
+++ b/content/renderer/gpu/stream_texture_host_android.h
@@ -13,6 +13,10 @@
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_message.h"
 
+namespace base {
+class UnguessableToken;
+}
+
 namespace gfx {
 class Size;
 }
@@ -29,7 +33,8 @@
 // StreamTextureProxy.
 class StreamTextureHost : public IPC::Listener {
  public:
-  explicit StreamTextureHost(scoped_refptr<gpu::GpuChannelHost> channel);
+  explicit StreamTextureHost(scoped_refptr<gpu::GpuChannelHost> channel,
+                             int32_t route_id);
   ~StreamTextureHost() override;
 
   // Listener class that is listening to the stream texture updates. It is
@@ -40,17 +45,22 @@
     virtual ~Listener() {}
   };
 
-  bool BindToCurrentThread(int32_t stream_id, Listener* listener);
+  bool BindToCurrentThread(Listener* listener);
 
   // IPC::Channel::Listener implementation:
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnChannelError() override;
 
+  void EstablishPeer(int player_id, int frame_id);
+  void SetStreamTextureSize(const gfx::Size& size);
+  void ForwardStreamTextureForSurfaceRequest(
+      const base::UnguessableToken& request_token);
+
  private:
   // Message handlers:
   void OnFrameAvailable();
 
-  int stream_id_;
+  int32_t route_id_;
   Listener* listener_;
   scoped_refptr<gpu::GpuChannelHost> channel_;
   base::WeakPtrFactory<StreamTextureHost> weak_ptr_factory_;
diff --git a/content/renderer/media/android/stream_texture_factory.cc b/content/renderer/media/android/stream_texture_factory.cc
index c8c015a..dc785add 100644
--- a/content/renderer/media/android/stream_texture_factory.cc
+++ b/content/renderer/media/android/stream_texture_factory.cc
@@ -35,7 +35,6 @@
 }
 
 void StreamTextureProxy::BindToTaskRunner(
-    int32_t stream_id,
     const base::Closure& received_frame_cb,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   DCHECK(task_runner.get());
@@ -48,18 +47,17 @@
   }
 
   if (task_runner->BelongsToCurrentThread()) {
-    BindOnThread(stream_id);
+    BindOnThread();
     return;
   }
   // Unretained is safe here only because the object is deleted on |loop_|
   // thread.
-  task_runner->PostTask(FROM_HERE,
-                        base::Bind(&StreamTextureProxy::BindOnThread,
-                                   base::Unretained(this), stream_id));
+  task_runner->PostTask(FROM_HERE, base::Bind(&StreamTextureProxy::BindOnThread,
+                                              base::Unretained(this)));
 }
 
-void StreamTextureProxy::BindOnThread(int32_t stream_id) {
-  host_->BindToCurrentThread(stream_id, this);
+void StreamTextureProxy::BindOnThread() {
+  host_->BindToCurrentThread(this);
 }
 
 void StreamTextureProxy::OnFrameAvailable() {
@@ -68,6 +66,19 @@
     received_frame_cb_.Run();
 }
 
+void StreamTextureProxy::EstablishPeer(int player_id, int frame_id) {
+  host_->EstablishPeer(player_id, frame_id);
+}
+
+void StreamTextureProxy::SetStreamTextureSize(const gfx::Size& size) {
+  host_->SetStreamTextureSize(size);
+}
+
+void StreamTextureProxy::ForwardStreamTextureForSurfaceRequest(
+    const base::UnguessableToken& request_token) {
+  host_->ForwardStreamTextureForSurfaceRequest(request_token);
+}
+
 // static
 scoped_refptr<StreamTextureFactory> StreamTextureFactory::Create(
     scoped_refptr<ContextProviderCommandBuffer> context_provider) {
@@ -83,44 +94,40 @@
 
 StreamTextureFactory::~StreamTextureFactory() {}
 
-StreamTextureProxy* StreamTextureFactory::CreateProxy() {
-  StreamTextureHost* host = new StreamTextureHost(channel_);
+StreamTextureProxy* StreamTextureFactory::CreateProxy(
+    unsigned texture_target,
+    unsigned* texture_id,
+    gpu::Mailbox* texture_mailbox) {
+  int32_t route_id =
+      CreateStreamTexture(texture_target, texture_id, texture_mailbox);
+  if (!route_id)
+    return nullptr;
+  StreamTextureHost* host = new StreamTextureHost(channel_, route_id);
   return new StreamTextureProxy(host);
 }
 
-void StreamTextureFactory::EstablishPeer(int32_t stream_id,
-                                             int player_id,
-                                             int frame_id) {
-  channel_->Send(
-      new GpuStreamTextureMsg_EstablishPeer(stream_id, frame_id, player_id));
-}
-
-void StreamTextureFactory::ForwardStreamTextureForSurfaceRequest(
-    int32_t stream_id,
-    const base::UnguessableToken& request_token) {
-  channel_->Send(new GpuStreamTextureMsg_ForwardForSurfaceRequest(
-      stream_id, request_token));
-}
-
 unsigned StreamTextureFactory::CreateStreamTexture(
     unsigned texture_target,
     unsigned* texture_id,
     gpu::Mailbox* texture_mailbox) {
-  GLuint stream_id = 0;
+  GLuint route_id = 0;
   gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
   gl->GenTextures(1, texture_id);
   gl->ShallowFlushCHROMIUM();
-  stream_id = context_provider_->GetCommandBufferProxy()->CreateStreamTexture(
+  route_id = context_provider_->GetCommandBufferProxy()->CreateStreamTexture(
       *texture_id);
-  gl->GenMailboxCHROMIUM(texture_mailbox->name);
-  gl->ProduceTextureDirectCHROMIUM(
-      *texture_id, texture_target, texture_mailbox->name);
-  return stream_id;
-}
-
-void StreamTextureFactory::SetStreamTextureSize(int32_t stream_id,
-                                                    const gfx::Size& size) {
-  channel_->Send(new GpuStreamTextureMsg_SetSize(stream_id, size));
+  if (!route_id) {
+    gl->DeleteTextures(1, texture_id);
+    // Flush to ensure that the stream texture gets deleted in a timely fashion.
+    gl->ShallowFlushCHROMIUM();
+    *texture_id = 0;
+    *texture_mailbox = gpu::Mailbox();
+  } else {
+    gl->GenMailboxCHROMIUM(texture_mailbox->name);
+    gl->ProduceTextureDirectCHROMIUM(*texture_id, texture_target,
+                                     texture_mailbox->name);
+  }
+  return route_id;
 }
 
 gpu::gles2::GLES2Interface* StreamTextureFactory::ContextGL() {
diff --git a/content/renderer/media/android/stream_texture_factory.h b/content/renderer/media/android/stream_texture_factory.h
index 7ba8cbd..a474d24 100644
--- a/content/renderer/media/android/stream_texture_factory.h
+++ b/content/renderer/media/android/stream_texture_factory.h
@@ -41,13 +41,27 @@
   // provided callback will be run on. This can be called on any thread, but
   // must be called with the same |task_runner| every time.
   void BindToTaskRunner(
-      int32_t stream_id,
       const base::Closure& received_frame_cb,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // StreamTextureHost::Listener implementation:
   void OnFrameAvailable() override;
 
+  // Set the streamTexture size.
+  void SetStreamTextureSize(const gfx::Size& size);
+
+  // Send an IPC message to the browser process to request a java surface
+  // object for the given route_id. After the the surface is created,
+  // it will be passed back to the WebMediaPlayerAndroid object identified by
+  // the player_id.
+  void EstablishPeer(int player_id, int frame_id);
+
+  // Sends an IPC to the GPU process.
+  // Asks the StreamTexture to forward its SurfaceTexture to the
+  // ScopedSurfaceRequestManager, using the gpu::ScopedSurfaceRequestConduit.
+  void ForwardStreamTextureForSurfaceRequest(
+      const base::UnguessableToken& request_token);
+
   struct Deleter {
     inline void operator()(StreamTextureProxy* ptr) const { ptr->Release(); }
   };
@@ -55,7 +69,7 @@
   friend class StreamTextureFactory;
   explicit StreamTextureProxy(StreamTextureHost* host);
 
-  void BindOnThread(int32_t stream_id);
+  void BindOnThread();
   void Release();
 
   const std::unique_ptr<StreamTextureHost> host_;
@@ -78,31 +92,17 @@
   static scoped_refptr<StreamTextureFactory> Create(
       scoped_refptr<ContextProviderCommandBuffer> context_provider);
 
-  // Create the StreamTextureProxy object.
-  StreamTextureProxy* CreateProxy();
-
-  // Send an IPC message to the browser process to request a java surface
-  // object for the given stream_id. After the the surface is created,
-  // it will be passed back to the WebMediaPlayerAndroid object identified by
-  // the player_id.
-  void EstablishPeer(int32_t stream_id, int player_id, int frame_id);
-
-  // Sends an IPC to the GPU process.
-  // Asks the StreamTexture to forward its SurfaceTexture to the
-  // ScopedSurfaceRequestManager, using the gpu::ScopedSurfaceRequestConduit.
-  void ForwardStreamTextureForSurfaceRequest(
-      int32_t stream_id,
-      const base::UnguessableToken& request_token);
-
-  // Creates a gpu::StreamTexture and returns its id.  Sets |*texture_id| to the
-  // client-side id of the gpu::StreamTexture. The texture is produced into
-  // a mailbox so it can be shipped in a VideoFrame.
-  unsigned CreateStreamTexture(unsigned texture_target,
-                               unsigned* texture_id,
-                               gpu::Mailbox* texture_mailbox);
-
-  // Set the streamTexture size for the given stream Id.
-  void SetStreamTextureSize(int32_t texture_id, const gfx::Size& size);
+  // Create the StreamTextureProxy object. This internally calls
+  // CreateSteamTexture with the recieved arguments. CreateSteamTexture
+  // generates a texture and stores it in  *texture_id, the texture is produced
+  // into a mailbox so it can be shipped in a VideoFrame, it creates a
+  // gpu::StreamTexture and returns its route_id. If this route_id is  invalid
+  // nullptr is returned and *texture_id will be set to 0. If the route_id is
+  // valid it returns StreamTextureProxy object. The caller needs to take care
+  // of cleaning up the texture_id.
+  StreamTextureProxy* CreateProxy(unsigned texture_target,
+                                  unsigned* texture_id,
+                                  gpu::Mailbox* texture_mailbox);
 
   gpu::gles2::GLES2Interface* ContextGL();
 
@@ -111,6 +111,12 @@
   StreamTextureFactory(
       scoped_refptr<ContextProviderCommandBuffer> context_provider);
   ~StreamTextureFactory();
+  // Creates a gpu::StreamTexture and returns its id.  Sets |*texture_id| to the
+  // client-side id of the gpu::StreamTexture. The texture is produced into
+  // a mailbox so it can be shipped in a VideoFrame.
+  unsigned CreateStreamTexture(unsigned texture_target,
+                               unsigned* texture_id,
+                               gpu::Mailbox* texture_mailbox);
 
   scoped_refptr<ContextProviderCommandBuffer> context_provider_;
   scoped_refptr<gpu::GpuChannelHost> channel_;
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.cc b/content/renderer/media/android/stream_texture_wrapper_impl.cc
index 0662a61..db0428d 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.cc
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.cc
@@ -33,7 +33,6 @@
     scoped_refptr<StreamTextureFactory> factory,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
     : texture_id_(0),
-      stream_id_(0),
       factory_(factory),
       main_task_runner_(main_task_runner),
       weak_factory_(this) {}
@@ -41,7 +40,7 @@
 StreamTextureWrapperImpl::~StreamTextureWrapperImpl() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
-  if (stream_id_) {
+  if (texture_id_) {
     GLES2Interface* gl = factory_->ContextGL();
     gl->DeleteTextures(1, &texture_id_);
     // Flush to ensure that the stream texture gets deleted in a timely fashion.
@@ -106,8 +105,7 @@
 
 void StreamTextureWrapperImpl::ForwardStreamTextureForSurfaceRequest(
     const base::UnguessableToken& request_token) {
-  return factory_->ForwardStreamTextureForSurfaceRequest(stream_id_,
-                                                         request_token);
+  stream_texture_proxy_->ForwardStreamTextureForSurfaceRequest(request_token);
 }
 
 void StreamTextureWrapperImpl::SetCurrentFrameInternal(
@@ -132,7 +130,7 @@
   natural_size_ = new_size;
 
   ReallocateVideoFrame(new_size);
-  factory_->SetStreamTextureSize(stream_id_, new_size);
+  stream_texture_proxy_->SetStreamTextureSize(new_size);
 }
 
 void StreamTextureWrapperImpl::Initialize(
@@ -157,13 +155,14 @@
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DVLOG(2) << __FUNCTION__;
 
-  stream_texture_proxy_.reset(factory_->CreateProxy());
+  stream_texture_proxy_.reset(factory_->CreateProxy(
+      kGLTextureExternalOES, &texture_id_, &texture_mailbox_));
+  if (!stream_texture_proxy_)
+    return;
 
-  stream_id_ = factory_->CreateStreamTexture(kGLTextureExternalOES,
-                                             &texture_id_, &texture_mailbox_);
   ReallocateVideoFrame(natural_size_);
 
-  stream_texture_proxy_->BindToTaskRunner(stream_id_, received_frame_cb,
+  stream_texture_proxy_->BindToTaskRunner(received_frame_cb,
                                           compositor_task_runner_);
 
   // TODO(tguilbert): Register the surface properly. See crbug.com/627658.
diff --git a/content/renderer/media/android/stream_texture_wrapper_impl.h b/content/renderer/media/android/stream_texture_wrapper_impl.h
index 25f881ba..a7e2bae4 100644
--- a/content/renderer/media/android/stream_texture_wrapper_impl.h
+++ b/content/renderer/media/android/stream_texture_wrapper_impl.h
@@ -101,9 +101,6 @@
   // GL texture mailbox for |texture_id_|.
   gpu::Mailbox texture_mailbox_;
 
-  // Stream texture ID.
-  unsigned stream_id_;
-
   // Object for calling back the compositor thread to repaint the video when a
   // frame is available. It should be bound to |compositor_task_runner_|.
   ScopedStreamTextureProxy stream_texture_proxy_;
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 14c38d01..2a38656a 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -151,7 +151,6 @@
       network_state_(WebMediaPlayer::NetworkStateEmpty),
       ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
       texture_id_(0),
-      stream_id_(0),
       is_player_initialized_(false),
       is_playing_(false),
       is_play_pending_(false),
@@ -200,14 +199,13 @@
 
   player_manager_->UnregisterMediaPlayer(player_id_);
 
-  if (stream_id_) {
+  if (texture_id_) {
     GLES2Interface* gl = stream_texture_factory_->ContextGL();
     gl->DeleteTextures(1, &texture_id_);
     // Flush to ensure that the stream texture gets deleted in a timely fashion.
     gl->ShallowFlushCHROMIUM();
     texture_id_ = 0;
     texture_mailbox_ = gpu::Mailbox();
-    stream_id_ = 0;
   }
 
   {
@@ -805,8 +803,8 @@
   // For hidden video element (with style "display:none"), ensure the texture
   // size is set.
   if (!is_remote_ && cached_stream_texture_size_ != natural_size_) {
-    stream_texture_factory_->SetStreamTextureSize(
-        stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
+    stream_texture_proxy_->SetStreamTextureSize(
+        gfx::Size(natural_size_.width, natural_size_.height));
     cached_stream_texture_size_ = natural_size_;
   }
 
@@ -1108,14 +1106,13 @@
 void WebMediaPlayerAndroid::RemoveSurfaceTextureAndProxy() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 
-  if (stream_id_) {
+  if (texture_id_) {
     GLES2Interface* gl = stream_texture_factory_->ContextGL();
     gl->DeleteTextures(1, &texture_id_);
     // Flush to ensure that the stream texture gets deleted in a timely fashion.
     gl->ShallowFlushCHROMIUM();
     texture_id_ = 0;
     texture_mailbox_ = gpu::Mailbox();
-    stream_id_ = 0;
   }
   stream_texture_proxy_.reset();
   needs_establish_peer_ =
@@ -1137,7 +1134,7 @@
                    base::Unretained(client));
   }
 
-  stream_texture_proxy_->BindToTaskRunner(stream_id_, frame_received_cb,
+  stream_texture_proxy_->BindToTaskRunner(frame_received_cb,
                                           compositor_task_runner_);
 }
 
@@ -1155,13 +1152,14 @@
   if (!needs_establish_peer_)
     return;
 
-  stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
-  if (stream_texture_proxy_) {
-    DoCreateStreamTexture();
-    ReallocateVideoFrame();
-    if (video_frame_provider_client_)
-      UpdateStreamTextureProxyCallback(video_frame_provider_client_);
-  }
+  DCHECK(!texture_id_);
+  stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy(
+      kGLTextureExternalOES, &texture_id_, &texture_mailbox_));
+  if (!stream_texture_proxy_)
+    return;
+  ReallocateVideoFrame();
+  if (video_frame_provider_client_)
+    UpdateStreamTextureProxyCallback(video_frame_provider_client_);
 }
 
 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
@@ -1169,27 +1167,18 @@
   if (!stream_texture_proxy_)
     return;
 
-  if (stream_texture_factory_.get() && stream_id_)
-    stream_texture_factory_->EstablishPeer(stream_id_, player_id_, frame_id_);
+  stream_texture_proxy_->EstablishPeer(player_id_, frame_id_);
 
   // Set the deferred size because the size was changed in remote mode.
   if (!is_remote_ && cached_stream_texture_size_ != natural_size_) {
-    stream_texture_factory_->SetStreamTextureSize(
-        stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
+    stream_texture_proxy_->SetStreamTextureSize(
+        gfx::Size(natural_size_.width, natural_size_.height));
     cached_stream_texture_size_ = natural_size_;
   }
 
   needs_establish_peer_ = false;
 }
 
-void WebMediaPlayerAndroid::DoCreateStreamTexture() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  DCHECK(!stream_id_);
-  DCHECK(!texture_id_);
-  stream_id_ = stream_texture_factory_->CreateStreamTexture(
-      kGLTextureExternalOES, &texture_id_, &texture_mailbox_);
-}
-
 void WebMediaPlayerAndroid::SetNeedsEstablishPeer(bool needs_establish_peer) {
   needs_establish_peer_ = needs_establish_peer;
 }
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 5492bdb..c7af8ce 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -229,7 +229,6 @@
   void UpdateNetworkState(blink::WebMediaPlayer::NetworkState state);
   void UpdateReadyState(blink::WebMediaPlayer::ReadyState state);
   void TryCreateStreamTextureProxyIfNeeded();
-  void DoCreateStreamTexture();
 
   // Helper method to reestablish the surface texture peer for android
   // media player.
@@ -348,9 +347,6 @@
   // point for when the mailbox was produced.
   gpu::Mailbox texture_mailbox_;
 
-  // Stream texture ID allocated to the video.
-  unsigned int stream_id_;
-
   // Whether the media player has been initialized.
   bool is_player_initialized_;
 
diff --git a/content/renderer/media/midi_message_filter.cc b/content/renderer/media/midi_message_filter.cc
index 8ad2004..7ac4f05 100644
--- a/content/renderer/media/midi_message_filter.cc
+++ b/content/renderer/media/midi_message_filter.cc
@@ -15,6 +15,7 @@
 #include "ipc/ipc_logging.h"
 
 using base::AutoLock;
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 // The maximum number of bytes which we're allowed to send to the browser
@@ -165,16 +166,14 @@
       base::Bind(&MidiMessageFilter::HandleAddOutputPort, this, info));
 }
 
-void MidiMessageFilter::OnSetInputPortState(uint32_t port,
-                                            midi::MidiPortState state) {
+void MidiMessageFilter::OnSetInputPortState(uint32_t port, PortState state) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   main_task_runner_->PostTask(
       FROM_HERE, base::Bind(&MidiMessageFilter::HandleSetInputPortState, this,
                             port, state));
 }
 
-void MidiMessageFilter::OnSetOutputPortState(uint32_t port,
-                                             midi::MidiPortState state) {
+void MidiMessageFilter::OnSetOutputPortState(uint32_t port, PortState state) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   main_task_runner_->PostTask(
       FROM_HERE, base::Bind(&MidiMessageFilter::HandleSetOutputPortState, this,
@@ -212,21 +211,19 @@
     if (result == Result::OK) {
       // Add the client's input and output ports.
       for (const auto& info : inputs_) {
-        client->didAddInputPort(
-            base::UTF8ToUTF16(info.id),
-            base::UTF8ToUTF16(info.manufacturer),
-            base::UTF8ToUTF16(info.name),
-            base::UTF8ToUTF16(info.version),
-            ToBlinkState(info.state));
+        client->didAddInputPort(base::UTF8ToUTF16(info.id),
+                                base::UTF8ToUTF16(info.manufacturer),
+                                base::UTF8ToUTF16(info.name),
+                                base::UTF8ToUTF16(info.version),
+                                ToBlinkState(info.state));
       }
 
       for (const auto& info : outputs_) {
-        client->didAddOutputPort(
-            base::UTF8ToUTF16(info.id),
-            base::UTF8ToUTF16(info.manufacturer),
-            base::UTF8ToUTF16(info.name),
-            base::UTF8ToUTF16(info.version),
-            ToBlinkState(info.state));
+        client->didAddOutputPort(base::UTF8ToUTF16(info.id),
+                                 base::UTF8ToUTF16(info.manufacturer),
+                                 base::UTF8ToUTF16(info.name),
+                                 base::UTF8ToUTF16(info.version),
+                                 ToBlinkState(info.state));
       }
     }
     client->didStartSession(result);
@@ -241,8 +238,7 @@
   const base::string16 manufacturer = base::UTF8ToUTF16(info.manufacturer);
   const base::string16 name = base::UTF8ToUTF16(info.name);
   const base::string16 version = base::UTF8ToUTF16(info.version);
-  const blink::WebMIDIAccessorClient::MIDIPortState state =
-      ToBlinkState(info.state);
+  const PortState state = ToBlinkState(info.state);
   for (auto* client : clients_)
     client->didAddInputPort(id, manufacturer, name, version, state);
 }
@@ -254,8 +250,7 @@
   const base::string16 manufacturer = base::UTF8ToUTF16(info.manufacturer);
   const base::string16 name = base::UTF8ToUTF16(info.name);
   const base::string16 version = base::UTF8ToUTF16(info.version);
-  const blink::WebMIDIAccessorClient::MIDIPortState state =
-      ToBlinkState(info.state);
+  const PortState state = ToBlinkState(info.state);
   for (auto* client : clients_)
     client->didAddOutputPort(id, manufacturer, name, version, state);
 }
@@ -278,18 +273,16 @@
     unacknowledged_bytes_sent_ -= bytes_sent;
 }
 
-void MidiMessageFilter::HandleSetInputPortState(
-    uint32_t port,
-    midi::MidiPortState state) {
+void MidiMessageFilter::HandleSetInputPortState(uint32_t port,
+                                                PortState state) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   inputs_[port].state = state;
   for (auto* client : clients_)
     client->didSetInputPortState(port, ToBlinkState(state));
 }
 
-void MidiMessageFilter::HandleSetOutputPortState(
-    uint32_t port,
-    midi::MidiPortState state) {
+void MidiMessageFilter::HandleSetOutputPortState(uint32_t port,
+                                                 PortState state) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   outputs_[port].state = state;
   for (auto* client : clients_)
diff --git a/content/renderer/media/midi_message_filter.h b/content/renderer/media/midi_message_filter.h
index f86d6e9..aabca4f 100644
--- a/content/renderer/media/midi_message_filter.h
+++ b/content/renderer/media/midi_message_filter.h
@@ -54,12 +54,13 @@
     return io_task_runner_.get();
   }
 
-  static blink::WebMIDIAccessorClient::MIDIPortState ToBlinkState(
-      midi::MidiPortState state) {
+  static midi::mojom::PortState ToBlinkState(midi::mojom::PortState state) {
     // "open" status is separately managed by blink per MIDIAccess instance.
-    if (state == midi::MIDI_PORT_OPENED)
-      state = midi::MIDI_PORT_CONNECTED;
-    return static_cast<blink::WebMIDIAccessorClient::MIDIPortState>(state);
+    // TODO(toyoshim): Pass through the state as is, and have a logic to convert
+    // this state to JavaScript exposing state in Blink side.
+    if (state == midi::mojom::PortState::OPENED)
+      return midi::mojom::PortState::CONNECTED;
+    return state;
   }
 
  protected:
@@ -98,8 +99,8 @@
   // These functions are called to notify the recipient that a device that is
   // notified via OnAddInputPort() or OnAddOutputPort() gets disconnected, or
   // connected again.
-  void OnSetInputPortState(uint32_t port, midi::MidiPortState state);
-  void OnSetOutputPortState(uint32_t port, midi::MidiPortState state);
+  void OnSetInputPortState(uint32_t port, midi::mojom::PortState state);
+  void OnSetOutputPortState(uint32_t port, midi::mojom::PortState state);
 
   // Called when the browser process has sent MIDI data containing one or
   // more messages.
@@ -117,9 +118,8 @@
 
   void HandleAddInputPort(midi::MidiPortInfo info);
   void HandleAddOutputPort(midi::MidiPortInfo info);
-  void HandleSetInputPortState(uint32_t port, midi::MidiPortState state);
-  void HandleSetOutputPortState(uint32_t port,
-                                midi::MidiPortState state);
+  void HandleSetInputPortState(uint32_t port, midi::mojom::PortState state);
+  void HandleSetOutputPortState(uint32_t port, midi::mojom::PortState state);
 
   void HandleDataReceived(uint32_t port,
                           const std::vector<uint8_t>& data,
diff --git a/content/renderer/media/midi_message_filter_unittest.cc b/content/renderer/media/midi_message_filter_unittest.cc
index 4e19855..45ee19b5 100644
--- a/content/renderer/media/midi_message_filter_unittest.cc
+++ b/content/renderer/media/midi_message_filter_unittest.cc
@@ -5,30 +5,32 @@
 #include "content/renderer/media/midi_message_filter.h"
 
 #include "base/message_loop/message_loop.h"
+#include "media/midi/midi_service.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
 
 namespace {
-using BlinkState = blink::WebMIDIAccessorClient::MIDIPortState;
-}  // namespace
+
+using midi::mojom::PortState;
 
 TEST(MidiMessageFilterTest, CastMidiPortState) {
   // Check if static_cast of ToMIDIPortState() just works fine for all states.
-  EXPECT_EQ(
-      BlinkState::MIDIPortStateDisconnected,
-      MidiMessageFilter::ToBlinkState(midi::MIDI_PORT_DISCONNECTED));
-  EXPECT_EQ(BlinkState::MIDIPortStateConnected,
-            MidiMessageFilter::ToBlinkState(midi::MIDI_PORT_CONNECTED));
+  EXPECT_EQ(PortState::DISCONNECTED,
+            MidiMessageFilter::ToBlinkState(PortState::DISCONNECTED));
+  EXPECT_EQ(PortState::CONNECTED,
+            MidiMessageFilter::ToBlinkState(PortState::CONNECTED));
   // Web MIDI API manages DeviceState and ConnectionState separately.
   // "open", "pending", or "closed" are managed separately for ConnectionState
   // by Blink per MIDIAccess instance. So, MIDI_PORT_OPENED in content can be
   // converted to MIDIPortStateConnected.
-  EXPECT_EQ(BlinkState::MIDIPortStateConnected,
-            MidiMessageFilter::ToBlinkState(midi::MIDI_PORT_OPENED));
+  EXPECT_EQ(PortState::CONNECTED,
+            MidiMessageFilter::ToBlinkState(PortState::OPENED));
 
   // Check if we do not have any unknown MidiPortState that is added later.
-  EXPECT_EQ(midi::MIDI_PORT_OPENED, midi::MIDI_PORT_STATE_LAST);
+  EXPECT_EQ(PortState::OPENED, PortState::LAST);
 }
 
+}  // namespace
+
 }  // namespace content
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 923db00..fda904d 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1760,6 +1760,9 @@
   } else {
     renderer_scheduler_->OnRendererForegrounded();
     record_purge_suspend_metric_closure_.Cancel();
+    record_purge_suspend_metric_closure_.Reset(
+        base::Bind(&RenderThreadImpl::RecordPurgeAndSuspendMetrics,
+                   base::Unretained(this)));
     is_renderer_suspended_ = false;
   }
 }
diff --git a/content/renderer/service_worker/embedded_worker_dispatcher.cc b/content/renderer/service_worker/embedded_worker_dispatcher.cc
index 2a9251a..e68ad20 100644
--- a/content/renderer/service_worker/embedded_worker_dispatcher.cc
+++ b/content/renderer/service_worker/embedded_worker_dispatcher.cc
@@ -77,7 +77,11 @@
 void EmbeddedWorkerDispatcher::OnStopWorker(int embedded_worker_id) {
   TRACE_EVENT0("ServiceWorker", "EmbeddedWorkerDispatcher::OnStopWorker");
   WorkerWrapper* wrapper = workers_.Lookup(embedded_worker_id);
-  DCHECK(wrapper);
+  // OnStopWorker is possible to be called twice.
+  if (!wrapper) {
+    LOG(WARNING) << "Got OnStopWorker for nonexistent worker";
+    return;
+  }
   // This should eventually call WorkerContextDestroyed. (We may need to post
   // a delayed task to forcibly abort the worker context if we find it
   // necessary)
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 4b399b88..d4f5883 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -69,7 +69,11 @@
     const StopWorkerCallback& callback) {
   DCHECK(ChildThreadImpl::current());
   DCHECK(embedded_worker_id_);
-  DCHECK(!stop_callback_);
+  // StopWorker is possible to be called twice.
+  if (stop_callback_) {
+    LOG(WARNING) << "Got StopWorker for stopping worker";
+    return;
+  }
   TRACE_EVENT0("ServiceWorker", "EmbeddedWorkerInstanceClientImpl::StopWorker");
   stop_callback_ = std::move(callback);
   dispatcher_->RecordStopWorkerTimer(embedded_worker_id_.value());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 0eccfaf..0817ac3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1388,6 +1388,7 @@
     "//media/blink",
     "//media/capture",
     "//media/midi:midi",
+    "//media/midi:mojo_cpp_sources",
     "//mojo/edk/test:test_support",
     "//mojo/public/cpp/bindings",
     "//net:extras",
diff --git a/content/test/data/accessibility/aria/aria-current-expected-win.txt b/content/test/data/accessibility/aria/aria-current-expected-win.txt
index 7aaf6fb..ccd15a9 100644
--- a/content/test/data/accessibility/aria/aria-current-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-current-expected-win.txt
@@ -1,11 +1,13 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_LINK name='Section one' FOCUSABLE
-++++ROLE_SYSTEM_STATICTEXT name='Section one'
-++ROLE_SYSTEM_LINK name='Section two' FOCUSABLE
-++++ROLE_SYSTEM_STATICTEXT name='Section two'
-++ROLE_SYSTEM_LINK name='Section three' FOCUSABLE current:location
-++++ROLE_SYSTEM_STATICTEXT name='Section three'
-++ROLE_SYSTEM_WHITESPACE name='<newline>'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_LINK name='Section one' FOCUSABLE
+++++++ROLE_SYSTEM_STATICTEXT name='Section one'
+++++ROLE_SYSTEM_LINK name='Section two' FOCUSABLE
+++++++ROLE_SYSTEM_STATICTEXT name='Section two'
+++++ROLE_SYSTEM_LINK name='Section three' FOCUSABLE current:location
+++++++ROLE_SYSTEM_STATICTEXT name='Section three'
+++++ROLE_SYSTEM_WHITESPACE name='
+'
 ++IA2_ROLE_HEADING name='Section one heading'
 ++++ROLE_SYSTEM_STATICTEXT name='Section one heading'
 ++IA2_ROLE_HEADING name='Section two heading'
diff --git a/content/test/data/accessibility/aria/aria-describedby-expected-android.txt b/content/test/data/accessibility/aria/aria-describedby-expected-android.txt
index 88ed66f..d4fdffc 100644
--- a/content/test/data/accessibility/aria/aria-describedby-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-describedby-expected-android.txt
@@ -1,3 +1,4 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.EditText clickable editable_text focusable name='Your username should be your email id' input_type=1
+++android.view.View
+++++android.widget.EditText clickable editable_text focusable name='Your username should be your email id' input_type=1
 ++android.view.View role_description='tooltip' name='Your username should be your email id'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt b/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt
index f3679c4..62908b2 100644
--- a/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt
@@ -1,4 +1,5 @@
 AXWebArea AXRoleDescription='HTML content'
-++AXTextField AXRoleDescription='text field' AXHelp='Your username should be your email id'
+++AXGroup AXRoleDescription='group'
+++++AXTextField AXRoleDescription='text field' AXHelp='Your username should be your email id'
 ++AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip'
 ++++AXStaticText AXRoleDescription='text' AXValue='Your username should be your email id'
diff --git a/content/test/data/accessibility/aria/aria-describedby-expected-win.txt b/content/test/data/accessibility/aria/aria-describedby-expected-win.txt
index 5b23e8c..f653ef57 100644
--- a/content/test/data/accessibility/aria/aria-describedby-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-describedby-expected-win.txt
@@ -1,4 +1,5 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_TEXT FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_TEXT FOCUSABLE
 ++ROLE_SYSTEM_TOOLTIP READONLY xml-roles:tooltip
 ++++ROLE_SYSTEM_STATICTEXT
diff --git a/content/test/data/accessibility/aria/aria-labelledby-heading-expected-mac.txt b/content/test/data/accessibility/aria/aria-labelledby-heading-expected-mac.txt
index 2c04c2f..1bc2f24a 100644
--- a/content/test/data/accessibility/aria/aria-labelledby-heading-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-labelledby-heading-expected-mac.txt
@@ -1,4 +1,5 @@
 AXWebArea
-++AXTextField AXTitleUIElement='AXHeading h2'
+++AXGroup
+++++AXTextField AXTitleUIElement='AXHeading h2'
 ++AXHeading AXTitle='h2' AXValue='2'
 ++++AXStaticText AXValue='h2'
diff --git a/content/test/data/accessibility/aria/aria-owns-expected-mac.txt b/content/test/data/accessibility/aria/aria-owns-expected-mac.txt
index 95bc262..4639c4bc 100644
--- a/content/test/data/accessibility/aria/aria-owns-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-owns-expected-mac.txt
@@ -5,10 +5,12 @@
 ++++++++AXListMarker AXValue='•'
 ++++++++AXStaticText AXValue='One'
 ++++AXGroup AXTitle='Two'
-++++++AXListMarker AXValue='•'
+++++++AXGroup
+++++++++AXListMarker AXValue='•'
 ++++++AXGroup
 ++++++++AXStaticText AXValue='Two'
 ++AXGroup AXTitle='Three'
-++++AXListMarker AXValue='•'
+++++AXGroup
+++++++AXListMarker AXValue='•'
 ++++AXGroup
 ++++++AXStaticText AXValue='Three'
diff --git a/content/test/data/accessibility/aria/aria-posinset-expected-android.txt b/content/test/data/accessibility/aria/aria-posinset-expected-android.txt
index 5f6217b..dab277b8 100644
--- a/content/test/data/accessibility/aria/aria-posinset-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-posinset-expected-android.txt
@@ -8,23 +8,29 @@
 ++android.view.View
 ++++android.widget.RadioButton role_description='radio button' checkable clickable focusable
 ++++android.view.View name='1'
-++++android.view.View name='<newline>'
+++++android.view.View name='
+'
 ++++android.widget.RadioButton role_description='radio button' checkable clickable focusable
 ++++android.view.View name='2'
-++android.widget.RadioButton role_description='radio button' checkable clickable focusable
-++android.view.View name='Apple'
-++android.view.View name='<newline>'
-++android.widget.RadioButton role_description='radio button' checkable clickable focusable
-++android.view.View name='Banana'
+++android.view.View
+++++android.widget.RadioButton role_description='radio button' checkable clickable focusable
+++++android.view.View name='Apple'
+++++android.view.View name='
+'
+++++android.widget.RadioButton role_description='radio button' checkable clickable focusable
+++++android.view.View name='Banana'
 ++android.view.View name='Cake'
 ++++android.view.View name='Cake'
-++++android.widget.RadioButton role_description='radio button' checkable checked clickable focusable name='Chiffon cakes'
-++++android.view.View name='<newline>'
-++++android.widget.RadioButton role_description='radio button' checkable clickable focusable name='Chocolate cakes'
+++++android.view.View
+++++++android.widget.RadioButton role_description='radio button' checkable checked clickable focusable name='Chiffon cakes'
+++++++android.view.View name='
+'
+++++++android.widget.RadioButton role_description='radio button' checkable clickable focusable name='Chocolate cakes'
 ++android.view.View
 ++++android.view.View
 ++++++android.widget.Button role_description='button' clickable focusable name='changedFromRadio'
 ++++++android.view.View name='red'
-++++++android.view.View name='<newline>'
+++++++android.view.View name='
+'
 ++++++android.widget.RadioButton role_description='radio button' checkable clickable focusable name='blue'
 ++android.view.View name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-posinset-expected-mac.txt b/content/test/data/accessibility/aria/aria-posinset-expected-mac.txt
index 0027c71..ce48d5cb 100644
--- a/content/test/data/accessibility/aria/aria-posinset-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-posinset-expected-mac.txt
@@ -8,25 +8,32 @@
 ++AXGroup AXRoleDescription='form'
 ++++AXRadioButton AXRoleDescription='radio button' AXValue='0' AXARIASetSize='4' AXARIAPosInSet='3'
 ++++AXStaticText AXRoleDescription='text' AXValue='1'
-++++AXUnknown AXRoleDescription='unknown' AXTitle='<newline>'
+++++AXUnknown AXRoleDescription='unknown' AXTitle='
+'
 ++++AXRadioButton AXRoleDescription='radio button' AXValue='0' AXARIASetSize='4' AXARIAPosInSet='4'
 ++++AXStaticText AXRoleDescription='text' AXValue='2'
-++AXRadioButton AXRoleDescription='radio button' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='1'
-++AXStaticText AXRoleDescription='text' AXValue='Apple'
-++AXUnknown AXRoleDescription='unknown' AXTitle='<newline>'
-++AXRadioButton AXRoleDescription='radio button' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='2'
-++AXStaticText AXRoleDescription='text' AXValue='Banana'
+++AXGroup AXRoleDescription='group'
+++++AXRadioButton AXRoleDescription='radio button' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='1'
+++++AXStaticText AXRoleDescription='text' AXValue='Apple'
+++++AXUnknown AXRoleDescription='unknown' AXTitle='
+'
+++++AXRadioButton AXRoleDescription='radio button' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='2'
+++++AXStaticText AXRoleDescription='text' AXValue='Banana'
 ++AXGroup AXRoleDescription='group' AXTitle='Cake'
 ++++AXGroup AXRoleDescription='group'
 ++++++AXStaticText AXRoleDescription='text' AXValue='Cake'
-++++AXRadioButton AXRoleDescription='radio button' AXTitle='Chiffon cakes' AXValue='1' AXARIASetSize='2' AXARIAPosInSet='1'
-++++AXUnknown AXRoleDescription='unknown' AXTitle='<newline>'
-++++AXRadioButton AXRoleDescription='radio button' AXTitle='Chocolate cakes' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='2'
+++++AXGroup AXRoleDescription='group'
+++++++AXRadioButton AXRoleDescription='radio button' AXTitle='Chiffon cakes' AXValue='1' AXARIASetSize='2' AXARIAPosInSet='1'
+++++++AXUnknown AXRoleDescription='unknown' AXTitle='
+'
+++++++AXRadioButton AXRoleDescription='radio button' AXTitle='Chocolate cakes' AXValue='0' AXARIASetSize='2' AXARIAPosInSet='2'
 ++AXGroup AXRoleDescription='form'
 ++++AXGroup AXRoleDescription='group'
 ++++++AXButton AXRoleDescription='button' AXTitle='changedFromRadio'
 ++++++AXGroup AXRoleDescription='group'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='red'
-++++++AXUnknown AXRoleDescription='unknown' AXTitle='<newline>'
+++++++AXUnknown AXRoleDescription='unknown' AXTitle='
+'
 ++++++AXRadioButton AXRoleDescription='radio button' AXTitle='blue' AXValue='0' AXARIASetSize='1' AXARIAPosInSet='1'
-++AXStaticText AXRoleDescription='text' AXValue='Done'
+++AXGroup AXRoleDescription='group'
+++++AXStaticText AXRoleDescription='text' AXValue='Done'
diff --git a/content/test/data/accessibility/aria/aria-posinset-expected-win.txt b/content/test/data/accessibility/aria/aria-posinset-expected-win.txt
index aa2bed3..401ab3e1 100644
--- a/content/test/data/accessibility/aria/aria-posinset-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-posinset-expected-win.txt
@@ -8,25 +8,32 @@
 ++IA2_ROLE_FORM
 ++++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE setsize:4 posinset:3
 ++++ROLE_SYSTEM_STATICTEXT name='1'
-++++ROLE_SYSTEM_WHITESPACE name='<newline>'
+++++ROLE_SYSTEM_WHITESPACE name='
+'
 ++++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE setsize:4 posinset:4
 ++++ROLE_SYSTEM_STATICTEXT name='2'
-++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE setsize:2 posinset:1
-++ROLE_SYSTEM_STATICTEXT name='Apple'
-++ROLE_SYSTEM_WHITESPACE name='<newline>'
-++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE setsize:2 posinset:2
-++ROLE_SYSTEM_STATICTEXT name='Banana'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE setsize:2 posinset:1
+++++ROLE_SYSTEM_STATICTEXT name='Apple'
+++++ROLE_SYSTEM_WHITESPACE name='
+'
+++++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE setsize:2 posinset:2
+++++ROLE_SYSTEM_STATICTEXT name='Banana'
 ++ROLE_SYSTEM_GROUPING name='Cake'
 ++++IA2_ROLE_LABEL
 ++++++ROLE_SYSTEM_STATICTEXT name='Cake'
-++++ROLE_SYSTEM_RADIOBUTTON name='Chiffon cakes' FOCUSABLE setsize:2 posinset:1
-++++ROLE_SYSTEM_WHITESPACE name='<newline>'
-++++ROLE_SYSTEM_RADIOBUTTON name='Chocolate cakes' FOCUSABLE setsize:2 posinset:2
+++++IA2_ROLE_SECTION
+++++++ROLE_SYSTEM_RADIOBUTTON name='Chiffon cakes' FOCUSABLE setsize:2 posinset:1
+++++++ROLE_SYSTEM_WHITESPACE name='
+'
+++++++ROLE_SYSTEM_RADIOBUTTON name='Chocolate cakes' FOCUSABLE setsize:2 posinset:2
 ++IA2_ROLE_FORM
 ++++IA2_ROLE_PARAGRAPH
 ++++++ROLE_SYSTEM_PUSHBUTTON name='changedFromRadio' FOCUSABLE
 ++++++IA2_ROLE_LABEL
 ++++++++ROLE_SYSTEM_STATICTEXT name='red'
-++++++ROLE_SYSTEM_WHITESPACE name='<newline>'
+++++++ROLE_SYSTEM_WHITESPACE name='
+'
 ++++++ROLE_SYSTEM_RADIOBUTTON name='blue' FOCUSABLE setsize:1 posinset:1
-++ROLE_SYSTEM_STATICTEXT name='Done'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT name='Done'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-separator-expected-mac.txt b/content/test/data/accessibility/aria/aria-separator-expected-mac.txt
index 8dc1ccd..b4cff15 100644
--- a/content/test/data/accessibility/aria/aria-separator-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-separator-expected-mac.txt
@@ -1,4 +1,6 @@
 AXWebArea AXRoleDescription='HTML content'
-++AXStaticText AXRoleDescription='text' AXValue='Before'
+++AXGroup AXRoleDescription='group'
+++++AXStaticText AXRoleDescription='text' AXValue='Before'
 ++AXSplitter AXRoleDescription='splitter'
-++AXStaticText AXRoleDescription='text' AXValue='After'
+++AXGroup AXRoleDescription='group'
+++++AXStaticText AXRoleDescription='text' AXValue='After'
diff --git a/content/test/data/accessibility/aria/aria-separator-expected-win.txt b/content/test/data/accessibility/aria/aria-separator-expected-win.txt
index bf52b66..70a8bc6 100644
--- a/content/test/data/accessibility/aria/aria-separator-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-separator-expected-win.txt
@@ -1,4 +1,6 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_STATICTEXT name='Before'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT name='Before'
 ++ROLE_SYSTEM_SEPARATOR xml-roles:separator
-++ROLE_SYSTEM_STATICTEXT name='After'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT name='After'
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-mac.txt b/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-mac.txt
index 79a8fe9..dc45983 100644
--- a/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-mac.txt
@@ -1,9 +1,11 @@
 AXWebArea AXRoleDescription='HTML content'
-++AXTextArea AXRoleDescription='text entry area' AXValue='TextBox1<newline><newline>'
+++AXTextArea AXRoleDescription='text entry area' AXValue='TextBox1
+'
 ++++AXHeading AXRoleDescription='heading' AXTitle='TextBox1' AXValue='1'
 ++++++AXStaticText AXRoleDescription='text' AXValue='TextBox1'
-++AXTextArea AXRoleDescription='text entry area' AXValue='TextBox2<newline><newline>Some text.'
+++AXTextArea AXRoleDescription='text entry area' AXValue='TextBox2
+Some text.'
 ++++AXHeading AXRoleDescription='heading' AXTitle='TextBox2' AXValue='2'
 ++++++AXStaticText AXRoleDescription='text' AXValue='TextBox2'
 ++++AXGroup AXRoleDescription='group'
-++++++AXStaticText AXRoleDescription='text' AXValue='Some text.'
\ No newline at end of file
+++++++AXStaticText AXRoleDescription='text' AXValue='Some text.'
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-win.txt b/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-win.txt
index e47278b5..8ecd5d6 100644
--- a/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-with-rich-text-expected-win.txt
@@ -1,9 +1,11 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1>' caret_offset=0 n_selections=0
-++ROLE_SYSTEM_TEXT value='TextBox1<newline><newline>' FOCUSABLE IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='<obj0>' caret_offset=0 n_selections=0
+++ROLE_SYSTEM_TEXT value='TextBox1
+' FOCUSABLE IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='<obj0>' caret_offset=0 n_selections=0
 ++++IA2_ROLE_HEADING name='TextBox1' xml-roles:heading ia2_hypertext='TextBox1' caret_offset=0 n_selections=0
 ++++++ROLE_SYSTEM_STATICTEXT name='TextBox1' ia2_hypertext='TextBox1' caret_offset=0 n_selections=0
-++ROLE_SYSTEM_TEXT value='TextBox2<newline><newline>Some text.' FOCUSABLE IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='<obj0><obj1>' n_selections=0
+++ROLE_SYSTEM_TEXT value='TextBox2
+Some text.' FOCUSABLE IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='<obj0><obj1>' n_selections=0
 ++++IA2_ROLE_HEADING name='TextBox2' xml-roles:heading ia2_hypertext='TextBox2' n_selections=0
 ++++++ROLE_SYSTEM_STATICTEXT name='TextBox2' ia2_hypertext='TextBox2' n_selections=0
 ++++IA2_ROLE_PARAGRAPH ia2_hypertext='Some text.' n_selections=0
-++++++ROLE_SYSTEM_STATICTEXT name='Some text.' ia2_hypertext='Some text.' n_selections=0
\ No newline at end of file
+++++++ROLE_SYSTEM_STATICTEXT name='Some text.' ia2_hypertext='Some text.' n_selections=0
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-android.txt b/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-android.txt
index f314ee1..eb65b221 100644
--- a/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-android.txt
@@ -1,3 +1,4 @@
 android.webkit.WebView focusable focused scrollable
 ++android.widget.EditText clickable editable_text has_non_empty_value name='Single line.' text_change_added_count=12
-++android.widget.EditText clickable editable_text has_non_empty_value multiline name='Multiple<newline>lines.' text_change_added_count=15
\ No newline at end of file
+++android.widget.EditText clickable editable_text has_non_empty_value multiline name='Multiple
+lines.' text_change_added_count=15
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-mac.txt b/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-mac.txt
index 595e1953..c7f3babd 100644
--- a/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-mac.txt
@@ -1,7 +1,9 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTextField AXRoleDescription='text field' AXValue='Single line.'
 ++++AXStaticText AXRoleDescription='text' AXValue='Single line.'
-++AXTextArea AXRoleDescription='text entry area' AXValue='Multiple<newline>lines.'
+++AXTextArea AXRoleDescription='text entry area' AXValue='Multiple
+lines.'
 ++++AXStaticText AXRoleDescription='text' AXValue='Multiple'
-++++AXUnknown AXRoleDescription='unknown' AXTitle='<newline>'
+++++AXUnknown AXRoleDescription='unknown' AXTitle='
+'
 ++++AXStaticText AXRoleDescription='text' AXValue='lines.'
diff --git a/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-win.txt b/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-win.txt
new file mode 100644
index 0000000..9a2c15bb
--- /dev/null
+++ b/content/test/data/accessibility/aria/aria-textbox-with-selection-expected-win.txt
@@ -0,0 +1,10 @@
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1>' caret_offset=2 n_selections=1 selection_start=0 selection_end=2
+++ROLE_SYSTEM_TEXT READONLY IA2_STATE_SINGLE_LINE xml-roles:textbox ia2_hypertext='Single line.' n_selections=1 selection_start=0 selection_end=12
+++++ROLE_SYSTEM_STATICTEXT name='Single line.' ia2_hypertext='Single line.' n_selections=1 selection_start=0 selection_end=12
+++ROLE_SYSTEM_TEXT READONLY IA2_STATE_MULTI_LINE xml-roles:textbox ia2_hypertext='Multiple
+lines.' caret_offset=8 n_selections=1 selection_start=0 selection_end=8
+++++ROLE_SYSTEM_STATICTEXT name='Multiple' ia2_hypertext='Multiple' caret_offset=8 n_selections=1 selection_start=0 selection_end=8
+++++ROLE_SYSTEM_WHITESPACE name='
+' ia2_hypertext='
+' n_selections=0
+++++ROLE_SYSTEM_STATICTEXT name='lines.' ia2_hypertext='lines.' n_selections=0
diff --git a/content/test/data/accessibility/aria/aria-tooltip-expected-android.txt b/content/test/data/accessibility/aria/aria-tooltip-expected-android.txt
index 88ed66f..d4fdffc 100644
--- a/content/test/data/accessibility/aria/aria-tooltip-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-tooltip-expected-android.txt
@@ -1,3 +1,4 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.EditText clickable editable_text focusable name='Your username should be your email id' input_type=1
+++android.view.View
+++++android.widget.EditText clickable editable_text focusable name='Your username should be your email id' input_type=1
 ++android.view.View role_description='tooltip' name='Your username should be your email id'
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt b/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt
index f3679c4..62908b2 100644
--- a/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt
@@ -1,4 +1,5 @@
 AXWebArea AXRoleDescription='HTML content'
-++AXTextField AXRoleDescription='text field' AXHelp='Your username should be your email id'
+++AXGroup AXRoleDescription='group'
+++++AXTextField AXRoleDescription='text field' AXHelp='Your username should be your email id'
 ++AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip'
 ++++AXStaticText AXRoleDescription='text' AXValue='Your username should be your email id'
diff --git a/content/test/data/accessibility/aria/aria-tooltip-expected-win.txt b/content/test/data/accessibility/aria/aria-tooltip-expected-win.txt
index 5b23e8c..f653ef57 100644
--- a/content/test/data/accessibility/aria/aria-tooltip-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-tooltip-expected-win.txt
@@ -1,4 +1,5 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_TEXT FOCUSABLE
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_TEXT FOCUSABLE
 ++ROLE_SYSTEM_TOOLTIP READONLY xml-roles:tooltip
 ++++ROLE_SYSTEM_STATICTEXT
diff --git a/content/test/data/accessibility/html/a-expected-auralinux.txt b/content/test/data/accessibility/html/a-expected-auralinux.txt
index e6c3c735..28ab4f4d 100644
--- a/content/test/data/accessibility/html/a-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/a-expected-auralinux.txt
@@ -1,4 +1,4 @@
-[document web] enabled focusable focused<newline>
-++[section] enabled<newline>
-++++[link] name='normal link' enabled focusable<newline>
-++++++[text] name='normal link' enabled<newline>
\ No newline at end of file
+[document web] enabled focusable focused
+++[section] enabled
+++++[link] name='normal link' enabled focusable
+++++++[text] name='normal link' enabled
diff --git a/content/test/data/accessibility/html/a-name-calc-expected-android.txt b/content/test/data/accessibility/html/a-name-calc-expected-android.txt
index 2faf0426..1e6e641 100644
--- a/content/test/data/accessibility/html/a-name-calc-expected-android.txt
+++ b/content/test/data/accessibility/html/a-name-calc-expected-android.txt
@@ -1,8 +1,9 @@
 android.webkit.WebView focusable focused scrollable
-++android.view.View role_description='link' clickable focusable link name='InnerText0'
-++android.view.View role_description='link' clickable focusable link name='InnerText1 Title1'
-++android.view.View role_description='link' clickable focusable link name='Title2'
-++android.view.View role_description='link' clickable focusable link name='LabelledBy3'
-++android.view.View role_description='link' clickable focusable link name='Title4'
-++android.view.View role_description='link' clickable focusable link name='Label5'
-++android.view.View role_description='link' clickable focusable link name='LabelledBy6'
\ No newline at end of file
+++android.view.View
+++++android.view.View role_description='link' clickable focusable link name='InnerText0'
+++++android.view.View role_description='link' clickable focusable link name='InnerText1 Title1'
+++++android.view.View role_description='link' clickable focusable link name='Title2'
+++++android.view.View role_description='link' clickable focusable link name='LabelledBy3'
+++++android.view.View role_description='link' clickable focusable link name='Title4'
+++++android.view.View role_description='link' clickable focusable link name='Label5'
+++++android.view.View role_description='link' clickable focusable link name='LabelledBy6'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/action-verbs-expected-blink.txt b/content/test/data/accessibility/html/action-verbs-expected-blink.txt
index ac62ce9..b04a00d 100644
--- a/content/test/data/accessibility/html/action-verbs-expected-blink.txt
+++ b/content/test/data/accessibility/html/action-verbs-expected-blink.txt
@@ -5,18 +5,20 @@
 ++heading name='Heading'
 ++++staticText name='Heading'
 ++++++inlineTextBox name='Heading'
-++button action='press' name='Button'
-++link action='jump' name='Link'
-++++staticText action='click' name='Link'
-++++++inlineTextBox name='Link'
-++textField
-++checkBox action='check'
-++checkBox action='uncheck'
-++radioButton action='select'
+++group
+++++button action='press' name='Button'
+++++link action='jump' name='Link'
+++++++staticText action='click' name='Link'
+++++++++inlineTextBox name='Link'
+++++textField
+++++checkBox action='check'
+++++checkBox action='uncheck'
+++++radioButton action='select'
 ++switch action='check' name='ARIA Switch'
-++popUpButton action='open'
-++++menuListPopup
-++++++menuListOption action='click' name='Pop-up button'
+++group
+++++popUpButton action='open'
+++++++menuListPopup
+++++++++menuListOption action='click' name='Pop-up button'
 ++div action='click'
 ++++staticText action='click' name='Div with click handler'
-++++++inlineTextBox name='Div with click handler'
\ No newline at end of file
+++++++inlineTextBox name='Div with click handler'
diff --git a/content/test/data/accessibility/html/button-name-calc-expected-android.txt b/content/test/data/accessibility/html/button-name-calc-expected-android.txt
index c874303..4887f2f 100644
--- a/content/test/data/accessibility/html/button-name-calc-expected-android.txt
+++ b/content/test/data/accessibility/html/button-name-calc-expected-android.txt
@@ -1,7 +1,8 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.Button role_description='button' clickable focusable name='InnerText0'
-++android.widget.Button role_description='button' clickable focusable name='InnerText1 Title1'
-++android.widget.Button role_description='button' clickable focusable name='AriaLabel2 Title2'
-++android.widget.Button role_description='button' clickable focusable name='LabelledBy3 Title3'
-++android.widget.Button role_description='button' clickable focusable name='LabelledBy4 DescribedBy4'
-++android.widget.Button role_description='button' clickable focusable name='InnerText5 DescribedBy5'
\ No newline at end of file
+++android.view.View
+++++android.widget.Button role_description='button' clickable focusable name='InnerText0'
+++++android.widget.Button role_description='button' clickable focusable name='InnerText1 Title1'
+++++android.widget.Button role_description='button' clickable focusable name='AriaLabel2 Title2'
+++++android.widget.Button role_description='button' clickable focusable name='LabelledBy3 Title3'
+++++android.widget.Button role_description='button' clickable focusable name='LabelledBy4 DescribedBy4'
+++++android.widget.Button role_description='button' clickable focusable name='InnerText5 DescribedBy5'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/button-name-calc-expected-mac.txt b/content/test/data/accessibility/html/button-name-calc-expected-mac.txt
index 19686dd6..d618f0b 100644
--- a/content/test/data/accessibility/html/button-name-calc-expected-mac.txt
+++ b/content/test/data/accessibility/html/button-name-calc-expected-mac.txt
@@ -1,7 +1,8 @@
 AXWebArea
-++AXButton AXTitle='InnerText0'
-++AXButton AXTitle='InnerText1' AXHelp='Title1'
-++AXButton AXDescription='AriaLabel2' AXHelp='Title2'
-++AXButton AXTitle='LabelledBy3' AXHelp='Title3'
-++AXButton AXTitle='LabelledBy4' AXHelp='DescribedBy4'
-++AXButton AXTitle='InnerText5' AXHelp='DescribedBy5'
+++AXGroup
+++++AXButton AXTitle='InnerText0'
+++++AXButton AXTitle='InnerText1' AXHelp='Title1'
+++++AXButton AXDescription='AriaLabel2' AXHelp='Title2'
+++++AXButton AXTitle='LabelledBy3' AXHelp='Title3'
+++++AXButton AXTitle='LabelledBy4' AXHelp='DescribedBy4'
+++++AXButton AXTitle='InnerText5' AXHelp='DescribedBy5'
diff --git a/content/test/data/accessibility/html/button-name-calc-expected-win.txt b/content/test/data/accessibility/html/button-name-calc-expected-win.txt
index 856df38b..82480dc7 100644
--- a/content/test/data/accessibility/html/button-name-calc-expected-win.txt
+++ b/content/test/data/accessibility/html/button-name-calc-expected-win.txt
@@ -1,7 +1,8 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_PUSHBUTTON name='InnerText0' FOCUSABLE
-++ROLE_SYSTEM_PUSHBUTTON name='InnerText1' FOCUSABLE description='Title1'
-++ROLE_SYSTEM_PUSHBUTTON name='AriaLabel2' FOCUSABLE explicit-name:true description='Title2'
-++ROLE_SYSTEM_PUSHBUTTON name='LabelledBy3' FOCUSABLE explicit-name:true description='Title3'
-++ROLE_SYSTEM_PUSHBUTTON name='LabelledBy4' FOCUSABLE explicit-name:true description='DescribedBy4'
-++ROLE_SYSTEM_PUSHBUTTON name='InnerText5' FOCUSABLE description='DescribedBy5'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_PUSHBUTTON name='InnerText0' FOCUSABLE
+++++ROLE_SYSTEM_PUSHBUTTON name='InnerText1' FOCUSABLE description='Title1'
+++++ROLE_SYSTEM_PUSHBUTTON name='AriaLabel2' FOCUSABLE explicit-name:true description='Title2'
+++++ROLE_SYSTEM_PUSHBUTTON name='LabelledBy3' FOCUSABLE explicit-name:true description='Title3'
+++++ROLE_SYSTEM_PUSHBUTTON name='LabelledBy4' FOCUSABLE explicit-name:true description='DescribedBy4'
+++++ROLE_SYSTEM_PUSHBUTTON name='InnerText5' FOCUSABLE description='DescribedBy5'
diff --git a/content/test/data/accessibility/html/checkbox-name-calc-expected-android.txt b/content/test/data/accessibility/html/checkbox-name-calc-expected-android.txt
index 571974f4..b88990189 100644
--- a/content/test/data/accessibility/html/checkbox-name-calc-expected-android.txt
+++ b/content/test/data/accessibility/html/checkbox-name-calc-expected-android.txt
@@ -1,7 +1,8 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='Title0'
-++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='Label1 Title1'
-++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='AriaLabel2 Title2'
-++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='LabelledBy3 Title3'
-++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='LabelledBy4 DescribedBy4'
-++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='DescribedBy5'
\ No newline at end of file
+++android.view.View
+++++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='Title0'
+++++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='Label1 Title1'
+++++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='AriaLabel2 Title2'
+++++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='LabelledBy3 Title3'
+++++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='LabelledBy4 DescribedBy4'
+++++android.widget.CheckBox role_description='checkbox' checkable clickable focusable name='DescribedBy5'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/checkbox-name-calc-expected-mac.txt b/content/test/data/accessibility/html/checkbox-name-calc-expected-mac.txt
index c826ec1..c930ab1 100644
--- a/content/test/data/accessibility/html/checkbox-name-calc-expected-mac.txt
+++ b/content/test/data/accessibility/html/checkbox-name-calc-expected-mac.txt
@@ -1,7 +1,8 @@
 AXWebArea
-++AXCheckBox AXDescription='Title0'
-++AXCheckBox AXTitle='Label1' AXHelp='Title1'
-++AXCheckBox AXDescription='AriaLabel2' AXHelp='Title2'
-++AXCheckBox AXTitle='LabelledBy3' AXHelp='Title3'
-++AXCheckBox AXTitle='LabelledBy4' AXHelp='DescribedBy4'
-++AXCheckBox AXHelp='DescribedBy5'
+++AXGroup
+++++AXCheckBox AXDescription='Title0'
+++++AXCheckBox AXTitle='Label1' AXHelp='Title1'
+++++AXCheckBox AXDescription='AriaLabel2' AXHelp='Title2'
+++++AXCheckBox AXTitle='LabelledBy3' AXHelp='Title3'
+++++AXCheckBox AXTitle='LabelledBy4' AXHelp='DescribedBy4'
+++++AXCheckBox AXHelp='DescribedBy5'
diff --git a/content/test/data/accessibility/html/checkbox-name-calc-expected-win.txt b/content/test/data/accessibility/html/checkbox-name-calc-expected-win.txt
index c9da1c8..634f507 100644
--- a/content/test/data/accessibility/html/checkbox-name-calc-expected-win.txt
+++ b/content/test/data/accessibility/html/checkbox-name-calc-expected-win.txt
@@ -1,7 +1,8 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_CHECKBUTTON name='Title0' FOCUSABLE explicit-name:true
-++ROLE_SYSTEM_CHECKBUTTON name='Label1' FOCUSABLE explicit-name:true description='Title1'
-++ROLE_SYSTEM_CHECKBUTTON name='AriaLabel2' FOCUSABLE explicit-name:true description='Title2'
-++ROLE_SYSTEM_CHECKBUTTON name='LabelledBy3' FOCUSABLE explicit-name:true description='Title3'
-++ROLE_SYSTEM_CHECKBUTTON name='LabelledBy4' FOCUSABLE explicit-name:true description='DescribedBy4'
-++ROLE_SYSTEM_CHECKBUTTON FOCUSABLE description='DescribedBy5'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_CHECKBUTTON name='Title0' FOCUSABLE explicit-name:true
+++++ROLE_SYSTEM_CHECKBUTTON name='Label1' FOCUSABLE explicit-name:true description='Title1'
+++++ROLE_SYSTEM_CHECKBUTTON name='AriaLabel2' FOCUSABLE explicit-name:true description='Title2'
+++++ROLE_SYSTEM_CHECKBUTTON name='LabelledBy3' FOCUSABLE explicit-name:true description='Title3'
+++++ROLE_SYSTEM_CHECKBUTTON name='LabelledBy4' FOCUSABLE explicit-name:true description='DescribedBy4'
+++++ROLE_SYSTEM_CHECKBUTTON FOCUSABLE description='DescribedBy5'
diff --git a/content/test/data/accessibility/html/cite-expected-android.txt b/content/test/data/accessibility/html/cite-expected-android.txt
index 6532727..81024f4 100644
--- a/content/test/data/accessibility/html/cite-expected-android.txt
+++ b/content/test/data/accessibility/html/cite-expected-android.txt
@@ -1,3 +1,4 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.Image role_description='graphic' name='Pipe'
+++android.view.View
+++++android.widget.Image role_description='graphic' name='Pipe'
 ++android.view.View name='The pipe clicked by SomeOne.'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/cite-expected-mac.txt b/content/test/data/accessibility/html/cite-expected-mac.txt
index 17def55..7a6b589 100644
--- a/content/test/data/accessibility/html/cite-expected-mac.txt
+++ b/content/test/data/accessibility/html/cite-expected-mac.txt
@@ -1,5 +1,6 @@
 AXWebArea
-++AXImage AXDescription='Pipe'
+++AXGroup
+++++AXImage AXDescription='Pipe'
 ++AXGroup
 ++++AXStaticText AXValue='The pipe'
 ++++AXStaticText AXValue=' clicked by SomeOne.'
diff --git a/content/test/data/accessibility/html/cite-expected-win.txt b/content/test/data/accessibility/html/cite-expected-win.txt
index 59017c1..8effa72 100644
--- a/content/test/data/accessibility/html/cite-expected-win.txt
+++ b/content/test/data/accessibility/html/cite-expected-win.txt
@@ -1,5 +1,6 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_GRAPHIC name='Pipe' READONLY
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_GRAPHIC name='Pipe' READONLY
 ++IA2_ROLE_PARAGRAPH
 ++++ROLE_SYSTEM_STATICTEXT name='The pipe'
 ++++ROLE_SYSTEM_STATICTEXT name=' clicked by SomeOne.'
diff --git a/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-mac.txt b/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-mac.txt
index b074b10e..74b460a4 100644
--- a/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-mac.txt
+++ b/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-mac.txt
@@ -1,10 +1,16 @@
 AXWebArea
-++AXTextArea AXValue='This is editable.<newline><newline>This is not editable.<newline>But this one is.<newline><newline>So is this one.'
+++AXTextArea AXValue='This is editable.
+This is not editable.
+But this one is.
+So is this one.'
 ++++AXGroup
 ++++++AXStaticText AXValue='This is editable.'
-++++AXStaticText AXValue='This is not editable.'
-++++AXUnknown AXTitle='<newline>'
+++++AXGroup
+++++++AXStaticText AXValue='This is not editable.'
+++++++AXUnknown AXTitle='
+'
 ++++AXGroup AXValue='But this one is.'
 ++++++AXStaticText AXValue='But this one is.'
 ++++AXGroup AXValue='So is this one.'
-++++++AXStaticText AXValue='So is this one.'
\ No newline at end of file
+++++++AXStaticText AXValue='So is this one.'
+
diff --git a/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-win.txt b/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-win.txt
index 7d8750a..3b0014db2 100644
--- a/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-win.txt
+++ b/content/test/data/accessibility/html/contenteditable-with-embedded-contenteditables-expected-win.txt
@@ -1,10 +1,14 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' n_selections=0
-++IA2_ROLE_SECTION FOCUSABLE IA2_STATE_EDITABLE ia2_hypertext='<obj0>This is not editable.<newline><obj3><obj4>' n_selections=0
+++IA2_ROLE_SECTION FOCUSABLE IA2_STATE_EDITABLE ia2_hypertext='<obj0><obj1><obj2><obj3>' n_selections=0
 ++++IA2_ROLE_PARAGRAPH IA2_STATE_EDITABLE ia2_hypertext='This is editable.' n_selections=0
 ++++++ROLE_SYSTEM_STATICTEXT name='This is editable.' IA2_STATE_EDITABLE ia2_hypertext='This is editable.' n_selections=0
-++++ROLE_SYSTEM_STATICTEXT name='This is not editable.' ia2_hypertext='This is not editable.' n_selections=0
-++++ROLE_SYSTEM_WHITESPACE name='<newline>' ia2_hypertext='<newline>' n_selections=0
+++++IA2_ROLE_SECTION ia2_hypertext='This is not editable.
+' n_selections=0
+++++++ROLE_SYSTEM_STATICTEXT name='This is not editable.' ia2_hypertext='This is not editable.' n_selections=0
+++++++ROLE_SYSTEM_WHITESPACE name='
+' ia2_hypertext='
+' n_selections=0
 ++++IA2_ROLE_PARAGRAPH FOCUSABLE IA2_STATE_EDITABLE ia2_hypertext='But this one is.' n_selections=0
 ++++++ROLE_SYSTEM_STATICTEXT name='But this one is.' IA2_STATE_EDITABLE ia2_hypertext='But this one is.' n_selections=0
 ++++IA2_ROLE_PARAGRAPH IA2_STATE_EDITABLE ia2_hypertext='So is this one.' n_selections=0
-++++++ROLE_SYSTEM_STATICTEXT name='So is this one.' IA2_STATE_EDITABLE ia2_hypertext='So is this one.' n_selections=0
\ No newline at end of file
+++++++ROLE_SYSTEM_STATICTEXT name='So is this one.' IA2_STATE_EDITABLE ia2_hypertext='So is this one.' n_selections=0
diff --git a/content/test/data/accessibility/html/element-class-id-src-attr-expected-android.txt b/content/test/data/accessibility/html/element-class-id-src-attr-expected-android.txt
index 8975012..58665a6 100644
--- a/content/test/data/accessibility/html/element-class-id-src-attr-expected-android.txt
+++ b/content/test/data/accessibility/html/element-class-id-src-attr-expected-android.txt
@@ -1,3 +1,4 @@
 android.webkit.WebView focusable focused scrollable
 ++android.view.View role_description='heading 1' heading name='Image'
-++android.widget.Image role_description='graphic' name='ImageAlt'
\ No newline at end of file
+++android.view.View
+++++android.widget.Image role_description='graphic' name='ImageAlt'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/element-class-id-src-attr-expected-mac.txt b/content/test/data/accessibility/html/element-class-id-src-attr-expected-mac.txt
index 0173ffae..d97f1eee 100644
--- a/content/test/data/accessibility/html/element-class-id-src-attr-expected-mac.txt
+++ b/content/test/data/accessibility/html/element-class-id-src-attr-expected-mac.txt
@@ -1,4 +1,5 @@
 AXWebArea
 ++AXHeading AXTitle='Image' AXValue='1'
 ++++AXStaticText AXValue='Image'
-++AXImage AXDescription='ImageAlt'
+++AXGroup
+++++AXImage AXDescription='ImageAlt'
diff --git a/content/test/data/accessibility/html/element-class-id-src-attr-expected-win.txt b/content/test/data/accessibility/html/element-class-id-src-attr-expected-win.txt
index 225bfc7..4000678 100644
--- a/content/test/data/accessibility/html/element-class-id-src-attr-expected-win.txt
+++ b/content/test/data/accessibility/html/element-class-id-src-attr-expected-win.txt
@@ -1,4 +1,5 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++IA2_ROLE_HEADING name='Image' class:headerClass id:headerID
 ++++ROLE_SYSTEM_STATICTEXT name='Image'
-++ROLE_SYSTEM_GRAPHIC name='ImageAlt' READONLY class:imageClass id:imageID src:greenbox.png
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_GRAPHIC name='ImageAlt' READONLY class:imageClass id:imageID src:greenbox.png
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/figcaption-expected-android.txt b/content/test/data/accessibility/html/figcaption-expected-android.txt
index aa1bf45..f252a7b 100644
--- a/content/test/data/accessibility/html/figcaption-expected-android.txt
+++ b/content/test/data/accessibility/html/figcaption-expected-android.txt
@@ -1,4 +1,5 @@
 android.webkit.WebView focusable focused scrollable
 ++android.view.View role_description='graphic' name='Fig.1 - A green Box'
-++++android.widget.Image role_description='graphic' name='This is a green box.'
+++++android.view.View
+++++++android.widget.Image role_description='graphic' name='This is a green box.'
 ++++android.view.View name='Fig.1 - A green Box'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/figcaption-expected-mac.txt b/content/test/data/accessibility/html/figcaption-expected-mac.txt
index b9dbd24..efb9097 100644
--- a/content/test/data/accessibility/html/figcaption-expected-mac.txt
+++ b/content/test/data/accessibility/html/figcaption-expected-mac.txt
@@ -1,5 +1,6 @@
 AXWebArea
 ++AXGroup AXTitle='Fig.1 - A green Box'
-++++AXImage AXDescription='This is a green box.'
+++++AXGroup
+++++++AXImage AXDescription='This is a green box.'
 ++++AXGroup
 ++++++AXStaticText AXValue='Fig.1 - A green Box'
diff --git a/content/test/data/accessibility/html/figcaption-expected-win.txt b/content/test/data/accessibility/html/figcaption-expected-win.txt
index c88e99e43..26a2770 100644
--- a/content/test/data/accessibility/html/figcaption-expected-win.txt
+++ b/content/test/data/accessibility/html/figcaption-expected-win.txt
@@ -1,5 +1,6 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_GROUPING name='Fig.1 - A green Box'
-++++ROLE_SYSTEM_GRAPHIC name='This is a green box.' READONLY
+++++IA2_ROLE_SECTION
+++++++ROLE_SYSTEM_GRAPHIC name='This is a green box.' READONLY
 ++++IA2_ROLE_CAPTION
 ++++++ROLE_SYSTEM_STATICTEXT name='Fig.1 - A green Box'
diff --git a/content/test/data/accessibility/html/iframe-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-cross-process-expected-blink.txt
index ab8a595..5cd0c952 100644
--- a/content/test/data/accessibility/html/iframe-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-cross-process-expected-blink.txt
@@ -10,4 +10,4 @@
 ++++++++++++inlineTextBox name='Text in iframe'
 ++paragraph
 ++++staticText name='After frame'
-++++++inlineTextBox name='After frame'
\ No newline at end of file
+++++++inlineTextBox name='After frame'
diff --git a/content/test/data/accessibility/html/input-button-in-menu-expected-win.txt b/content/test/data/accessibility/html/input-button-in-menu-expected-win.txt
index 06d12aeb..183ef6e 100644
--- a/content/test/data/accessibility/html/input-button-in-menu-expected-win.txt
+++ b/content/test/data/accessibility/html/input-button-in-menu-expected-win.txt
@@ -1,7 +1,9 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++IA2_ROLE_SECTION
 ++++ROLE_SYSTEM_MENUITEM name='Button in menu element' FOCUSABLE
-++++++ROLE_SYSTEM_STATICTEXT name='Button in menu element'
+++++++IA2_ROLE_SECTION
+++++++++ROLE_SYSTEM_STATICTEXT name='Button in menu element'
 ++ROLE_SYSTEM_MENUPOPUP xml-roles:menu
 ++++ROLE_SYSTEM_MENUITEM name='Button in element with menu role' FOCUSABLE
-++++++ROLE_SYSTEM_STATICTEXT name='Button in element with menu role'
+++++++IA2_ROLE_SECTION
+++++++++ROLE_SYSTEM_STATICTEXT name='Button in element with menu role'
diff --git a/content/test/data/accessibility/html/input-radio-expected-android.txt b/content/test/data/accessibility/html/input-radio-expected-android.txt
index b6881a5..5c7e559b 100644
--- a/content/test/data/accessibility/html/input-radio-expected-android.txt
+++ b/content/test/data/accessibility/html/input-radio-expected-android.txt
@@ -2,7 +2,8 @@
 ++android.view.View
 ++++android.widget.RadioButton role_description='radio button' checkable clickable focusable
 ++++android.view.View name='Radio1'
-++++android.view.View name='<newline>'
+++++android.view.View name='
+'
 ++++android.widget.RadioButton role_description='radio button' checkable clickable focusable
 ++++android.view.View name='Radio2'
 ++android.view.View
diff --git a/content/test/data/accessibility/html/input-radio-expected-mac.txt b/content/test/data/accessibility/html/input-radio-expected-mac.txt
index 4d3e8fd54..a297a09 100644
--- a/content/test/data/accessibility/html/input-radio-expected-mac.txt
+++ b/content/test/data/accessibility/html/input-radio-expected-mac.txt
@@ -2,7 +2,8 @@
 ++AXGroup
 ++++AXRadioButton AXValue='0'
 ++++AXStaticText AXValue='Radio1'
-++++AXUnknown AXTitle='<newline>'
+++++AXUnknown AXTitle='
+'
 ++++AXRadioButton AXValue='0'
 ++++AXStaticText AXValue='Radio2'
 ++AXGroup
diff --git a/content/test/data/accessibility/html/input-radio-expected-win.txt b/content/test/data/accessibility/html/input-radio-expected-win.txt
index b8c8be3..d637f872 100644
--- a/content/test/data/accessibility/html/input-radio-expected-win.txt
+++ b/content/test/data/accessibility/html/input-radio-expected-win.txt
@@ -1,10 +1,13 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0><obj1>'
-++IA2_ROLE_FORM ia2_hypertext='<obj0>Radio1<newline><obj3>Radio2'
+++IA2_ROLE_FORM ia2_hypertext='<obj0>Radio1
+<obj3>Radio2'
 ++++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true
 ++++ROLE_SYSTEM_STATICTEXT name='Radio1' ia2_hypertext='Radio1'
-++++ROLE_SYSTEM_WHITESPACE name='<newline>' ia2_hypertext='<newline>'
+++++ROLE_SYSTEM_WHITESPACE name='
+' ia2_hypertext='
+'
 ++++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE IA2_STATE_CHECKABLE checkable:true
 ++++ROLE_SYSTEM_STATICTEXT name='Radio2' ia2_hypertext='Radio2'
 ++IA2_ROLE_FORM ia2_hypertext='<obj0><obj1>'
 ++++ROLE_SYSTEM_RADIOBUTTON name='Radio3' FOCUSABLE IA2_STATE_CHECKABLE checkable:true ia2_hypertext='Radio3'
-++++ROLE_SYSTEM_RADIOBUTTON name='Radio4' CHECKED FOCUSABLE IA2_STATE_CHECKABLE checkable:true ia2_hypertext='Radio4'
\ No newline at end of file
+++++ROLE_SYSTEM_RADIOBUTTON name='Radio4' CHECKED FOCUSABLE IA2_STATE_CHECKABLE checkable:true ia2_hypertext='Radio4'
diff --git a/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt b/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt
index 2af2af9..849006f 100644
--- a/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt
+++ b/content/test/data/accessibility/html/input-text-name-calc-expected-android.txt
@@ -1,8 +1,9 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.EditText clickable editable_text focusable name='Title0' input_type=1
-++android.widget.EditText clickable editable_text focusable name='Label1 Title1' input_type=1
-++android.widget.EditText clickable editable_text focusable name='AriaLabel2 Title2' input_type=1
-++android.widget.EditText clickable editable_text focusable name='LabelledBy3 Title3' input_type=1
-++android.widget.EditText clickable editable_text focusable name='Placeholder4' input_type=1
-++android.widget.EditText clickable editable_text focusable name='Placeholder5 Title5' input_type=1
-++android.widget.EditText clickable editable_text focusable name='LabelledBy6 DescribedBy6' input_type=1
\ No newline at end of file
+++android.view.View
+++++android.widget.EditText clickable editable_text focusable name='Title0' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='Label1 Title1' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='AriaLabel2 Title2' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='LabelledBy3 Title3' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='Placeholder4' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='Placeholder5 Title5' input_type=1
+++++android.widget.EditText clickable editable_text focusable name='LabelledBy6 DescribedBy6' input_type=1
diff --git a/content/test/data/accessibility/html/input-text-name-calc-expected-win.txt b/content/test/data/accessibility/html/input-text-name-calc-expected-win.txt
index 62d4a50e..a5ff360 100644
--- a/content/test/data/accessibility/html/input-text-name-calc-expected-win.txt
+++ b/content/test/data/accessibility/html/input-text-name-calc-expected-win.txt
@@ -1,8 +1,9 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_TEXT name='Title0' FOCUSABLE explicit-name:true
-++ROLE_SYSTEM_TEXT name='Label1' FOCUSABLE explicit-name:true description='Title1'
-++ROLE_SYSTEM_TEXT name='AriaLabel2' FOCUSABLE explicit-name:true description='Title2'
-++ROLE_SYSTEM_TEXT name='LabelledBy3' FOCUSABLE explicit-name:true description='Title3'
-++ROLE_SYSTEM_TEXT name='Placeholder4' FOCUSABLE explicit-name:true
-++ROLE_SYSTEM_TEXT name='Placeholder5' FOCUSABLE explicit-name:true description='Title5'
-++ROLE_SYSTEM_TEXT name='LabelledBy6' FOCUSABLE explicit-name:true description='DescribedBy6'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_TEXT name='Title0' FOCUSABLE explicit-name:true
+++++ROLE_SYSTEM_TEXT name='Label1' FOCUSABLE explicit-name:true description='Title1'
+++++ROLE_SYSTEM_TEXT name='AriaLabel2' FOCUSABLE explicit-name:true description='Title2'
+++++ROLE_SYSTEM_TEXT name='LabelledBy3' FOCUSABLE explicit-name:true description='Title3'
+++++ROLE_SYSTEM_TEXT name='Placeholder4' FOCUSABLE explicit-name:true
+++++ROLE_SYSTEM_TEXT name='Placeholder5' FOCUSABLE explicit-name:true description='Title5'
+++++ROLE_SYSTEM_TEXT name='LabelledBy6' FOCUSABLE explicit-name:true description='DescribedBy6'
diff --git a/content/test/data/accessibility/html/legend-expected-android.txt b/content/test/data/accessibility/html/legend-expected-android.txt
index b684472..b8fe791d 100644
--- a/content/test/data/accessibility/html/legend-expected-android.txt
+++ b/content/test/data/accessibility/html/legend-expected-android.txt
@@ -2,7 +2,8 @@
 ++android.view.View
 ++++android.view.View name='Browser Engines:'
 ++++++android.view.View name='Browser Engines:'
-++++++android.view.View name='Browser: '
-++++++android.widget.EditText clickable editable_text focusable input_type=1
-++++++android.view.View name=' Rendering Engine: '
-++++++android.widget.EditText clickable editable_text focusable input_type=1
\ No newline at end of file
+++++++android.view.View
+++++++++android.view.View name='Browser: '
+++++++++android.widget.EditText clickable editable_text focusable input_type=1
+++++++++android.view.View name=' Rendering Engine: '
+++++++++android.widget.EditText clickable editable_text focusable input_type=1
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/legend-expected-mac.txt b/content/test/data/accessibility/html/legend-expected-mac.txt
index f1545dc..40bc23ea 100644
--- a/content/test/data/accessibility/html/legend-expected-mac.txt
+++ b/content/test/data/accessibility/html/legend-expected-mac.txt
@@ -3,7 +3,8 @@
 ++++AXGroup AXTitle='Browser Engines:'
 ++++++AXGroup
 ++++++++AXStaticText AXValue='Browser Engines:'
-++++++AXStaticText AXValue='Browser: '
-++++++AXTextField
-++++++AXStaticText AXValue=' Rendering Engine: '
-++++++AXTextField
+++++++AXGroup
+++++++++AXStaticText AXValue='Browser: '
+++++++++AXTextField
+++++++++AXStaticText AXValue=' Rendering Engine: '
+++++++++AXTextField
diff --git a/content/test/data/accessibility/html/legend-expected-win.txt b/content/test/data/accessibility/html/legend-expected-win.txt
index 0c32286..a533ea9 100644
--- a/content/test/data/accessibility/html/legend-expected-win.txt
+++ b/content/test/data/accessibility/html/legend-expected-win.txt
@@ -3,7 +3,8 @@
 ++++ROLE_SYSTEM_GROUPING name='Browser Engines:'
 ++++++IA2_ROLE_LABEL
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser Engines:'
-++++++ROLE_SYSTEM_STATICTEXT name='Browser: '
-++++++ROLE_SYSTEM_TEXT FOCUSABLE
-++++++ROLE_SYSTEM_STATICTEXT name=' Rendering Engine: '
-++++++ROLE_SYSTEM_TEXT FOCUSABLE
+++++++IA2_ROLE_SECTION
+++++++++ROLE_SYSTEM_STATICTEXT name='Browser: '
+++++++++ROLE_SYSTEM_TEXT FOCUSABLE
+++++++++ROLE_SYSTEM_STATICTEXT name=' Rendering Engine: '
+++++++++ROLE_SYSTEM_TEXT FOCUSABLE
diff --git a/content/test/data/accessibility/html/modal-dialog-closed-expected-mac.txt b/content/test/data/accessibility/html/modal-dialog-closed-expected-mac.txt
index 823d48bd..c53f0d6 100644
--- a/content/test/data/accessibility/html/modal-dialog-closed-expected-mac.txt
+++ b/content/test/data/accessibility/html/modal-dialog-closed-expected-mac.txt
@@ -1,7 +1,9 @@
 AXWebArea
-++AXStaticText AXValue='Test that elements respawn in the accessibility tree after a modal dialog closes.'
+++AXGroup
+++++AXStaticText AXValue='Test that elements respawn in the accessibility tree after a modal dialog closes.'
 ++AXGroup AXSubrole=AXDocumentRegion
 ++++AXPopUpButton AXValue='This should be in the tree.'
 ++++++AXUnknown
 ++++++++AXMenuItem AXValue='This should be in the tree.'
-++AXColorWell AXValue='rgb 0.00000 0.00000 0.00000 1'
+++AXGroup
+++++AXColorWell AXValue='rgb 0.00000 0.00000 0.00000 1'
diff --git a/content/test/data/accessibility/html/modal-dialog-closed-expected-win.txt b/content/test/data/accessibility/html/modal-dialog-closed-expected-win.txt
index e07713dd..fba5e92a7 100644
--- a/content/test/data/accessibility/html/modal-dialog-closed-expected-win.txt
+++ b/content/test/data/accessibility/html/modal-dialog-closed-expected-win.txt
@@ -1,7 +1,9 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_STATICTEXT name='Test that elements respawn in the accessibility tree after a modal dialog closes.'
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT name='Test that elements respawn in the accessibility tree after a modal dialog closes.'
 ++IA2_ROLE_SECTION
 ++++ROLE_SYSTEM_COMBOBOX FOCUSABLE
 ++++++ROLE_SYSTEM_LIST
 ++++++++ROLE_SYSTEM_LISTITEM name='This should be in the tree.' FOCUSABLE
-++IA2_ROLE_COLOR_CHOOSER FOCUSABLE
+++IA2_ROLE_SECTION
+++++IA2_ROLE_COLOR_CHOOSER FOCUSABLE
diff --git a/content/test/data/accessibility/html/p-expected-blink.txt b/content/test/data/accessibility/html/p-expected-blink.txt
index c53218d7..1fb2e3322 100644
--- a/content/test/data/accessibility/html/p-expected-blink.txt
+++ b/content/test/data/accessibility/html/p-expected-blink.txt
@@ -1,8 +1,11 @@
 rootWebArea
-++staticText name='Before'
-++++inlineTextBox name='Before' wordStarts=0 wordEnds=6
+++group
+++++staticText name='Before'
+++++++inlineTextBox name='Before' wordStarts=0 wordEnds=6
 ++paragraph
 ++++staticText name='Paragraph'
 ++++++inlineTextBox name='Paragraph' wordStarts=0 wordEnds=9
-++staticText name='After'
-++++inlineTextBox name='After' wordStarts=0 wordEnds=5
\ No newline at end of file
+++group
+++++staticText name='After'
+++++++inlineTextBox name='After' wordStarts=0 wordEnds=5
+<-- End-of-file -->
diff --git a/content/test/data/accessibility/html/p-expected-mac.txt b/content/test/data/accessibility/html/p-expected-mac.txt
index 5f411e2b..8935ef1 100644
--- a/content/test/data/accessibility/html/p-expected-mac.txt
+++ b/content/test/data/accessibility/html/p-expected-mac.txt
@@ -1,5 +1,7 @@
 AXWebArea
-++AXStaticText AXValue='Before'
+++AXGroup
+++++AXStaticText AXValue='Before'
 ++AXGroup
 ++++AXStaticText AXValue='Paragraph'
-++AXStaticText AXValue='After'
+++AXGroup
+++++AXStaticText AXValue='After'
diff --git a/content/test/data/accessibility/html/p-expected-win.txt b/content/test/data/accessibility/html/p-expected-win.txt
index 8888e09f..c97131c4 100644
--- a/content/test/data/accessibility/html/p-expected-win.txt
+++ b/content/test/data/accessibility/html/p-expected-win.txt
@@ -1,5 +1,7 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_STATICTEXT
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT
 ++IA2_ROLE_PARAGRAPH
 ++++ROLE_SYSTEM_STATICTEXT
-++ROLE_SYSTEM_STATICTEXT
+++IA2_ROLE_SECTION
+++++ROLE_SYSTEM_STATICTEXT
diff --git a/content/test/data/accessibility/html/ruby-expected-mac.txt b/content/test/data/accessibility/html/ruby-expected-mac.txt
index 6f4d19d..2889f43d 100644
--- a/content/test/data/accessibility/html/ruby-expected-mac.txt
+++ b/content/test/data/accessibility/html/ruby-expected-mac.txt
@@ -3,4 +3,5 @@
 ++++AXUnknown
 ++++++AXUnknown
 ++++++++AXStaticText AXValue='ruby text'
-++++++AXStaticText AXValue='ruby base'
+++++++AXGroup
+++++++++AXStaticText AXValue='ruby base'
diff --git a/content/test/data/accessibility/html/ruby-expected-win.txt b/content/test/data/accessibility/html/ruby-expected-win.txt
index eaee683..0eb29d7 100644
--- a/content/test/data/accessibility/html/ruby-expected-win.txt
+++ b/content/test/data/accessibility/html/ruby-expected-win.txt
@@ -3,4 +3,5 @@
 ++++IA2_ROLE_TEXT_FRAME
 ++++++ROLE_SYSTEM_STATICTEXT
 ++++++++ROLE_SYSTEM_STATICTEXT name='ruby text'
-++++++ROLE_SYSTEM_STATICTEXT name='ruby base'
+++++++IA2_ROLE_SECTION
+++++++++ROLE_SYSTEM_STATICTEXT name='ruby base'
diff --git a/content/test/data/accessibility/html/textarea-expected-mac.txt b/content/test/data/accessibility/html/textarea-expected-mac.txt
index a216fdcd..3868acc 100644
--- a/content/test/data/accessibility/html/textarea-expected-mac.txt
+++ b/content/test/data/accessibility/html/textarea-expected-mac.txt
@@ -1,3 +1,4 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXGroup AXRoleDescription='group'
-++++AXTextArea AXRoleDescription='text entry area' AXValue='The textarea tag defines a multi-line text input control.<newline>'
+++++AXTextArea AXRoleDescription='text entry area' AXValue='The textarea tag defines a multi-line text input control.
+'
diff --git a/content/test/data/accessibility/html/textarea-expected-win.txt b/content/test/data/accessibility/html/textarea-expected-win.txt
index 6e191eaf..5d07a2c 100644
--- a/content/test/data/accessibility/html/textarea-expected-win.txt
+++ b/content/test/data/accessibility/html/textarea-expected-win.txt
@@ -1,3 +1,4 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' n_selections=0
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>' n_selections=0
-++++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE IA2_STATE_SELECTABLE_TEXT ia2_hypertext='The textarea tag defines a multi-line text input control.<newline>' caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE IA2_STATE_SELECTABLE_TEXT ia2_hypertext='The textarea tag defines a multi-line text input control.
+' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/html/textarea-read-only-expected-mac.txt b/content/test/data/accessibility/html/textarea-read-only-expected-mac.txt
index a216fdcd..3868acc 100644
--- a/content/test/data/accessibility/html/textarea-read-only-expected-mac.txt
+++ b/content/test/data/accessibility/html/textarea-read-only-expected-mac.txt
@@ -1,3 +1,4 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXGroup AXRoleDescription='group'
-++++AXTextArea AXRoleDescription='text entry area' AXValue='The textarea tag defines a multi-line text input control.<newline>'
+++++AXTextArea AXRoleDescription='text entry area' AXValue='The textarea tag defines a multi-line text input control.
+'
diff --git a/content/test/data/accessibility/html/textarea-read-only-expected-win.txt b/content/test/data/accessibility/html/textarea-read-only-expected-win.txt
index 7b92308..97e76dd 100644
--- a/content/test/data/accessibility/html/textarea-read-only-expected-win.txt
+++ b/content/test/data/accessibility/html/textarea-read-only-expected-win.txt
@@ -1,3 +1,4 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' n_selections=0
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>' n_selections=0
-++++ROLE_SYSTEM_TEXT READONLY FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE IA2_STATE_SELECTABLE_TEXT ia2_hypertext='The textarea tag defines a multi-line text input control.<newline>' caret_offset=0 n_selections=0
+++++ROLE_SYSTEM_TEXT READONLY FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE IA2_STATE_SELECTABLE_TEXT ia2_hypertext='The textarea tag defines a multi-line text input control.
+' caret_offset=0 n_selections=0
diff --git a/content/test/data/accessibility/html/textarea-with-selection-expected-mac.txt b/content/test/data/accessibility/html/textarea-with-selection-expected-mac.txt
index a216fdcd..3868acc 100644
--- a/content/test/data/accessibility/html/textarea-with-selection-expected-mac.txt
+++ b/content/test/data/accessibility/html/textarea-with-selection-expected-mac.txt
@@ -1,3 +1,4 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXGroup AXRoleDescription='group'
-++++AXTextArea AXRoleDescription='text entry area' AXValue='The textarea tag defines a multi-line text input control.<newline>'
+++++AXTextArea AXRoleDescription='text entry area' AXValue='The textarea tag defines a multi-line text input control.
+'
diff --git a/content/test/data/accessibility/html/textarea-with-selection-expected-win.txt b/content/test/data/accessibility/html/textarea-with-selection-expected-win.txt
index 0ad3c98..f5011064 100644
--- a/content/test/data/accessibility/html/textarea-with-selection-expected-win.txt
+++ b/content/test/data/accessibility/html/textarea-with-selection-expected-win.txt
@@ -1,3 +1,4 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ia2_hypertext='<obj0>' caret_offset=1 n_selections=1 selection_start=0 selection_end=1
 ++IA2_ROLE_SECTION ia2_hypertext='<obj0>' caret_offset=1 n_selections=1 selection_start=0 selection_end=1
-++++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE IA2_STATE_SELECTABLE_TEXT ia2_hypertext='The textarea tag defines a multi-line text input control.<newline>' caret_offset=58 n_selections=1 selection_start=0 selection_end=58
+++++ROLE_SYSTEM_TEXT FOCUSABLE IA2_STATE_EDITABLE IA2_STATE_MULTI_LINE IA2_STATE_SELECTABLE_TEXT ia2_hypertext='The textarea tag defines a multi-line text input control.
+' caret_offset=58 n_selections=1 selection_start=0 selection_end=58
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index ad403af..af04734 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "9.11",
+  "version": "9.12",
   "entries": [
     {
       "id": 1,
@@ -1457,11 +1457,7 @@
         "type": "android"
       },
       "gl_vendor": "Qualcomm.*",
-      "gl_renderer": "Adreno \\(TM\\) 4.*",
-      "driver_version": {
-        "op": "<",
-        "value": "141.0"
-      },
+      "gl_renderer": "Adreno \\(TM\\) [45].*",
       "features": [
         "broken_egl_image_ref_counting"
       ]
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 8b4ef8b8..3ec461b 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -5,7 +5,7 @@
   project_id: "build"
   url: "https://chromium.googlesource.com/chromium/tools/build.git"
   branch: "master"
-  revision: "7d0005bcfebe9c9fcb121d9a9edfb09ffba36a17"
+  revision: "e8df1f233486b1d2d4c88393e6b2d26787ba3d2e"
 }
 deps {
   project_id: "depot_tools"
diff --git a/ios/chrome/browser/reading_list/reading_list_model.h b/ios/chrome/browser/reading_list/reading_list_model.h
index 40b3551..052bbe1 100644
--- a/ios/chrome/browser/reading_list/reading_list_model.h
+++ b/ios/chrome/browser/reading_list/reading_list_model.h
@@ -79,6 +79,10 @@
   // the reading list and read, move it to the top of unread if it is not here
   // already. This may trigger deletion of old read entries.
   virtual void MarkReadByURL(const GURL& url) = 0;
+  // If the |url| is in the reading list and read, mark it unread. If it is in
+  // the reading list and unread, move it to the top of read if it is not here
+  // already.
+  virtual void MarkUnreadByURL(const GURL& url) = 0;
 
   // Methods to mutate an entry. Will locate the relevant entry by URL. Does
   // nothing if the entry is not found.
diff --git a/ios/chrome/browser/reading_list/reading_list_model_impl.cc b/ios/chrome/browser/reading_list/reading_list_model_impl.cc
index 7951622..a07f7f2b9 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_impl.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_impl.cc
@@ -138,6 +138,30 @@
   return *unread_.begin();
 }
 
+void ReadingListModelImpl::MarkUnreadByURL(const GURL& url) {
+  DCHECK(loaded());
+  ReadingListEntry entry(url, std::string());
+  auto result = std::find(read_.begin(), read_.end(), entry);
+  if (result == read_.end())
+    return;
+
+  for (ReadingListModelObserver& observer : observers_) {
+    observer.ReadingListWillMoveEntry(this,
+                                      std::distance(read_.begin(), result));
+  }
+
+  unread_.insert(unread_.begin(), std::move(*result));
+  read_.erase(result);
+
+  if (storageLayer_ && !IsPerformingBatchUpdates()) {
+    storageLayer_->SavePersistentUnreadList(read_);
+    storageLayer_->SavePersistentReadList(unread_);
+  }
+  for (ReadingListModelObserver& observer : observers_) {
+    observer.ReadingListDidApplyChanges(this);
+  }
+}
+
 void ReadingListModelImpl::MarkReadByURL(const GURL& url) {
   DCHECK(loaded());
   ReadingListEntry entry(url, std::string());
diff --git a/ios/chrome/browser/reading_list/reading_list_model_impl.h b/ios/chrome/browser/reading_list/reading_list_model_impl.h
index d185c519..3293724 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_impl.h
+++ b/ios/chrome/browser/reading_list/reading_list_model_impl.h
@@ -49,6 +49,7 @@
                                    const std::string& title) override;
 
   void MarkReadByURL(const GURL& url) override;
+  void MarkUnreadByURL(const GURL& url) override;
 
   void SetEntryTitle(const GURL& url, const std::string& title) override;
   void SetEntryDistilledURL(const GURL& url,
diff --git a/ios/chrome/browser/reading_list/reading_list_model_observer.h b/ios/chrome/browser/reading_list/reading_list_model_observer.h
index e438e36..1d7bea8 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_observer.h
+++ b/ios/chrome/browser/reading_list/reading_list_model_observer.h
@@ -40,10 +40,9 @@
                                                 size_t index) {}
   virtual void ReadingListWillRemoveReadEntry(const ReadingListModel* model,
                                               size_t index) {}
-  // Invoked when elements are moved from unread to read. (The opposite does not
-  // exist as moving an element from read to unread is considered akin to
-  // deleting and re-adding it.) |index| is the original position in the unread
-  // list. The element will be added to the beginning of the read list.
+  // Invoked when elements are moved from unread to read or from read to unread.
+  // |index| is the original position in the origin list. The element will be
+  // added to the beginning of the target list.
   virtual void ReadingListWillMoveEntry(const ReadingListModel* model,
                                         size_t index) {}
 
diff --git a/ios/chrome/browser/reading_list/reading_list_model_unittest.cc b/ios/chrome/browser/reading_list/reading_list_model_unittest.cc
index e27ad4b9..873b330 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_unittest.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_unittest.cc
@@ -171,6 +171,28 @@
   EXPECT_EQ("sample", other_entry.Title());
 }
 
+TEST_F(ReadingListModelTest, UnreadEntry) {
+  // Setup.
+  model_->AddEntry(GURL("http://example.com"), "sample");
+  model_->MarkReadByURL(GURL("http://example.com"));
+  ClearCounts();
+  ASSERT_EQ(0ul, model_->unread_size());
+  ASSERT_EQ(1ul, model_->read_size());
+
+  // Action.
+  model_->MarkUnreadByURL(GURL("http://example.com"));
+
+  // Tests.
+  AssertObserverCount(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+  EXPECT_EQ(1ul, model_->unread_size());
+  EXPECT_EQ(0ul, model_->read_size());
+  EXPECT_TRUE(model_->HasUnseenEntries());
+
+  const ReadingListEntry& other_entry = model_->GetUnreadEntryAtIndex(0);
+  EXPECT_EQ(GURL("http://example.com"), other_entry.URL());
+  EXPECT_EQ("sample", other_entry.Title());
+}
+
 TEST_F(ReadingListModelTest, BatchUpdates) {
   auto token = model_->BeginBatchUpdates();
   AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h
index 51dad819..95fd7fc 100644
--- a/media/base/video_decoder.h
+++ b/media/base/video_decoder.h
@@ -79,8 +79,7 @@
   // frame are returned via the provided callback. Some decoders may allow
   // decoding multiple buffers in parallel. Callers should call
   // GetMaxDecodeRequests() to get number of buffers that may be decoded in
-  // parallel. Decoder must call |decode_cb| in the same order in which Decode()
-  // is called.
+  // parallel.
   //
   // Implementations guarantee that the |decode_cb| will not be called from
   // within this method, and that it will be called even if Decode() is never
diff --git a/media/blink/video_frame_compositor.cc b/media/blink/video_frame_compositor.cc
index 96192f5..7bc98164 100644
--- a/media/blink/video_frame_compositor.cc
+++ b/media/blink/video_frame_compositor.cc
@@ -193,8 +193,10 @@
     bool repaint_duplicate_frame) {
   DCHECK(compositor_task_runner_->BelongsToCurrentThread());
 
-  if (!repaint_duplicate_frame && frame == current_frame_)
+  if (frame && current_frame_ && !repaint_duplicate_frame &&
+      frame->unique_id() == current_frame_->unique_id()) {
     return false;
+  }
 
   // Set the flag indicating that the current frame is unrendered, if we get a
   // subsequent PutCurrentFrame() call it will mark it as rendered.
diff --git a/media/midi/midi_manager.cc b/media/midi/midi_manager.cc
index 9157c73..308982d4 100644
--- a/media/midi/midi_manager.cc
+++ b/media/midi/midi_manager.cc
@@ -17,6 +17,7 @@
 namespace {
 
 using Sample = base::HistogramBase::Sample;
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 // If many users have more devices, this number will be increased.
@@ -202,7 +203,7 @@
     client->AddOutputPort(info);
 }
 
-void MidiManager::SetInputPortState(uint32_t port_index, MidiPortState state) {
+void MidiManager::SetInputPortState(uint32_t port_index, PortState state) {
   base::AutoLock auto_lock(lock_);
   DCHECK_LT(port_index, input_ports_.size());
   input_ports_[port_index].state = state;
@@ -210,7 +211,7 @@
     client->SetInputPortState(port_index, state);
 }
 
-void MidiManager::SetOutputPortState(uint32_t port_index, MidiPortState state) {
+void MidiManager::SetOutputPortState(uint32_t port_index, PortState state) {
   base::AutoLock auto_lock(lock_);
   DCHECK_LT(port_index, output_ports_.size());
   output_ports_[port_index].state = state;
diff --git a/media/midi/midi_manager.h b/media/midi/midi_manager.h
index 544d396..9d0896a3 100644
--- a/media/midi/midi_manager.h
+++ b/media/midi/midi_manager.h
@@ -40,8 +40,10 @@
 
   // SetInputPortState() and SetOutputPortState() are called to notify a known
   // device gets disconnected, or connected again.
-  virtual void SetInputPortState(uint32_t port_index, MidiPortState state) = 0;
-  virtual void SetOutputPortState(uint32_t port_index, MidiPortState state) = 0;
+  virtual void SetInputPortState(uint32_t port_index,
+                                 mojom::PortState state) = 0;
+  virtual void SetOutputPortState(uint32_t port_index,
+                                  mojom::PortState state) = 0;
 
   // CompleteStartSession() is called when platform dependent preparation is
   // finished.
@@ -145,8 +147,8 @@
 
   void AddInputPort(const MidiPortInfo& info);
   void AddOutputPort(const MidiPortInfo& info);
-  void SetInputPortState(uint32_t port_index, MidiPortState state);
-  void SetOutputPortState(uint32_t port_index, MidiPortState state);
+  void SetInputPortState(uint32_t port_index, mojom::PortState state);
+  void SetOutputPortState(uint32_t port_index, mojom::PortState state);
 
   // Dispatches to all clients.
   // TODO(toyoshim): Fix the mac implementation to use
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc
index 8a8fb9cd..d99751b 100644
--- a/media/midi/midi_manager_alsa.cc
+++ b/media/midi/midi_manager_alsa.cc
@@ -32,7 +32,8 @@
 
 namespace {
 
-using midi::mojom::Result;
+using mojom::PortState;
+using mojom::Result;
 
 // Per-output buffer. This can be smaller, but then large sysex messages
 // will be (harmlessly) split across multiple seq events. This should
@@ -1202,11 +1203,11 @@
         case MidiPort::Type::kInput:
           source_map_.erase(
               AddrToInt(old_port->client_id(), old_port->port_id()));
-          SetInputPortState(web_port_index, MIDI_PORT_DISCONNECTED);
+          SetInputPortState(web_port_index, PortState::DISCONNECTED);
           break;
         case MidiPort::Type::kOutput:
           DeleteAlsaOutputPort(web_port_index);
-          SetOutputPortState(web_port_index, MIDI_PORT_DISCONNECTED);
+          SetOutputPortState(web_port_index, PortState::DISCONNECTED);
           break;
       }
     }
@@ -1231,7 +1232,7 @@
       it = new_port_state->erase(it);
 
       MidiPortInfo info(opaque_key, manufacturer, port_name, version,
-                        MIDI_PORT_OPENED);
+                        PortState::OPENED);
       switch (type) {
         case MidiPort::Type::kInput:
           if (Subscribe(web_port_index, client_id, port_id))
@@ -1253,12 +1254,12 @@
         case MidiPort::Type::kInput:
           if (Subscribe(web_port_index, (*old_port)->client_id(),
                         (*old_port)->port_id()))
-            SetInputPortState(web_port_index, MIDI_PORT_OPENED);
+            SetInputPortState(web_port_index, PortState::OPENED);
           break;
         case MidiPort::Type::kOutput:
           if (CreateAlsaOutputPort(web_port_index, (*old_port)->client_id(),
                                    (*old_port)->port_id()))
-            SetOutputPortState(web_port_index, MIDI_PORT_OPENED);
+            SetOutputPortState(web_port_index, PortState::OPENED);
           break;
       }
       (*old_port)->set_connected(true);
diff --git a/media/midi/midi_manager_android.cc b/media/midi/midi_manager_android.cc
index b9aec01..c04b62d 100644
--- a/media/midi/midi_manager_android.cc
+++ b/media/midi/midi_manager_android.cc
@@ -17,6 +17,7 @@
 #include "media/midi/usb_midi_device_factory_android.h"
 
 using base::android::JavaParamRef;
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 namespace midi {
@@ -71,11 +72,11 @@
     return;
   }
   DCHECK_EQ(output_ports().size(), all_output_ports_.size());
-  if (output_ports()[port_index].state == MIDI_PORT_CONNECTED) {
+  if (output_ports()[port_index].state == PortState::CONNECTED) {
     // We treat send call as implicit open.
     // TODO(yhirano): Implement explicit open operation from the renderer.
     if (all_output_ports_[port_index]->Open()) {
-      SetOutputPortState(port_index, MIDI_PORT_OPENED);
+      SetOutputPortState(port_index, PortState::OPENED);
     } else {
       // We cannot open the port. It's useless to send data to such a port.
       return;
@@ -133,12 +134,12 @@
       for (auto* port : device->input_ports()) {
         DCHECK(input_port_to_index_.end() != input_port_to_index_.find(port));
         size_t index = input_port_to_index_[port];
-        SetInputPortState(index, MIDI_PORT_DISCONNECTED);
+        SetInputPortState(index, PortState::DISCONNECTED);
       }
       for (auto* port : device->output_ports()) {
         DCHECK(output_port_to_index_.end() != output_port_to_index_.find(port));
         size_t index = output_port_to_index_[port];
-        SetOutputPortState(index, MIDI_PORT_DISCONNECTED);
+        SetOutputPortState(index, PortState::DISCONNECTED);
       }
     }
   }
@@ -149,7 +150,7 @@
     // We implicitly open input ports here, because there are no signal
     // from the renderer when to open.
     // TODO(yhirano): Implement open operation in Blink.
-    MidiPortState state = port->Open() ? MIDI_PORT_OPENED : MIDI_PORT_CONNECTED;
+    PortState state = port->Open() ? PortState::OPENED : PortState::CONNECTED;
 
     const size_t index = all_input_ports_.size();
     all_input_ports_.push_back(port);
@@ -177,7 +178,7 @@
     output_port_to_index_.insert(std::make_pair(port, index));
     AddOutputPort(
         MidiPortInfo(id, device->GetManufacturer(), device->GetProductName(),
-                     device->GetDeviceVersion(), MIDI_PORT_CONNECTED));
+                     device->GetDeviceVersion(), PortState::CONNECTED));
   }
   devices_.push_back(device.release());
 }
diff --git a/media/midi/midi_manager_mac.cc b/media/midi/midi_manager_mac.cc
index 306b599..4e35863 100644
--- a/media/midi/midi_manager_mac.cc
+++ b/media/midi/midi_manager_mac.cc
@@ -18,6 +18,7 @@
 using base::IntToString;
 using base::SysCFStringRefToUTF8;
 using std::string;
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 // NB: System MIDI types are pointer types in 32-bit and integer types in
@@ -87,7 +88,7 @@
                   << result;
   }
 
-  const MidiPortState state = MIDI_PORT_OPENED;
+  const PortState state = PortState::OPENED;
   return MidiPortInfo(id, manufacturer, name, version, state);
 }
 
@@ -265,7 +266,7 @@
               coremidi_input_, endpoint, reinterpret_cast<void*>(endpoint));
         }
       } else {
-        SetInputPortState(it->second, MIDI_PORT_OPENED);
+        SetInputPortState(it->second, PortState::OPENED);
       }
     } else if (notification->childType == kMIDIObjectType_Destination) {
       // Attaching device is an output device.
@@ -278,7 +279,7 @@
           AddOutputPort(info);
         }
       } else {
-        SetOutputPortState(it - destinations_.begin(), MIDI_PORT_OPENED);
+        SetOutputPortState(it - destinations_.begin(), PortState::OPENED);
       }
     }
   } else if (kMIDIMsgObjectRemoved == message->messageID) {
@@ -291,12 +292,12 @@
       // Detaching device is an input device.
       auto it = source_map_.find(endpoint);
       if (it != source_map_.end())
-        SetInputPortState(it->second, MIDI_PORT_DISCONNECTED);
+        SetInputPortState(it->second, PortState::DISCONNECTED);
     } else if (notification->childType == kMIDIObjectType_Destination) {
       // Detaching device is an output device.
       auto it = std::find(destinations_.begin(), destinations_.end(), endpoint);
       if (it != destinations_.end())
-        SetOutputPortState(it - destinations_.begin(), MIDI_PORT_DISCONNECTED);
+        SetOutputPortState(it - destinations_.begin(), PortState::DISCONNECTED);
     }
   }
 }
diff --git a/media/midi/midi_manager_mac_unittest.cc b/media/midi/midi_manager_mac_unittest.cc
index f0871f7d..048ac5f2 100644
--- a/media/midi/midi_manager_mac_unittest.cc
+++ b/media/midi/midi_manager_mac_unittest.cc
@@ -21,6 +21,7 @@
 
 namespace {
 
+using mojom::PortState;
 using mojom::Result;
 
 void Noop(const MIDIPacketList*, void*, void*) {}
@@ -51,8 +52,8 @@
     info_ = info;
     wait_for_port_ = false;
   }
-  void SetInputPortState(uint32_t port_index, MidiPortState state) override {}
-  void SetOutputPortState(uint32_t port_index, MidiPortState state) override {}
+  void SetInputPortState(uint32_t port_index, PortState state) override {}
+  void SetOutputPortState(uint32_t port_index, PortState state) override {}
 
   void CompleteStartSession(Result result) override {
     base::AutoLock lock(lock_);
diff --git a/media/midi/midi_manager_unittest.cc b/media/midi/midi_manager_unittest.cc
index 5a073b5..6b680c35 100644
--- a/media/midi/midi_manager_unittest.cc
+++ b/media/midi/midi_manager_unittest.cc
@@ -24,6 +24,7 @@
 
 namespace {
 
+using mojom::PortState;
 using mojom::Result;
 
 class FakeMidiManager : public MidiManager {
@@ -73,8 +74,8 @@
   // MidiManagerClient implementation.
   void AddInputPort(const MidiPortInfo& info) override {}
   void AddOutputPort(const MidiPortInfo& info) override {}
-  void SetInputPortState(uint32_t port_index, MidiPortState state) override {}
-  void SetOutputPortState(uint32_t port_index, MidiPortState state) override {}
+  void SetInputPortState(uint32_t port_index, PortState state) override {}
+  void SetOutputPortState(uint32_t port_index, PortState state) override {}
 
   void CompleteStartSession(Result result) override {
     EXPECT_TRUE(wait_for_result_);
diff --git a/media/midi/midi_manager_usb.cc b/media/midi/midi_manager_usb.cc
index 35ab6a5..70b2fa9 100644
--- a/media/midi/midi_manager_usb.cc
+++ b/media/midi/midi_manager_usb.cc
@@ -14,6 +14,7 @@
 
 namespace midi {
 
+using mojom::PortState;
 using mojom::Result;
 
 MidiManagerUsb::MidiManagerUsb(std::unique_ptr<UsbMidiDevice::Factory> factory)
@@ -95,13 +96,13 @@
   UsbMidiDevice* device = devices_[index];
   for (size_t i = 0; i < output_streams_.size(); ++i) {
     if (output_streams_[i]->jack().device == device) {
-      SetOutputPortState(static_cast<uint32_t>(i), MIDI_PORT_DISCONNECTED);
+      SetOutputPortState(static_cast<uint32_t>(i), PortState::DISCONNECTED);
     }
   }
   const std::vector<UsbMidiJack>& input_jacks = input_stream_->jacks();
   for (size_t i = 0; i < input_jacks.size(); ++i) {
     if (input_jacks[i].device == device) {
-      SetInputPortState(static_cast<uint32_t>(i), MIDI_PORT_DISCONNECTED);
+      SetInputPortState(static_cast<uint32_t>(i), PortState::DISCONNECTED);
     }
   }
 }
@@ -156,12 +157,12 @@
     if (jacks[j].direction() == UsbMidiJack::DIRECTION_OUT) {
       output_streams_.push_back(new UsbMidiOutputStream(jacks[j]));
       AddOutputPort(MidiPortInfo(id, manufacturer, product_name, version,
-                                 MIDI_PORT_OPENED));
+                                 PortState::OPENED));
     } else {
       DCHECK_EQ(jacks[j].direction(), UsbMidiJack::DIRECTION_IN);
       input_stream_->Add(jacks[j]);
       AddInputPort(MidiPortInfo(id, manufacturer, product_name, version,
-                                MIDI_PORT_OPENED));
+                                PortState::OPENED));
     }
   }
   return true;
diff --git a/media/midi/midi_manager_usb_unittest.cc b/media/midi/midi_manager_usb_unittest.cc
index 3359439..e73bb45 100644
--- a/media/midi/midi_manager_usb_unittest.cc
+++ b/media/midi/midi_manager_usb_unittest.cc
@@ -22,6 +22,7 @@
 
 namespace {
 
+using mojom::PortState;
 using mojom::Result;
 
 template<typename T, size_t N>
@@ -109,9 +110,9 @@
     output_ports_.push_back(info);
   }
 
-  void SetInputPortState(uint32_t port_index, MidiPortState state) override {}
+  void SetInputPortState(uint32_t port_index, PortState state) override {}
 
-  void SetOutputPortState(uint32_t port_index, MidiPortState state) override {}
+  void SetOutputPortState(uint32_t port_index, PortState state) override {}
 
   void CompleteStartSession(Result result) override {
     complete_start_session_ = true;
diff --git a/media/midi/midi_manager_win.cc b/media/midi/midi_manager_win.cc
index 75d9ce0..d5b85d12 100644
--- a/media/midi/midi_manager_win.cc
+++ b/media/midi/midi_manager_win.cc
@@ -52,6 +52,7 @@
 namespace midi {
 namespace {
 
+using mojom::PortState;
 using mojom::Result;
 
 static const size_t kBufferLength = 32 * 1024;
@@ -681,7 +682,7 @@
           GetManufacturerName(state_device_info),
           base::WideToUTF8(state_device_info.product_name),
           MmversionToString(state_device_info.driver_version),
-          MIDI_PORT_OPENED);
+          PortState::OPENED);
       task_thread_.task_runner()->PostTask(
           FROM_HERE, base::Bind(&MidiServiceWinImpl::AddInputPortOnTaskThread,
                                 base::Unretained(this), port_info));
@@ -690,7 +691,7 @@
           FROM_HERE,
           base::Bind(&MidiServiceWinImpl::SetInputPortStateOnTaskThread,
                      base::Unretained(this), port_number,
-                     MidiPortState::MIDI_PORT_CONNECTED));
+                     PortState::CONNECTED));
     }
   }
 
@@ -782,7 +783,7 @@
         FROM_HERE,
         base::Bind(&MidiServiceWinImpl::SetInputPortStateOnTaskThread,
                    base::Unretained(this), port_number,
-                   MIDI_PORT_DISCONNECTED));
+                   PortState::DISCONNECTED));
   }
 
   static void CALLBACK
@@ -859,7 +860,7 @@
           GetManufacturerName(state_device_info),
           base::WideToUTF8(state_device_info.product_name),
           MmversionToString(state_device_info.driver_version),
-          MIDI_PORT_OPENED);
+          PortState::OPENED);
       task_thread_.task_runner()->PostTask(
           FROM_HERE, base::Bind(&MidiServiceWinImpl::AddOutputPortOnTaskThread,
                                 base::Unretained(this), port_info));
@@ -867,7 +868,8 @@
       task_thread_.task_runner()->PostTask(
           FROM_HERE,
           base::Bind(&MidiServiceWinImpl::SetOutputPortStateOnTaskThread,
-                     base::Unretained(this), port_number, MIDI_PORT_CONNECTED));
+                     base::Unretained(this), port_number,
+                     PortState::CONNECTED));
     }
   }
 
@@ -905,7 +907,7 @@
         FROM_HERE,
         base::Bind(&MidiServiceWinImpl::SetOutputPortStateOnTaskThread,
                    base::Unretained(this), port_number,
-                   MIDI_PORT_DISCONNECTED));
+                   PortState::DISCONNECTED));
   }
 
   /////////////////////////////////////////////////////////////////////////////
@@ -1077,13 +1079,12 @@
     delegate_->OnAddOutputPort(info);
   }
 
-  void SetInputPortStateOnTaskThread(uint32_t port_index, MidiPortState state) {
+  void SetInputPortStateOnTaskThread(uint32_t port_index, PortState state) {
     AssertOnTaskThread();
     delegate_->OnSetInputPortState(port_index, state);
   }
 
-  void SetOutputPortStateOnTaskThread(uint32_t port_index,
-                                      MidiPortState state) {
+  void SetOutputPortStateOnTaskThread(uint32_t port_index, PortState state) {
     AssertOnTaskThread();
     delegate_->OnSetOutputPortState(port_index, state);
   }
@@ -1177,13 +1178,12 @@
   AddOutputPort(info);
 }
 
-void MidiManagerWin::OnSetInputPortState(uint32_t port_index,
-                                         MidiPortState state) {
+void MidiManagerWin::OnSetInputPortState(uint32_t port_index, PortState state) {
   SetInputPortState(port_index, state);
 }
 
 void MidiManagerWin::OnSetOutputPortState(uint32_t port_index,
-                                          MidiPortState state) {
+                                          PortState state) {
   SetOutputPortState(port_index, state);
 }
 
diff --git a/media/midi/midi_manager_win.h b/media/midi/midi_manager_win.h
index 4303163..e791a3b5 100644
--- a/media/midi/midi_manager_win.h
+++ b/media/midi/midi_manager_win.h
@@ -14,6 +14,7 @@
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "media/midi/midi_manager.h"
+#include "media/midi/midi_service.mojom.h"
 
 namespace midi {
 
@@ -24,9 +25,9 @@
   virtual void OnAddInputPort(MidiPortInfo info) = 0;
   virtual void OnAddOutputPort(MidiPortInfo info) = 0;
   virtual void OnSetInputPortState(uint32_t port_index,
-                                   MidiPortState state) = 0;
+                                   mojom::PortState state) = 0;
   virtual void OnSetOutputPortState(uint32_t port_index,
-                                    MidiPortState state) = 0;
+                                    mojom::PortState state) = 0;
   virtual void OnReceiveMidiData(uint32_t port_index,
                                  const std::vector<uint8_t>& data,
                                  base::TimeTicks time) = 0;
@@ -60,8 +61,8 @@
   void OnCompleteInitialization(mojom::Result result) final;
   void OnAddInputPort(MidiPortInfo info) final;
   void OnAddOutputPort(MidiPortInfo info) final;
-  void OnSetInputPortState(uint32_t port_index, MidiPortState state) final;
-  void OnSetOutputPortState(uint32_t port_index, MidiPortState state) final;
+  void OnSetInputPortState(uint32_t port_index, mojom::PortState state) final;
+  void OnSetOutputPortState(uint32_t port_index, mojom::PortState state) final;
   void OnReceiveMidiData(uint32_t port_index,
                          const std::vector<uint8_t>& data,
                          base::TimeTicks time) final;
diff --git a/media/midi/midi_manager_winrt.cc b/media/midi/midi_manager_winrt.cc
index 285ef05..8575154 100644
--- a/media/midi/midi_manager_winrt.cc
+++ b/media/midi/midi_manager_winrt.cc
@@ -42,6 +42,7 @@
 using namespace ABI::Windows::Storage::Streams;
 
 using base::win::ScopedComPtr;
+using mojom::PortState;
 using mojom::Result;
 
 // Helpers for printing HRESULTs.
@@ -649,7 +650,7 @@
       return;
     }
 
-    SetPortState(port->index, MIDI_PORT_DISCONNECTED);
+    SetPortState(port->index, PortState::DISCONNECTED);
 
     RemovePortEventHandlers(port);
     port->handle = nullptr;
@@ -691,7 +692,7 @@
       GetDriverInfoFromDeviceId(dev_id, &manufacturer, &driver_version);
 
       AddPort(MidiPortInfo(dev_id, manufacturer, port_names_[dev_id],
-                           driver_version, MIDI_PORT_OPENED));
+                           driver_version, PortState::OPENED));
 
       port = new MidiPort<InterfaceType>;
       port->index = static_cast<uint32_t>(port_ids_.size());
@@ -699,7 +700,7 @@
       ports_[dev_id].reset(port);
       port_ids_.push_back(dev_id);
     } else {
-      SetPortState(port->index, MIDI_PORT_CONNECTED);
+      SetPortState(port->index, PortState::CONNECTED);
     }
 
     port->handle = handle;
@@ -724,7 +725,7 @@
   virtual void AddPort(MidiPortInfo info) = 0;
 
   // Calls midi_manager_->Set{Input,Output}PortState.
-  virtual void SetPortState(uint32_t port_index, MidiPortState state) = 0;
+  virtual void SetPortState(uint32_t port_index, PortState state) = 0;
 
   // WeakPtrFactory has to be declared in derived class, use this method to
   // retrieve upcasted WeakPtr for posting tasks.
@@ -849,7 +850,7 @@
 
   void AddPort(MidiPortInfo info) final { midi_manager_->AddInputPort(info); }
 
-  void SetPortState(uint32_t port_index, MidiPortState state) final {
+  void SetPortState(uint32_t port_index, PortState state) final {
     midi_manager_->SetInputPortState(port_index, state);
   }
 
@@ -890,7 +891,7 @@
   // MidiPortManager overrides:
   void AddPort(MidiPortInfo info) final { midi_manager_->AddOutputPort(info); }
 
-  void SetPortState(uint32_t port_index, MidiPortState state) final {
+  void SetPortState(uint32_t port_index, PortState state) final {
     midi_manager_->SetOutputPortState(port_index, state);
   }
 
diff --git a/media/midi/midi_port_info.cc b/media/midi/midi_port_info.cc
index 29bae144..90cbebf 100644
--- a/media/midi/midi_port_info.cc
+++ b/media/midi/midi_port_info.cc
@@ -6,13 +6,15 @@
 
 namespace midi {
 
+using mojom::PortState;
+
 MidiPortInfo::MidiPortInfo() {}
 
 MidiPortInfo::MidiPortInfo(const std::string& in_id,
                            const std::string& in_manufacturer,
                            const std::string& in_name,
                            const std::string& in_version,
-                           MidiPortState in_state)
+                           PortState in_state)
     : id(in_id),
       manufacturer(in_manufacturer),
       name(in_name),
diff --git a/media/midi/midi_port_info.h b/media/midi/midi_port_info.h
index 3bd842c..26895862 100644
--- a/media/midi/midi_port_info.h
+++ b/media/midi/midi_port_info.h
@@ -9,23 +9,17 @@
 #include <vector>
 
 #include "media/midi/midi_export.h"
+#include "media/midi/midi_service.mojom.h"
 
 namespace midi {
 
-enum MidiPortState {
-  MIDI_PORT_DISCONNECTED,
-  MIDI_PORT_CONNECTED,
-  MIDI_PORT_OPENED,
-  MIDI_PORT_STATE_LAST = MIDI_PORT_OPENED,
-};
-
 struct MIDI_EXPORT MidiPortInfo final {
   MidiPortInfo();
   MidiPortInfo(const std::string& in_id,
                const std::string& in_manufacturer,
                const std::string& in_name,
                const std::string& in_version,
-               MidiPortState in_state);
+               mojom::PortState in_state);
 
   MidiPortInfo(const MidiPortInfo& info);
   ~MidiPortInfo();
@@ -34,7 +28,7 @@
   std::string manufacturer;
   std::string name;
   std::string version;
-  MidiPortState state;
+  mojom::PortState state;
 };
 
 using MidiPortInfoList = std::vector<MidiPortInfo>;
diff --git a/media/midi/midi_service.mojom b/media/midi/midi_service.mojom
index 92959bd..42601211 100644
--- a/media/midi/midi_service.mojom
+++ b/media/midi/midi_service.mojom
@@ -22,6 +22,15 @@
   MAX = INITIALIZATION_ERROR,
 };
 
-// TODO(toyoshim): MidiPortState, MidiPortInfo, and MidiService should be
+enum PortState {
+  DISCONNECTED,
+  CONNECTED,
+  OPENED,
+  // TODO(toyosim): Remove |LAST| once IPC is replaced with Mojo.
+  // http://crbug.com/582327
+  LAST = OPENED,
+};
+
+// TODO(toyoshim): MidiPortInfo, and MidiService should be
 // declared here.
 // http://crbug.com/582327
diff --git a/media/mojo/clients/mojo_video_decoder.cc b/media/mojo/clients/mojo_video_decoder.cc
index ee293e6..51f61cc 100644
--- a/media/mojo/clients/mojo_video_decoder.cc
+++ b/media/mojo/clients/mojo_video_decoder.cc
@@ -32,9 +32,11 @@
 
 MojoVideoDecoder::~MojoVideoDecoder() {
   DVLOG(1) << __FUNCTION__;
+  Stop();
 }
 
 std::string MojoVideoDecoder::GetDisplayName() const {
+  // TODO(sandersd): Build the name including information from the remote end.
   return "MojoVideoDecoder";
 }
 
@@ -55,6 +57,7 @@
     return;
   }
 
+  initialized_ = false;
   init_cb_ = init_cb;
   output_cb_ = output_cb;
   remote_decoder_->Initialize(
@@ -62,17 +65,20 @@
       base::Bind(&MojoVideoDecoder::OnInitializeDone, base::Unretained(this)));
 }
 
-// TODO(sandersd): Remove this indirection once a working decoder has been
-// brought up.
-void MojoVideoDecoder::OnInitializeDone(bool status) {
+void MojoVideoDecoder::OnInitializeDone(bool status,
+                                        bool needs_bitstream_conversion,
+                                        int32_t max_decode_requests) {
   DVLOG(1) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
+  initialized_ = status;
+  needs_bitstream_conversion_ = needs_bitstream_conversion;
+  max_decode_requests_ = max_decode_requests;
   base::ResetAndReturn(&init_cb_).Run(status);
 }
 
 void MojoVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
                               const DecodeCB& decode_cb) {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   if (has_connection_error_) {
@@ -89,23 +95,32 @@
     return;
   }
 
-  // TODO(sandersd): Support more than one decode at a time.
-  decode_cb_ = decode_cb;
-  remote_decoder_->Decode(
-      std::move(mojo_buffer),
-      base::Bind(&MojoVideoDecoder::OnDecodeDone, base::Unretained(this)));
+  uint64_t decode_id = decode_counter_++;
+  pending_decodes_[decode_id] = decode_cb;
+  remote_decoder_->Decode(std::move(mojo_buffer),
+                          base::Bind(&MojoVideoDecoder::OnDecodeDone,
+                                     base::Unretained(this), decode_id));
 }
 
 void MojoVideoDecoder::OnVideoFrameDecoded(mojom::VideoFramePtr frame) {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   output_cb_.Run(frame.To<scoped_refptr<VideoFrame>>());
 }
 
-void MojoVideoDecoder::OnDecodeDone(DecodeStatus status) {
-  DVLOG(1) << __FUNCTION__;
+void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id, DecodeStatus status) {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
-  base::ResetAndReturn(&decode_cb_).Run(status);
+
+  auto it = pending_decodes_.find(decode_id);
+  if (it == pending_decodes_.end()) {
+    DLOG(ERROR) << "Decode request " << decode_id << " not found";
+    Stop();
+    return;
+  }
+  DecodeCB decode_cb = it->second;
+  pending_decodes_.erase(it);
+  decode_cb.Run(status);
 }
 
 void MojoVideoDecoder::Reset(const base::Closure& reset_cb) {
@@ -129,22 +144,24 @@
 }
 
 bool MojoVideoDecoder::NeedsBitstreamConversion() const {
-  DVLOG(1) << __FUNCTION__;
-  return false;
+  DVLOG(3) << __FUNCTION__;
+  DCHECK(initialized_);
+  return needs_bitstream_conversion_;
 }
 
 bool MojoVideoDecoder::CanReadWithoutStalling() const {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(3) << __FUNCTION__;
   return true;
 }
 
 int MojoVideoDecoder::GetMaxDecodeRequests() const {
-  DVLOG(1) << __FUNCTION__;
-  return 1;
+  DVLOG(3) << __FUNCTION__;
+  DCHECK(initialized_);
+  return max_decode_requests_;
 }
 
 void MojoVideoDecoder::BindRemoteDecoder() {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(3) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!remote_decoder_bound_);
 
@@ -152,8 +169,9 @@
   remote_decoder_bound_ = true;
 
   remote_decoder_.set_connection_error_handler(
-      base::Bind(&MojoVideoDecoder::OnConnectionError, base::Unretained(this)));
+      base::Bind(&MojoVideoDecoder::Stop, base::Unretained(this)));
 
+  // TODO(sandersd): Does this need its own error handler?
   mojom::VideoDecoderClientAssociatedPtrInfo client_ptr_info;
   client_binding_.Bind(&client_ptr_info, remote_decoder_.associated_group());
 
@@ -166,19 +184,19 @@
                              std::move(remote_consumer_handle));
 }
 
-void MojoVideoDecoder::OnConnectionError() {
-  DVLOG(1) << __FUNCTION__;
+void MojoVideoDecoder::Stop() {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   has_connection_error_ = true;
 
-  // TODO(sandersd): Write a wrapper class (like BindToCurrentLoop) that handles
-  // the lifetime of callbacks like this.
   if (!init_cb_.is_null())
     base::ResetAndReturn(&init_cb_).Run(false);
-  // TODO(sandersd): If there is a pending reset, should these be aborted?
-  if (!decode_cb_.is_null())
-    base::ResetAndReturn(&decode_cb_).Run(DecodeStatus::DECODE_ERROR);
+
+  for (const auto& pending_decode : pending_decodes_)
+    pending_decode.second.Run(DecodeStatus::DECODE_ERROR);
+  pending_decodes_.clear();
+
   if (!reset_cb_.is_null())
     base::ResetAndReturn(&reset_cb_).Run();
 }
diff --git a/media/mojo/clients/mojo_video_decoder.h b/media/mojo/clients/mojo_video_decoder.h
index 1c0facc0..78d36c3 100644
--- a/media/mojo/clients/mojo_video_decoder.h
+++ b/media/mojo/clients/mojo_video_decoder.h
@@ -50,12 +50,16 @@
   void OnVideoFrameDecoded(mojom::VideoFramePtr frame) final;
 
  private:
-  void OnInitializeDone(bool status);
-  void OnDecodeDone(DecodeStatus status);
+  void OnInitializeDone(bool status,
+                        bool needs_bitstream_conversion,
+                        int32_t max_decode_requests);
+  void OnDecodeDone(uint64_t decode_id, DecodeStatus status);
   void OnResetDone();
 
   void BindRemoteDecoder();
-  void OnConnectionError();
+
+  // Cleans up callbacks and blocks future calls.
+  void Stop();
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   GpuVideoAcceleratorFactories* gpu_factories_;
@@ -66,7 +70,8 @@
 
   InitCB init_cb_;
   OutputCB output_cb_;
-  DecodeCB decode_cb_;
+  uint64_t decode_counter_ = 0;
+  std::map<uint64_t, DecodeCB> pending_decodes_;
   base::Closure reset_cb_;
 
   mojom::VideoDecoderPtr remote_decoder_;
@@ -75,6 +80,10 @@
   bool has_connection_error_ = false;
   mojo::AssociatedBinding<VideoDecoderClient> client_binding_;
 
+  bool initialized_ = false;
+  bool needs_bitstream_conversion_ = false;
+  int32_t max_decode_requests_ = 1;
+
   DISALLOW_COPY_AND_ASSIGN(MojoVideoDecoder);
 };
 
diff --git a/media/mojo/interfaces/video_decoder.mojom b/media/mojo/interfaces/video_decoder.mojom
index f0f4ae32..b0bcf94 100644
--- a/media/mojo/interfaces/video_decoder.mojom
+++ b/media/mojo/interfaces/video_decoder.mojom
@@ -23,24 +23,29 @@
   //
   // If |low_delay| is true, the decoder must output frames as soon as possible;
   // in particular, it must not wait for another Decode() request, except as
-  // required for frame reordering.
-  Initialize(VideoDecoderConfig config, bool low_delay) => (bool success);
+  // required for frame reordering. Implementations must fail initialization if
+  // they cannot satisfy this requirement.
+  //
+  // On completion, the callback also includes |needs_bitstream_conversion|,
+  // indicating whether decode buffers need bitstream conversion, and
+  // |max_decode_requests|, the maximum number of concurrent Decode() requests
+  // the implementation supports.
+  Initialize(VideoDecoderConfig config, bool low_delay) =>
+      (bool success, bool needs_bitstream_conversion,
+       int32 max_decode_requests);
 
   // Request decoding of exactly one frame or an EOS buffer. This must not be
-  // called while there are pending Configure(), Reset(), or Decode() requests.
+  // called while there are pending Initialize(), Reset(), or Decode(EOS)
+  // requests.
   //
   // Implementations must eventually execute the callback, even if Decode() is
   // not called again. It is not required that the decode status match the
-  // actual result of decoding a frame; only that decode errors are eventually
-  // reported (such as at EOS). The purpose of the callback is primarily for
-  // Decode() rate control.
+  // actual result of decoding the buffer, only that decode errors are
+  // eventually reported (such as at EOS).
   //
-  // If |buffer| is an EOS buffer, implementations execute all other pending
-  // Decode() callbacks and output all pending frames before executing the EOS
-  // buffer Decode() callback. (That is, they must flush.)
-  //
-  // TODO(sandersd): Plumb GetMaxDecodeRequests() so that parallel Decode()
-  // requests can be allowed.
+  // If |buffer| is an EOS buffer, implementations must execute all other
+  // pending Decode() callbacks and output all pending frames before executing
+  // the Decode(EOS) callback. (That is, they must flush.)
   Decode(DecoderBuffer buffer) => (DecodeStatus status);
 
   // Reset the decoder. All ongoing Decode() requests must be completed or
diff --git a/media/mojo/services/mojo_video_decoder_service.cc b/media/mojo/services/mojo_video_decoder_service.cc
index 0150f0d..7b3d6bdc 100644
--- a/media/mojo/services/mojo_video_decoder_service.cc
+++ b/media/mojo/services/mojo_video_decoder_service.cc
@@ -37,7 +37,7 @@
   if (decoder_)
     return;
 
-  // TODO(sandersd): Provide callback for requesting a stub.
+  // TODO(sandersd): Provide callback for requesting a GpuCommandBufferStub.
   decoder_ = mojo_media_client_->CreateVideoDecoder(
       base::ThreadTaskRunnerHandle::Get());
 
@@ -53,7 +53,7 @@
   DVLOG(1) << __FUNCTION__;
 
   if (!decoder_) {
-    callback.Run(false);
+    callback.Run(false, false, 1);
     return;
   }
 
@@ -66,7 +66,7 @@
 
 void MojoVideoDecoderService::Decode(mojom::DecoderBufferPtr buffer,
                                      const DecodeCallback& callback) {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(2) << __FUNCTION__;
 
   if (!decoder_) {
     callback.Run(DecodeStatus::DECODE_ERROR);
@@ -103,12 +103,16 @@
     const InitializeCallback& callback,
     bool success) {
   DVLOG(1) << __FUNCTION__;
-  callback.Run(success);
+  DCHECK(decoder_);
+  callback.Run(success, decoder_->NeedsBitstreamConversion(),
+               decoder_->GetMaxDecodeRequests());
 }
 
 void MojoVideoDecoderService::OnDecoderDecoded(const DecodeCallback& callback,
                                                DecodeStatus status) {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(2) << __FUNCTION__;
+  DCHECK(decoder_);
+  DCHECK(decoder_->CanReadWithoutStalling());
   callback.Run(status);
 }
 
@@ -119,7 +123,7 @@
 
 void MojoVideoDecoderService::OnDecoderOutput(
     const scoped_refptr<VideoFrame>& frame) {
-  DVLOG(1) << __FUNCTION__;
+  DVLOG(2) << __FUNCTION__;
   DCHECK(client_);
   client_->OnVideoFrameDecoded(mojom::VideoFrame::From(frame));
 }
diff --git a/net/DEPS b/net/DEPS
index 345a6ec..8b106fa 100644
--- a/net/DEPS
+++ b/net/DEPS
@@ -4,6 +4,7 @@
   "+jni",
   "+mojo/public",
   "+third_party/apple_apsl",
+  "+third_party/boringssl/src/include",
   "+third_party/nss",
   "+third_party/protobuf/src/google/protobuf",
   "+third_party/zlib",
diff --git a/net/base/keygen_handler_openssl.cc b/net/base/keygen_handler_openssl.cc
index 76f0e5bd6..161a5b74 100644
--- a/net/base/keygen_handler_openssl.cc
+++ b/net/base/keygen_handler_openssl.cc
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <openssl/bytestring.h>
-#include <openssl/digest.h>
-#include <openssl/evp.h>
-#include <openssl/mem.h>
 #include <stdint.h>
 
 #include <memory>
@@ -18,6 +14,10 @@
 #include "crypto/rsa_private_key.h"
 #include "net/base/keygen_handler.h"
 #include "net/base/openssl_private_key_store.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
 
 namespace net {
 
diff --git a/net/base/keygen_handler_unittest.cc b/net/base/keygen_handler_unittest.cc
index 8060fae..b0c90b23 100644
--- a/net/base/keygen_handler_unittest.cc
+++ b/net/base/keygen_handler_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "net/base/keygen_handler.h"
 
-#include <openssl/bytestring.h>
-#include <openssl/evp.h>
 #include <stdint.h>
 
 #include <string>
@@ -21,6 +19,8 @@
 #include "base/threading/worker_pool.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 #if defined(USE_NSS_CERTS)
 #include <private/pprthred.h>  // PR_DetachThread
diff --git a/net/base/openssl_private_key_store_android.cc b/net/base/openssl_private_key_store_android.cc
index 224a4f53..59cd8b0 100644
--- a/net/base/openssl_private_key_store_android.cc
+++ b/net/base/openssl_private_key_store_android.cc
@@ -4,14 +4,13 @@
 
 #include "net/base/openssl_private_key_store.h"
 
-#include <openssl/bytestring.h>
-#include <openssl/evp.h>
-#include <openssl/mem.h>
-
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "crypto/openssl_util.h"
 #include "net/android/network_library.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
 
 namespace net {
 
diff --git a/net/base/openssl_private_key_store_memory.cc b/net/base/openssl_private_key_store_memory.cc
index 49e6e1d..5b86b152 100644
--- a/net/base/openssl_private_key_store_memory.cc
+++ b/net/base/openssl_private_key_store_memory.cc
@@ -6,12 +6,11 @@
 
 #include "net/base/openssl_private_key_store.h"
 
-#include <openssl/evp.h>
-
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/synchronization/lock.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
diff --git a/net/cert/cert_verifier.cc b/net/cert/cert_verifier.cc
index 3aea1be..c471fa9 100644
--- a/net/cert/cert_verifier.cc
+++ b/net/cert/cert_verifier.cc
@@ -4,8 +4,6 @@
 
 #include "net/cert/cert_verifier.h"
 
-#include <openssl/sha.h>
-
 #include <algorithm>
 #include <memory>
 
@@ -13,6 +11,7 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "net/cert/cert_verify_proc.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
 
 #if defined(OS_NACL)
 #include "base/logging.h"
diff --git a/net/cert/cert_verify_proc_android.cc b/net/cert/cert_verify_proc_android.cc
index 3825b20..2cb12f7 100644
--- a/net/cert/cert_verify_proc_android.cc
+++ b/net/cert/cert_verify_proc_android.cc
@@ -4,8 +4,6 @@
 
 #include "net/cert/cert_verify_proc_android.h"
 
-#include <openssl/x509v3.h>
-
 #include <string>
 #include <vector>
 
@@ -20,6 +18,7 @@
 #include "net/cert/cert_status_flags.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
+#include "third_party/boringssl/src/include/openssl/x509v3.h"
 
 namespace net {
 
diff --git a/net/cert/cert_verify_proc_openssl.cc b/net/cert/cert_verify_proc_openssl.cc
index ab7daf04..988bdec1 100644
--- a/net/cert/cert_verify_proc_openssl.cc
+++ b/net/cert/cert_verify_proc_openssl.cc
@@ -4,8 +4,6 @@
 
 #include "net/cert/cert_verify_proc_openssl.h"
 
-#include <openssl/x509v3.h>
-
 #include <string>
 #include <vector>
 
@@ -20,6 +18,7 @@
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/test_root_certs.h"
 #include "net/cert/x509_certificate.h"
+#include "third_party/boringssl/src/include/openssl/x509v3.h"
 
 namespace net {
 
diff --git a/net/cert/ct_log_verifier.cc b/net/cert/ct_log_verifier.cc
index 2e95beb..d55fc97 100644
--- a/net/cert/ct_log_verifier.cc
+++ b/net/cert/ct_log_verifier.cc
@@ -5,8 +5,6 @@
 #include "net/cert/ct_log_verifier.h"
 
 #include <string.h>
-#include <openssl/bytestring.h>
-#include <openssl/evp.h>
 
 #include "base/logging.h"
 #include "crypto/openssl_util.h"
@@ -15,6 +13,8 @@
 #include "net/cert/ct_serialization.h"
 #include "net/cert/merkle_consistency_proof.h"
 #include "net/cert/signed_tree_head.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
diff --git a/net/cert/ct_objects_extractor.cc b/net/cert/ct_objects_extractor.cc
index 55b3fe23..4f451fd 100644
--- a/net/cert/ct_objects_extractor.cc
+++ b/net/cert/ct_objects_extractor.cc
@@ -6,16 +6,15 @@
 
 #include <string.h>
 
-#include <openssl/bytestring.h>
-#include <openssl/obj.h>
-#include <openssl/x509.h>
-
 #include "base/logging.h"
 #include "base/sha1.h"
 #include "base/strings/string_util.h"
 #include "crypto/sha2.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/signed_certificate_timestamp.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/obj.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 namespace net {
 
diff --git a/net/cert/internal/signature_policy.cc b/net/cert/internal/signature_policy.cc
index 20a4cd3..0785cbf6 100644
--- a/net/cert/internal/signature_policy.cc
+++ b/net/cert/internal/signature_policy.cc
@@ -7,8 +7,7 @@
 #include "base/logging.h"
 #include "net/cert/internal/cert_error_params.h"
 #include "net/cert/internal/cert_errors.h"
-
-#include <openssl/obj.h>
+#include "third_party/boringssl/src/include/openssl/obj.h"
 
 namespace net {
 
diff --git a/net/cert/internal/verify_name_match.cc b/net/cert/internal/verify_name_match.cc
index e1cc813..b999355b 100644
--- a/net/cert/internal/verify_name_match.cc
+++ b/net/cert/internal/verify_name_match.cc
@@ -4,9 +4,6 @@
 
 #include "net/cert/internal/verify_name_match.h"
 
-#include <openssl/bytestring.h>
-#include <openssl/mem.h>
-
 #include <algorithm>
 #include <vector>
 
@@ -16,6 +13,8 @@
 #include "net/der/input.h"
 #include "net/der/parser.h"
 #include "net/der/tag.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
 
 namespace net {
 
diff --git a/net/cert/internal/verify_signed_data.cc b/net/cert/internal/verify_signed_data.cc
index a8727dc..37fc0eb 100644
--- a/net/cert/internal/verify_signed_data.cc
+++ b/net/cert/internal/verify_signed_data.cc
@@ -4,14 +4,6 @@
 
 #include "net/cert/internal/verify_signed_data.h"
 
-#include <openssl/bn.h>
-#include <openssl/bytestring.h>
-#include <openssl/digest.h>
-#include <openssl/ec.h>
-#include <openssl/ec_key.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "crypto/openssl_util.h"
@@ -21,6 +13,13 @@
 #include "net/der/input.h"
 #include "net/der/parse_values.h"
 #include "net/der/parser.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 namespace net {
 
diff --git a/net/cert/internal/verify_signed_data_unittest.cc b/net/cert/internal/verify_signed_data_unittest.cc
index 7710abc..1f72903 100644
--- a/net/cert/internal/verify_signed_data_unittest.cc
+++ b/net/cert/internal/verify_signed_data_unittest.cc
@@ -15,8 +15,7 @@
 #include "net/der/parse_values.h"
 #include "net/der/parser.h"
 #include "testing/gtest/include/gtest/gtest.h"
-
-#include <openssl/obj.h>
+#include "third_party/boringssl/src/include/openssl/obj.h"
 
 namespace net {
 
diff --git a/net/cert/jwk_serializer.cc b/net/cert/jwk_serializer.cc
index bcd9545d..0faab404 100644
--- a/net/cert/jwk_serializer.cc
+++ b/net/cert/jwk_serializer.cc
@@ -4,17 +4,16 @@
 
 #include "net/cert/jwk_serializer.h"
 
-#include <openssl/bn.h>
-#include <openssl/bytestring.h>
-#include <openssl/ec.h>
-#include <openssl/ec_key.h>
-#include <openssl/evp.h>
-
 #include "base/base64url.h"
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "crypto/openssl_util.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
diff --git a/net/cert/test_root_certs_openssl.cc b/net/cert/test_root_certs_openssl.cc
index 76906d8..0cac6ab 100644
--- a/net/cert/test_root_certs_openssl.cc
+++ b/net/cert/test_root_certs_openssl.cc
@@ -4,13 +4,12 @@
 
 #include "net/cert/test_root_certs.h"
 
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
-
 #include "base/location.h"
 #include "base/logging.h"
 #include "crypto/openssl_util.h"
 #include "net/cert/x509_certificate.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/x509v3.h"
 
 namespace net {
 
diff --git a/net/cert/x509_certificate_ios.cc b/net/cert/x509_certificate_ios.cc
index fccc23bab..7379707 100644
--- a/net/cert/x509_certificate_ios.cc
+++ b/net/cert/x509_certificate_ios.cc
@@ -7,9 +7,6 @@
 #include <CommonCrypto/CommonDigest.h>
 #include <Security/Security.h>
 
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
 #include "base/mac/scoped_cftyperef.h"
 #include "base/pickle.h"
 #include "base/strings/string_piece.h"
@@ -18,6 +15,8 @@
 #include "net/base/ip_address.h"
 #include "net/cert/x509_util_openssl.h"
 #include "net/ssl/openssl_ssl_util.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
+#include "third_party/boringssl/src/include/openssl/x509v3.h"
 
 using base::ScopedCFTypeRef;
 
diff --git a/net/cert/x509_certificate_openssl.cc b/net/cert/x509_certificate_openssl.cc
index e7d62ff..30d9598 100644
--- a/net/cert/x509_certificate_openssl.cc
+++ b/net/cert/x509_certificate_openssl.cc
@@ -4,15 +4,6 @@
 
 #include "net/cert/x509_certificate.h"
 
-#include <openssl/asn1.h>
-#include <openssl/bytestring.h>
-#include <openssl/crypto.h>
-#include <openssl/obj_mac.h>
-#include <openssl/pem.h>
-#include <openssl/sha.h>
-#include <openssl/ssl.h>
-#include <openssl/x509v3.h>
-
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/numerics/safe_conversions.h"
@@ -25,6 +16,14 @@
 #include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
 #include "net/cert/x509_util_openssl.h"
+#include "third_party/boringssl/src/include/openssl/asn1.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/crypto.h"
+#include "third_party/boringssl/src/include/openssl/obj_mac.h"
+#include "third_party/boringssl/src/include/openssl/pem.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "third_party/boringssl/src/include/openssl/x509v3.h"
 
 #if defined(OS_ANDROID)
 #include "base/logging.h"
diff --git a/net/cert/x509_certificate_win.cc b/net/cert/x509_certificate_win.cc
index 4c6e389..c67011e 100644
--- a/net/cert/x509_certificate_win.cc
+++ b/net/cert/x509_certificate_win.cc
@@ -6,8 +6,6 @@
 
 #include <memory>
 
-#include <openssl/sha.h>
-
 #include "base/logging.h"
 #include "base/memory/free_deleter.h"
 #include "base/numerics/safe_conversions.h"
@@ -19,6 +17,7 @@
 #include "crypto/scoped_capi_types.h"
 #include "crypto/sha2.h"
 #include "net/base/net_errors.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
 
 using base::Time;
 
diff --git a/net/cert/x509_util_openssl.cc b/net/cert/x509_util_openssl.cc
index 98c5575..4a2aba0 100644
--- a/net/cert/x509_util_openssl.cc
+++ b/net/cert/x509_util_openssl.cc
@@ -5,9 +5,6 @@
 #include "net/cert/x509_util_openssl.h"
 
 #include <limits.h>
-#include <openssl/asn1.h>
-#include <openssl/digest.h>
-#include <openssl/mem.h>
 
 #include <algorithm>
 #include <memory>
@@ -25,6 +22,9 @@
 #include "net/cert/x509_cert_types.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util.h"
+#include "third_party/boringssl/src/include/openssl/asn1.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
 
 namespace net {
 
diff --git a/net/cert/x509_util_openssl.h b/net/cert/x509_util_openssl.h
index c77aed07..b735c1a 100644
--- a/net/cert/x509_util_openssl.h
+++ b/net/cert/x509_util_openssl.h
@@ -5,14 +5,13 @@
 #ifndef NET_CERT_X509_UTIL_OPENSSL_H_
 #define NET_CERT_X509_UTIL_OPENSSL_H_
 
-#include <openssl/asn1.h>
-#include <openssl/x509v3.h>
-
 #include <string>
 #include <vector>
 
 #include "base/strings/string_piece.h"
 #include "net/base/net_export.h"
+#include "third_party/boringssl/src/include/openssl/asn1.h"
+#include "third_party/boringssl/src/include/openssl/x509v3.h"
 
 namespace base {
 class Time;
diff --git a/net/der/parser.h b/net/der/parser.h
index bb5e3f5..d83a375 100644
--- a/net/der/parser.h
+++ b/net/der/parser.h
@@ -5,7 +5,6 @@
 #ifndef NET_DER_PARSER_H_
 #define NET_DER_PARSER_H_
 
-#include <openssl/bytestring.h>
 #include <stdint.h>
 
 #include "base/compiler_specific.h"
@@ -14,6 +13,7 @@
 #include "net/base/net_export.h"
 #include "net/der/input.h"
 #include "net/der/tag.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
 
 namespace net {
 
diff --git a/net/http/des.cc b/net/http/des.cc
index 4f05022..57f67d7c 100644
--- a/net/http/des.cc
+++ b/net/http/des.cc
@@ -4,10 +4,9 @@
 
 #include "net/http/des.h"
 
-#include <openssl/des.h>
-
 #include "base/logging.h"
 #include "crypto/openssl_util.h"
+#include "third_party/boringssl/src/include/openssl/des.h"
 
 // The iOS version of DESEncrypt is our own code.
 // DESSetKeyParity and DESMakeKey are based on
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 2adfe69..b0cd3d6 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -4,8 +4,6 @@
 
 #include "net/http/http_response_info.h"
 
-#include <openssl/ssl.h>
-
 #include "base/logging.h"
 #include "base/pickle.h"
 #include "base/time/time.h"
@@ -18,6 +16,7 @@
 #include "net/http/http_response_headers.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 using base::Time;
 
diff --git a/net/quic/chromium/crypto/proof_source_chromium.cc b/net/quic/chromium/crypto/proof_source_chromium.cc
index 0b76f73..77ea530 100644
--- a/net/quic/chromium/crypto/proof_source_chromium.cc
+++ b/net/quic/chromium/crypto/proof_source_chromium.cc
@@ -4,13 +4,12 @@
 
 #include "net/quic/chromium/crypto/proof_source_chromium.h"
 
-#include <openssl/digest.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-
 #include "base/strings/string_number_conversions.h"
 #include "crypto/openssl_util.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 using std::string;
 using std::vector;
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index 9dbc66f..081aff1e 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -4,8 +4,6 @@
 
 #include "net/quic/chromium/quic_chromium_client_session.h"
 
-#include <openssl/ssl.h>
-
 #include <utility>
 
 #include "base/callback_helpers.h"
@@ -39,6 +37,7 @@
 #include "net/ssl/ssl_info.h"
 #include "net/ssl/token_binding.h"
 #include "net/udp/datagram_client_socket.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 namespace net {
 
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index 86c5657..9214253 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -4,8 +4,6 @@
 
 #include "net/quic/chromium/quic_stream_factory.h"
 
-#include <openssl/aead.h>
-
 #include <algorithm>
 #include <tuple>
 #include <utility>
@@ -56,6 +54,7 @@
 #include "net/socket/socket_performance_watcher_factory.h"
 #include "net/ssl/token_binding.h"
 #include "net/udp/udp_client_socket.h"
+#include "third_party/boringssl/src/include/openssl/aead.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
diff --git a/net/quic/core/crypto/aead_base_decrypter.cc b/net/quic/core/crypto/aead_base_decrypter.cc
index 721fe5b..1da2261 100644
--- a/net/quic/core/crypto/aead_base_decrypter.cc
+++ b/net/quic/core/crypto/aead_base_decrypter.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <openssl/err.h>
-#include <openssl/evp.h>
+#include "net/quic/core/crypto/aead_base_decrypter.h"
 
 #include <memory>
 
-#include "net/quic/core/crypto/aead_base_decrypter.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_utils.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 using base::StringPiece;
 using std::string;
diff --git a/net/quic/core/crypto/aead_base_encrypter.cc b/net/quic/core/crypto/aead_base_encrypter.cc
index 195aba79..477810fc 100644
--- a/net/quic/core/crypto/aead_base_encrypter.cc
+++ b/net/quic/core/crypto/aead_base_encrypter.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <openssl/err.h>
-#include <openssl/evp.h>
 #include <string.h>
 
 #include <memory>
@@ -11,6 +9,8 @@
 #include "net/quic/core/crypto/aead_base_encrypter.h"
 #include "net/quic/core/quic_flags.h"
 #include "net/quic/core/quic_utils.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 using base::StringPiece;
 
diff --git a/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc b/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc
index a9eb9cb..8926fad 100644
--- a/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc
+++ b/net/quic/core/crypto/aes_128_gcm_12_decrypter.cc
@@ -4,8 +4,8 @@
 
 #include "net/quic/core/crypto/aes_128_gcm_12_decrypter.h"
 
-#include <openssl/evp.h>
-#include <openssl/tls1.h>
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/tls1.h"
 
 namespace net {
 
diff --git a/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc b/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc
index 50c24cbb..dde7e3e3 100644
--- a/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc
+++ b/net/quic/core/crypto/aes_128_gcm_12_encrypter.cc
@@ -4,7 +4,7 @@
 
 #include "net/quic/core/crypto/aes_128_gcm_12_encrypter.h"
 
-#include <openssl/evp.h>
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
diff --git a/net/quic/core/crypto/chacha20_poly1305_decrypter.cc b/net/quic/core/crypto/chacha20_poly1305_decrypter.cc
index 302d105..0c652296 100644
--- a/net/quic/core/crypto/chacha20_poly1305_decrypter.cc
+++ b/net/quic/core/crypto/chacha20_poly1305_decrypter.cc
@@ -4,8 +4,8 @@
 
 #include "net/quic/core/crypto/chacha20_poly1305_decrypter.h"
 
-#include <openssl/evp.h>
-#include <openssl/tls1.h>
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/tls1.h"
 
 namespace net {
 
diff --git a/net/quic/core/crypto/chacha20_poly1305_encrypter.cc b/net/quic/core/crypto/chacha20_poly1305_encrypter.cc
index 3a796226..520ed17 100644
--- a/net/quic/core/crypto/chacha20_poly1305_encrypter.cc
+++ b/net/quic/core/crypto/chacha20_poly1305_encrypter.cc
@@ -4,7 +4,7 @@
 
 #include "net/quic/core/crypto/chacha20_poly1305_encrypter.h"
 
-#include <openssl/evp.h>
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
diff --git a/net/quic/core/crypto/channel_id.cc b/net/quic/core/crypto/channel_id.cc
index 65a5e2ee..6588c4ed 100644
--- a/net/quic/core/crypto/channel_id.cc
+++ b/net/quic/core/crypto/channel_id.cc
@@ -4,14 +4,13 @@
 
 #include "net/quic/core/crypto/channel_id.h"
 
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/ec_key.h>
-#include <openssl/ecdsa.h>
-#include <openssl/nid.h>
-#include <openssl/sha.h>
-
 #include "crypto/openssl_util.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
 
 using base::StringPiece;
 
diff --git a/net/quic/core/crypto/p256_key_exchange.cc b/net/quic/core/crypto/p256_key_exchange.cc
index 3a92118..bfef9247 100644
--- a/net/quic/core/crypto/p256_key_exchange.cc
+++ b/net/quic/core/crypto/p256_key_exchange.cc
@@ -4,13 +4,12 @@
 
 #include "net/quic/core/crypto/p256_key_exchange.h"
 
-#include <openssl/ec.h>
-#include <openssl/ecdh.h>
-#include <openssl/evp.h>
-
 #include <utility>
 
 #include "base/logging.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ecdh.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 using base::StringPiece;
 using std::string;
diff --git a/net/quic/core/crypto/p256_key_exchange.h b/net/quic/core/crypto/p256_key_exchange.h
index 64fa8b9..059cd208 100644
--- a/net/quic/core/crypto/p256_key_exchange.h
+++ b/net/quic/core/crypto/p256_key_exchange.h
@@ -5,7 +5,6 @@
 #ifndef NET_QUIC_CRYPTO_P256_KEY_EXCHANGE_H_
 #define NET_QUIC_CRYPTO_P256_KEY_EXCHANGE_H_
 
-#include <openssl/base.h>
 #include <stdint.h>
 
 #include <memory>
@@ -16,7 +15,7 @@
 #include "crypto/openssl_util.h"
 #include "net/base/net_export.h"
 #include "net/quic/core/crypto/key_exchange.h"
-
+#include "third_party/boringssl/src/include/openssl/base.h"
 
 namespace net {
 
diff --git a/net/quic/core/crypto/scoped_evp_aead_ctx.h b/net/quic/core/crypto/scoped_evp_aead_ctx.h
index d8067fc..afb58614 100644
--- a/net/quic/core/crypto/scoped_evp_aead_ctx.h
+++ b/net/quic/core/crypto/scoped_evp_aead_ctx.h
@@ -5,9 +5,8 @@
 #ifndef NET_QUIC_CRYPTO_SCOPED_EVP_AEAD_CTX_H_
 #define NET_QUIC_CRYPTO_SCOPED_EVP_AEAD_CTX_H_
 
-#include <openssl/evp.h>
-
 #include "base/macros.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 namespace net {
 
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 05a3c69..dd664c8 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -4,13 +4,6 @@
 
 #include "net/quic/test_tools/crypto_test_utils.h"
 
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/ecdsa.h>
-#include <openssl/evp.h>
-#include <openssl/obj_mac.h>
-#include <openssl/sha.h>
-
 #include <memory>
 
 #include "base/strings/string_util.h"
@@ -34,6 +27,12 @@
 #include "net/quic/test_tools/quic_framer_peer.h"
 #include "net/quic/test_tools/quic_test_utils.h"
 #include "net/quic/test_tools/simple_quic_framer.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/obj_mac.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
 
 using base::StringPiece;
 using std::make_pair;
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index bb3df44..532969a21 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -5,12 +5,6 @@
 #include "net/socket/ssl_client_socket_impl.h"
 
 #include <errno.h>
-#include <openssl/bio.h>
-#include <openssl/bytestring.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/mem.h>
-#include <openssl/ssl.h>
 #include <string.h>
 
 #include <utility>
@@ -52,6 +46,12 @@
 #include "net/ssl/ssl_info.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/token_binding.h"
+#include "third_party/boringssl/src/include/openssl/bio.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 #if !defined(OS_NACL)
 #include "net/ssl/ssl_key_logger.h"
diff --git a/net/socket/ssl_client_socket_impl.h b/net/socket/ssl_client_socket_impl.h
index 010a6f00..e63a1b6f 100644
--- a/net/socket/ssl_client_socket_impl.h
+++ b/net/socket/ssl_client_socket_impl.h
@@ -5,8 +5,6 @@
 #ifndef NET_SOCKET_SSL_CLIENT_SOCKET_IMPL_H_
 #define NET_SOCKET_SSL_CLIENT_SOCKET_IMPL_H_
 
-#include <openssl/base.h>
-#include <openssl/ssl.h>
 #include <stddef.h>
 #include <stdint.h>
 
@@ -32,6 +30,8 @@
 #include "net/ssl/openssl_ssl_util.h"
 #include "net/ssl/ssl_client_cert_type.h"
 #include "net/ssl/ssl_config_service.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 namespace base {
 class FilePath;
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index 2efa404..b6cb5cd 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -4,8 +4,6 @@
 
 #include "net/socket/ssl_client_socket_pool.h"
 
-#include <openssl/ssl.h>
-
 #include <utility>
 
 #include "base/bind.h"
@@ -30,6 +28,7 @@
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 #include "net/ssl/ssl_info.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 namespace net {
 
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index a613dd9..d451d31 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -9,10 +9,6 @@
 
 #include <utility>
 
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-
 #include "base/callback_helpers.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
@@ -61,6 +57,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
+#include "third_party/boringssl/src/include/openssl/bio.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/pem.h"
 
 using net::test::IsError;
 using net::test::IsOk;
diff --git a/net/socket/ssl_server_socket_impl.cc b/net/socket/ssl_server_socket_impl.cc
index c7d1e667..3e3f79b2 100644
--- a/net/socket/ssl_server_socket_impl.cc
+++ b/net/socket/ssl_server_socket_impl.cc
@@ -4,9 +4,6 @@
 
 #include "net/socket/ssl_server_socket_impl.h"
 
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
 #include <utility>
 
 #include "base/callback_helpers.h"
@@ -24,6 +21,9 @@
 #include "net/ssl/openssl_ssl_util.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 #include "net/ssl/ssl_info.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 #define GotoState(s) next_handshake_state_ = s
 
diff --git a/net/socket/ssl_server_socket_impl.h b/net/socket/ssl_server_socket_impl.h
index 5437e4e..d206198 100644
--- a/net/socket/ssl_server_socket_impl.h
+++ b/net/socket/ssl_server_socket_impl.h
@@ -5,7 +5,6 @@
 #ifndef NET_SOCKET_SSL_SERVER_SOCKET_IMPL_H_
 #define NET_SOCKET_SSL_SERVER_SOCKET_IMPL_H_
 
-#include <openssl/base.h>
 #include <stdint.h>
 
 #include <memory>
@@ -15,6 +14,7 @@
 #include "net/base/io_buffer.h"
 #include "net/socket/ssl_server_socket.h"
 #include "net/ssl/ssl_server_config.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
 
 namespace net {
 
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index e6a71a1..fe9953d 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -20,10 +20,6 @@
 #include <queue>
 #include <utility>
 
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-
 #include "base/callback_helpers.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
@@ -73,6 +69,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 using net::test::IsError;
 using net::test::IsOk;
diff --git a/net/ssl/openssl_client_key_store.cc b/net/ssl/openssl_client_key_store.cc
index e205d4f..295810f 100644
--- a/net/ssl/openssl_client_key_store.cc
+++ b/net/ssl/openssl_client_key_store.cc
@@ -4,15 +4,14 @@
 
 #include "net/ssl/openssl_client_key_store.h"
 
-#include <openssl/evp.h>
-#include <openssl/mem.h>
-#include <openssl/x509.h>
-
 #include <utility>
 
 #include "base/memory/singleton.h"
 #include "net/cert/x509_certificate.h"
 #include "net/ssl/ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 namespace net {
 
diff --git a/net/ssl/openssl_client_key_store.h b/net/ssl/openssl_client_key_store.h
index 9e1e1f4..1ae5582 100644
--- a/net/ssl/openssl_client_key_store.h
+++ b/net/ssl/openssl_client_key_store.h
@@ -5,8 +5,6 @@
 #ifndef NET_SSL_OPENSSL_CLIENT_KEY_STORE_H_
 #define NET_SSL_OPENSSL_CLIENT_KEY_STORE_H_
 
-#include <openssl/base.h>
-
 #include <map>
 #include <string>
 
@@ -14,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "net/base/net_export.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
 
 namespace net {
 
diff --git a/net/ssl/openssl_ssl_util.cc b/net/ssl/openssl_ssl_util.cc
index 52316bc8..cf3d53f 100644
--- a/net/ssl/openssl_ssl_util.cc
+++ b/net/ssl/openssl_ssl_util.cc
@@ -5,9 +5,6 @@
 #include "net/ssl/openssl_ssl_util.h"
 
 #include <errno.h>
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
 #include <utility>
 
 #include "base/bind.h"
@@ -18,6 +15,9 @@
 #include "crypto/openssl_util.h"
 #include "net/base/net_errors.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 namespace net {
 
diff --git a/net/ssl/openssl_ssl_util.h b/net/ssl/openssl_ssl_util.h
index 04bcf30..5e533d94 100644
--- a/net/ssl/openssl_ssl_util.h
+++ b/net/ssl/openssl_ssl_util.h
@@ -7,11 +7,10 @@
 
 #include <stdint.h>
 
-#include <openssl/x509.h>
-
 #include "net/base/net_export.h"
 #include "net/cert/x509_certificate.h"
 #include "net/log/net_log_parameters_callback.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 namespace crypto {
 class OpenSSLErrStackTracer;
diff --git a/net/ssl/ssl_cipher_suite_names.cc b/net/ssl/ssl_cipher_suite_names.cc
index 24f54fc0d..320c22e 100644
--- a/net/ssl/ssl_cipher_suite_names.cc
+++ b/net/ssl/ssl_cipher_suite_names.cc
@@ -6,12 +6,11 @@
 
 #include <stdlib.h>
 
-#include <openssl/ssl.h>
-
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 // Rather than storing the names of all the ciphersuites we eliminate the
 // redundancy and break each cipher suite into a key exchange method, cipher
diff --git a/net/ssl/ssl_client_session_cache.cc b/net/ssl/ssl_client_session_cache.cc
index ccc13ff..8b0fa1e5 100644
--- a/net/ssl/ssl_client_session_cache.cc
+++ b/net/ssl/ssl_client_session_cache.cc
@@ -4,13 +4,12 @@
 
 #include "net/ssl/ssl_client_session_cache.h"
 
-#include <openssl/ssl.h>
-
 #include <utility>
 
 #include "base/memory/memory_coordinator_client_registry.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_client_session_cache.h b/net/ssl/ssl_client_session_cache.h
index 2f93aa3..b02e2ede 100644
--- a/net/ssl/ssl_client_session_cache.h
+++ b/net/ssl/ssl_client_session_cache.h
@@ -5,7 +5,6 @@
 #ifndef NET_SSL_SSL_CLIENT_SESSION_CACHE_H
 #define NET_SSL_SSL_CLIENT_SESSION_CACHE_H
 
-#include <openssl/base.h>
 #include <stddef.h>
 
 #include <memory>
@@ -20,6 +19,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
 
 namespace base {
 class Clock;
diff --git a/net/ssl/ssl_client_session_cache_unittest.cc b/net/ssl/ssl_client_session_cache_unittest.cc
index b019034..9a1e27a 100644
--- a/net/ssl/ssl_client_session_cache_unittest.cc
+++ b/net/ssl/ssl_client_session_cache_unittest.cc
@@ -4,13 +4,12 @@
 
 #include "net/ssl/ssl_client_session_cache.h"
 
-#include <openssl/ssl.h>
-
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/simple_test_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_info.cc b/net/ssl/ssl_info.cc
index a6232d0..977aac84 100644
--- a/net/ssl/ssl_info.cc
+++ b/net/ssl/ssl_info.cc
@@ -4,14 +4,13 @@
 
 #include "net/ssl/ssl_info.h"
 
-#include <openssl/ssl.h>
-
 #include "base/pickle.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/cert/ct_policy_status.h"
 #include "net/cert/signed_certificate_timestamp.h"
 #include "net/cert/x509_certificate.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_platform_key_android.cc b/net/ssl/ssl_platform_key_android.cc
index e6bc349..492c094b3 100644
--- a/net/ssl/ssl_platform_key_android.cc
+++ b/net/ssl/ssl_platform_key_android.cc
@@ -4,10 +4,6 @@
 
 #include "net/ssl/ssl_platform_key_android.h"
 
-#include <openssl/ecdsa.h>
-#include <openssl/mem.h>
-#include <openssl/nid.h>
-#include <openssl/rsa.h>
 #include <strings.h>
 
 #include <memory>
@@ -27,6 +23,10 @@
 #include "net/ssl/ssl_platform_key.h"
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/threaded_ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 using base::android::JavaRef;
 using base::android::ScopedJavaGlobalRef;
diff --git a/net/ssl/ssl_platform_key_android_unittest.cc b/net/ssl/ssl_platform_key_android_unittest.cc
index 2adaaa4..118de12 100644
--- a/net/ssl/ssl_platform_key_android_unittest.cc
+++ b/net/ssl/ssl_platform_key_android_unittest.cc
@@ -2,15 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <openssl/bytestring.h>
-#include <openssl/digest.h>
-#include <openssl/ecdsa.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/pem.h>
-#include <openssl/rsa.h>
-#include <openssl/x509.h>
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/scoped_java_ref.h"
@@ -29,6 +20,14 @@
 #include "net/test/jni/AndroidKeyStoreTestUtil_jni.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/err.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/pem.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_platform_key_chromecast.cc b/net/ssl/ssl_platform_key_chromecast.cc
index 429703d..4aa0a14 100644
--- a/net/ssl/ssl_platform_key_chromecast.cc
+++ b/net/ssl/ssl_platform_key_chromecast.cc
@@ -3,9 +3,6 @@
 // found in the LICENSE file.
 
 #include <keyhi.h>
-#include <openssl/mem.h>
-#include <openssl/nid.h>
-#include <openssl/rsa.h>
 #include <pk11pub.h>
 #include <prerror.h>
 
@@ -20,6 +17,9 @@
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/threaded_ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_platform_key_mac.cc b/net/ssl/ssl_platform_key_mac.cc
index 029c0f3..e305ce6 100644
--- a/net/ssl/ssl_platform_key_mac.cc
+++ b/net/ssl/ssl_platform_key_mac.cc
@@ -4,15 +4,11 @@
 
 #include "net/ssl/ssl_platform_key.h"
 
+#include <Security/cssm.h>
 #include <Security/SecBase.h>
 #include <Security/SecCertificate.h>
 #include <Security/SecIdentity.h>
 #include <Security/SecKey.h>
-#include <Security/cssm.h>
-#include <openssl/ecdsa.h>
-#include <openssl/mem.h>
-#include <openssl/nid.h>
-#include <openssl/rsa.h>
 
 #include <memory>
 
@@ -32,6 +28,10 @@
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/threaded_ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_platform_key_nss.cc b/net/ssl/ssl_platform_key_nss.cc
index 687f7962..cbbc8ec 100644
--- a/net/ssl/ssl_platform_key_nss.cc
+++ b/net/ssl/ssl_platform_key_nss.cc
@@ -4,14 +4,6 @@
 
 #include <cert.h>
 #include <keyhi.h>
-#include <openssl/bn.h>
-#include <openssl/bytestring.h>
-#include <openssl/ec.h>
-#include <openssl/ec_key.h>
-#include <openssl/ecdsa.h>
-#include <openssl/mem.h>
-#include <openssl/nid.h>
-#include <openssl/rsa.h>
 #include <pk11pub.h>
 #include <prerror.h>
 
@@ -28,6 +20,14 @@
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/threaded_ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 namespace net {
 
diff --git a/net/ssl/ssl_platform_key_win.cc b/net/ssl/ssl_platform_key_win.cc
index 40913aa..a1b294ae 100644
--- a/net/ssl/ssl_platform_key_win.cc
+++ b/net/ssl/ssl_platform_key_win.cc
@@ -12,11 +12,6 @@
 #include <utility>
 #include <vector>
 
-#include <openssl/bn.h>
-#include <openssl/ecdsa.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/sequenced_task_runner.h"
@@ -28,6 +23,10 @@
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/threaded_ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/x509.h"
 
 namespace net {
 
diff --git a/net/ssl/test_ssl_private_key.cc b/net/ssl/test_ssl_private_key.cc
index 59dea2f..fd1f26f 100644
--- a/net/ssl/test_ssl_private_key.cc
+++ b/net/ssl/test_ssl_private_key.cc
@@ -4,11 +4,6 @@
 
 #include "net/ssl/test_ssl_private_key.h"
 
-#include <openssl/digest.h>
-#include <openssl/ec.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-
 #include <utility>
 
 #include "base/logging.h"
@@ -18,6 +13,10 @@
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/ssl/threaded_ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/digest.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/rsa.h"
 
 namespace net {
 
diff --git a/net/ssl/test_ssl_private_key.h b/net/ssl/test_ssl_private_key.h
index 0fa4a9f9..15e4f91 100644
--- a/net/ssl/test_ssl_private_key.h
+++ b/net/ssl/test_ssl_private_key.h
@@ -5,10 +5,9 @@
 #ifndef NET_SSL_TEST_SSL_PLATFORM_KEY_H_
 #define NET_SSL_TEST_SSL_PLATFORM_KEY_H_
 
-#include <openssl/base.h>
-
 #include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
 
 namespace net {
 
diff --git a/net/ssl/token_binding.cc b/net/ssl/token_binding.cc
index 06bca3d9..fc4ef6ca 100644
--- a/net/ssl/token_binding.cc
+++ b/net/ssl/token_binding.cc
@@ -4,18 +4,17 @@
 
 #include "net/ssl/token_binding.h"
 
-#include <openssl/bn.h>
-#include <openssl/bytestring.h>
-#include <openssl/ec.h>
-#include <openssl/ec_key.h>
-#include <openssl/ecdsa.h>
-#include <openssl/evp.h>
-#include <openssl/mem.h>
-
 #include "base/stl_util.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/net_errors.h"
 #include "net/ssl/ssl_config.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/bytestring.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
 
 namespace net {
 
diff --git a/remoting/protocol/channel_socket_adapter.cc b/remoting/protocol/channel_socket_adapter.cc
index 42be20b..4a5946da 100644
--- a/remoting/protocol/channel_socket_adapter.cc
+++ b/remoting/protocol/channel_socket_adapter.cc
@@ -124,13 +124,13 @@
 }
 
 void TransportChannelSocketAdapter::OnNewPacket(
-    cricket::TransportChannel* channel,
+    rtc::PacketTransportInterface* transport,
     const char* data,
     size_t data_size,
     const rtc::PacketTime& packet_time,
     int flags) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(channel, channel_);
+  DCHECK_EQ(transport, channel_);
   if (!read_callback_.is_null()) {
     DCHECK(read_buffer_.get());
     CHECK_LT(data_size, static_cast<size_t>(std::numeric_limits<int>::max()));
@@ -155,7 +155,7 @@
 }
 
 void TransportChannelSocketAdapter::OnWritableState(
-    cricket::TransportChannel* channel) {
+    rtc::PacketTransportInterface* transport) {
   DCHECK(thread_checker_.CalledOnValidThread());
   // Try to send the packet if there is a pending write.
   if (!write_callback_.is_null()) {
diff --git a/remoting/protocol/channel_socket_adapter.h b/remoting/protocol/channel_socket_adapter.h
index 9da2a90..0d2bdf59 100644
--- a/remoting/protocol/channel_socket_adapter.h
+++ b/remoting/protocol/channel_socket_adapter.h
@@ -15,6 +15,10 @@
 #include "third_party/webrtc/base/asyncpacketsocket.h"
 #include "third_party/webrtc/base/sigslot.h"
 #include "third_party/webrtc/base/socketaddress.h"
+// TODO(johan): Replace #include by forward declaration once proper
+// inheritance is defined for rtc::PacketTransportInterface and
+// cricket::TransportChannel.
+#include "third_party/webrtc/p2p/base/packettransportinterface.h"
 
 namespace cricket {
 class TransportChannel;
@@ -51,12 +55,12 @@
            const net::CompletionCallback& callback) override;
 
  private:
-  void OnNewPacket(cricket::TransportChannel* channel,
+  void OnNewPacket(rtc::PacketTransportInterface* transport,
                    const char* data,
                    size_t data_size,
                    const rtc::PacketTime& packet_time,
                    int flags);
-  void OnWritableState(cricket::TransportChannel* channel);
+  void OnWritableState(rtc::PacketTransportInterface* transport);
   void OnChannelDestroyed(cricket::TransportChannel* channel);
 
   base::ThreadChecker thread_checker_;
diff --git a/remoting/protocol/ice_transport_channel.cc b/remoting/protocol/ice_transport_channel.cc
index 18bb6128..9c3658ae 100644
--- a/remoting/protocol/ice_transport_channel.cc
+++ b/remoting/protocol/ice_transport_channel.cc
@@ -19,6 +19,7 @@
 #include "third_party/webrtc/base/network.h"
 #include "third_party/webrtc/p2p/base/p2pconstants.h"
 #include "third_party/webrtc/p2p/base/p2ptransportchannel.h"
+#include "third_party/webrtc/p2p/base/packettransportinterface.h"
 #include "third_party/webrtc/p2p/base/port.h"
 
 namespace remoting {
@@ -196,10 +197,12 @@
     NotifyRouteChanged();
 }
 
-void IceTransportChannel::OnWritableState(cricket::TransportChannel* channel) {
-  DCHECK_EQ(channel, static_cast<cricket::TransportChannel*>(channel_.get()));
+void IceTransportChannel::OnWritableState(
+    rtc::PacketTransportInterface* transport) {
+  DCHECK_EQ(transport,
+            static_cast<rtc::PacketTransportInterface*>(channel_.get()));
 
-  if (channel->writable()) {
+  if (transport->writable()) {
     connect_attempts_left_ =
         transport_context_->network_settings().ice_reconnect_attempts;
     reconnect_timer_.Stop();
diff --git a/remoting/protocol/ice_transport_channel.h b/remoting/protocol/ice_transport_channel.h
index f97f3ed..edd8539e 100644
--- a/remoting/protocol/ice_transport_channel.h
+++ b/remoting/protocol/ice_transport_channel.h
@@ -15,6 +15,10 @@
 #include "remoting/protocol/transport.h"
 #include "third_party/webrtc/base/sigslot.h"
 
+// TODO(johan): Replace #include by forward declaration once proper inheritance
+// is defined for rtc::PacketTransportInterface and cricket::TransportChannel.
+#include "third_party/webrtc/p2p/base/packettransportinterface.h"
+
 namespace cricket {
 class Candidate;
 class P2PTransportChannel;
@@ -96,7 +100,7 @@
                            const cricket::Candidate& candidate);
   void OnRouteChange(cricket::TransportChannel* channel,
                      const cricket::Candidate& candidate);
-  void OnWritableState(cricket::TransportChannel* channel);
+  void OnWritableState(rtc::PacketTransportInterface* transport);
 
   // Callback for TransportChannelSocketAdapter to notify when the socket is
   // destroyed.
diff --git a/services/ui/surfaces/compositor_frame_sink.cc b/services/ui/surfaces/compositor_frame_sink.cc
index c880bd1..fd9680a 100644
--- a/services/ui/surfaces/compositor_frame_sink.cc
+++ b/services/ui/surfaces/compositor_frame_sink.cc
@@ -105,11 +105,6 @@
   factory_.SubmitCompositorFrame(local_frame_id_, std::move(frame), callback);
 }
 
-void CompositorFrameSink::RequestCopyOfOutput(
-    std::unique_ptr<cc::CopyOutputRequest> output_request) {
-  factory_.RequestCopyOfSurface(local_frame_id_, std::move(output_request));
-}
-
 void CompositorFrameSink::ReturnResources(
     const cc::ReturnedResourceArray& resources) {
   // TODO(fsamuel): Implement this.
diff --git a/services/ui/surfaces/compositor_frame_sink.h b/services/ui/surfaces/compositor_frame_sink.h
index a6601f8..ab5290d 100644
--- a/services/ui/surfaces/compositor_frame_sink.h
+++ b/services/ui/surfaces/compositor_frame_sink.h
@@ -51,15 +51,6 @@
   // exposed outside of CompositorFrameSink.
   const cc::LocalFrameId& local_frame_id() const { return local_frame_id_; }
 
-  // This requests the display CompositorFrame be rendered and given to the
-  // callback within CopyOutputRequest.
-  void RequestCopyOfOutput(
-      std::unique_ptr<cc::CopyOutputRequest> output_request);
-
-  // TODO(fsamuel): Invent an async way to create a SurfaceNamespace
-  // A SurfaceNamespace can create CompositorFrameSinks where the client can
-  // make up the ID.
-
  private:
   // SurfaceFactoryClient implementation.
   void ReturnResources(const cc::ReturnedResourceArray& resources) override;
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index cbed7bd..825a90a2 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -68,12 +68,6 @@
   }
 }
 
-void FrameGenerator::RequestCopyOfOutput(
-    std::unique_ptr<cc::CopyOutputRequest> output_request) {
-  if (compositor_frame_sink_)
-    compositor_frame_sink_->RequestCopyOfOutput(std::move(output_request));
-}
-
 void FrameGenerator::WantToDraw() {
   if (draw_timer_.IsRunning() || frame_pending_)
     return;
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h
index f608758e..35b40139 100644
--- a/services/ui/ws/frame_generator.h
+++ b/services/ui/ws/frame_generator.h
@@ -60,8 +60,6 @@
   // Schedules a redraw for the provided region.
   void RequestRedraw(const gfx::Rect& redraw_region);
   void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget);
-  void RequestCopyOfOutput(
-      std::unique_ptr<cc::CopyOutputRequest> output_request);
 
   bool is_frame_pending() { return frame_pending_; }
 
diff --git a/services/ui/ws/platform_display.cc b/services/ui/ws/platform_display.cc
index 35d7f9b7..685ee61 100644
--- a/services/ui/ws/platform_display.cc
+++ b/services/ui/ws/platform_display.cc
@@ -289,11 +289,6 @@
 
 void DefaultPlatformDisplay::OnActivationChanged(bool active) {}
 
-void DefaultPlatformDisplay::RequestCopyOfOutput(
-    std::unique_ptr<cc::CopyOutputRequest> output_request) {
-  frame_generator_->RequestCopyOfOutput(std::move(output_request));
-}
-
 ServerWindow* DefaultPlatformDisplay::GetRootWindow() {
   return delegate_->GetRootWindow();
 }
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h
index a4cd5c8..db6a43d 100644
--- a/services/ui/ws/platform_display.h
+++ b/services/ui/ws/platform_display.h
@@ -89,9 +89,6 @@
   // Returns true if a compositor frame has been submitted but not drawn yet.
   virtual bool IsFramePending() const = 0;
 
-  virtual void RequestCopyOfOutput(
-      std::unique_ptr<cc::CopyOutputRequest> output_request) = 0;
-
   virtual gfx::Rect GetBounds() const = 0;
 
   virtual bool IsPrimaryDisplay() const = 0;
@@ -136,8 +133,6 @@
   void UpdateTextInputState(const ui::TextInputState& state) override;
   void SetImeVisibility(bool visible) override;
   bool IsFramePending() const override;
-  void RequestCopyOfOutput(
-      std::unique_ptr<cc::CopyOutputRequest> output_request) override;
   gfx::Rect GetBounds() const override;
   bool IsPrimaryDisplay() const override;
   void OnGpuChannelEstablished(
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc
index f5b9ea86..9d67e94a 100644
--- a/services/ui/ws/test_utils.cc
+++ b/services/ui/ws/test_utils.cc
@@ -63,8 +63,6 @@
   void UpdateTextInputState(const ui::TextInputState& state) override {}
   void SetImeVisibility(bool visible) override {}
   bool IsFramePending() const override { return false; }
-  void RequestCopyOfOutput(
-      std::unique_ptr<cc::CopyOutputRequest> output_request) override {}
   gfx::Rect GetBounds() const override { return display_metrics_.bounds; }
   bool IsPrimaryDisplay() const override { return is_primary_; }
   void OnGpuChannelEstablished(
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c743885e..51c601a 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1267,7 +1267,5 @@
 crbug.com/655458 imported/wpt/workers/semantics/structured-clone/dedicated.html [ Crash Failure Timeout ]
 crbug.com/655458 imported/wpt/workers/semantics/structured-clone/shared.html [ Crash Failure Timeout ]
 
-crbug.com/656622 inspector/sources/debugger-pause/debugger-eval-while-paused-throws.html [ NeedsManualRebaseline ]
-
 # Web platform tests for the service workers cannot work without --enable-wptserve.
 crbug.com/602693 imported/wpt/service-workers [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt b/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
index 825374b..f614e7fc0 100644
--- a/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
@@ -60,12 +60,14 @@
     AXRole: AXParagraph
         AXRole: AXStaticText "Paragraph"
             AXRole: AXInlineTextBox "Paragraph"
-    AXRole: AXRuby
-        AXRole: AXAnnotation
-            AXRole: AXStaticText "한국"
-                AXRole: AXInlineTextBox "한국"
-        AXRole: AXStaticText "韓國"
-            AXRole: AXInlineTextBox "韓國"
+    AXRole: AXGroup
+        AXRole: AXRuby
+            AXRole: AXAnnotation
+                AXRole: AXStaticText "한국"
+                    AXRole: AXInlineTextBox "한국"
+            AXRole: AXGroup
+                AXRole: AXStaticText "韓國"
+                    AXRole: AXInlineTextBox "韓國"
     AXRole: AXDescriptionList
         AXRole: AXDescriptionListTerm
             AXRole: AXStaticText "Coffee"
@@ -79,17 +81,18 @@
         AXRole: AXDescriptionListDetail
             AXRole: AXStaticText "- white cold drink"
                 AXRole: AXInlineTextBox "- white cold drink"
-    AXRole: AXMath
-        AXRole: AXStaticText "x "
-            AXRole: AXInlineTextBox "x "
-        AXRole: AXStaticText "+ "
-            AXRole: AXInlineTextBox "+ "
-        AXRole: AXStaticText "a "
-            AXRole: AXInlineTextBox "a "
-        AXRole: AXStaticText "/ "
-            AXRole: AXInlineTextBox "/ "
-        AXRole: AXStaticText "b"
-            AXRole: AXInlineTextBox "b"
+    AXRole: AXGroup
+        AXRole: AXMath
+            AXRole: AXStaticText "x "
+                AXRole: AXInlineTextBox "x "
+            AXRole: AXStaticText "+ "
+                AXRole: AXInlineTextBox "+ "
+            AXRole: AXStaticText "a "
+                AXRole: AXInlineTextBox "a "
+            AXRole: AXStaticText "/ "
+                AXRole: AXInlineTextBox "/ "
+            AXRole: AXStaticText "b"
+                AXRole: AXInlineTextBox "b"
     AXRole: AXMain
         AXRole: AXArticle
             AXRole: AXGroup
@@ -189,11 +192,13 @@
                     AXRole: AXInlineTextBox "Cell2"
         AXRole: AXTableHeaderContainer
     AXRole: AXFigure "Fig1. - Blue Box"
-        AXRole: AXImage "blue"
+        AXRole: AXGroup
+            AXRole: AXImage "blue"
         AXRole: AXFigcaption
             AXRole: AXStaticText "Fig1. - Blue Box"
                 AXRole: AXInlineTextBox "Fig1. - Blue Box"
-    AXRole: AXEmbeddedObject
+    AXRole: AXGroup
+        AXRole: AXEmbeddedObject
     AXRole: AXFooter
         AXRole: AXParagraph
             AXRole: AXStaticText "This is a footer."
diff --git a/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-scale-expected.txt b/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-bounds-expected.txt
similarity index 86%
rename from third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-scale-expected.txt
rename to third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-bounds-expected.txt
index 7e71c96..ffb7fa3 100644
--- a/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-scale-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-bounds-expected.txt
@@ -11,7 +11,7 @@
       "position": [8, 8],
       "bounds": [310, 175],
       "drawsContent": true,
-      "preferredRasterScale": 1.57741940021515
+      "preferredRasterBounds": [489, 537]
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-scale.html b/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-bounds.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-scale.html
rename to third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-bounds.html
index c035774e..1ba180b 100644
--- a/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-scale.html
+++ b/third_party/WebKit/LayoutTests/compositing/scaling/preferred-raster-bounds.html
@@ -8,7 +8,7 @@
     window.testRunner.dumpAsText();
   }
   if (window.internals)
-    window.internals.runtimeFlags.preferredImageRasterScaleEnabled = true;
+    window.internals.runtimeFlags.preferredImageRasterBoundsEnabled = true;
 
   var bgImg = new Image();
   bgImg.src = '../../paint/invalidation/resources/ducky.png';
diff --git a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-zIndex-non-auto-expected.txt b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-zIndex-non-auto-expected.txt
index 82eb66e1..82d2bbe3 100644
--- a/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-zIndex-non-auto-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css/getComputedStyle/getComputedStyle-zIndex-non-auto-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL z-index on non-positioned div assert_equals: Computed style expected "20" but got "0"
+FAIL z-index on non-positioned div assert_equals: Computed style expected "20" but got "auto"
 PASS z-index on positioned div 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/fast/performance/performance-observer-callback-after-gc.html b/third_party/WebKit/LayoutTests/fast/performance/performance-observer-callback-after-gc.html
new file mode 100644
index 0000000..6e5c8e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/performance/performance-observer-callback-after-gc.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+    var observer = new PerformanceObserver(function() {
+        t.done();
+    });
+    gc();
+    observer.observe({entryTypes: ['mark', 'measure']});
+    window.performance.measure('measure_1');
+}, 'Callback should be invoked after gc');
+</script>
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-restore-selection-when-node-comes-later-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-restore-selection-when-node-comes-later-expected.txt
new file mode 100644
index 0000000..cdbecaa26
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-restore-selection-when-node-comes-later-expected.txt
@@ -0,0 +1,13 @@
+Verify that last selected element is restored properly later, even if it failed to do so once.
+
+
+Running: selectNode
+Selected node: 'span'
+
+Running: firstReloadWithoutNodeInDOM
+Selected node: 'body'
+
+Running: secondReloadWithNodeInDOM
+Page reloaded.
+Selected node: 'span'
+
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-restore-selection-when-node-comes-later.html b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-restore-selection-when-node-comes-later.html
new file mode 100644
index 0000000..3a77fb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-restore-selection-when-node-comes-later.html
@@ -0,0 +1,112 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/elements-test.js"></script>
+<script src="./shadow/elements-panel-shadow-selection-on-refresh.js"></script>
+<script>
+
+function test()
+{
+    var domModel = WebInspector.DOMModel.fromTarget(WebInspector.targetManager.mainTarget());
+    var node;
+
+    InspectorTest.runTestSuite([
+        function selectNode(next)
+        {
+            InspectorTest.nodeWithId("inspected", onNodeFound);
+
+            function onNodeFound(n)
+            {
+                node = n;
+                InspectorTest.selectNode(node).then(onNodeSelected);
+            }
+
+            function onNodeSelected()
+            {
+                dumpSelectedNode();
+                next();
+            }
+        },
+
+        function firstReloadWithoutNodeInDOM(next)
+        {
+            InspectorTest.addSniffer(WebInspector.ElementsPanel.prototype, "_lastSelectedNodeSelectedForTest", onNodeRestored);
+            // Do a reload and pretend page's DOM doesn't have a node to restore.
+            overridePushNodeForPath(node.path());
+            InspectorTest.reloadPage(function() { });
+
+            function onNodeRestored()
+            {
+                dumpSelectedNode();
+                next();
+            }
+        },
+
+        function secondReloadWithNodeInDOM(next)
+        {
+            var pageReloaded = false;
+            var nodeRestored = false;
+            InspectorTest.addSniffer(WebInspector.ElementsPanel.prototype, "_lastSelectedNodeSelectedForTest", onNodeRestored);
+            InspectorTest.reloadPage(onPageReloaded);
+
+            function onPageReloaded()
+            {
+                pageReloaded = true;
+                maybeNext();
+            }
+
+            function onNodeRestored()
+            {
+                nodeRestored = true;
+                maybeNext();
+            }
+
+            function maybeNext()
+            {
+                if (!nodeRestored || !pageReloaded)
+                    return;
+                dumpSelectedNode();
+                next();
+            }
+        },
+
+    ]);
+
+    function dumpSelectedNode()
+    {
+        var selectedElement = InspectorTest.firstElementsTreeOutline().selectedTreeElement;
+        var nodeName = selectedElement ? selectedElement.node().nodeNameInCorrectCase() : "null";
+        InspectorTest.addResult("Selected node: '" + nodeName + "'");
+    }
+
+    /**
+     * @param {string} pathToIgnore
+     */
+    function overridePushNodeForPath(pathToIgnore)
+    {
+        var original = InspectorTest.override(WebInspector.DOMModel.prototype, "pushNodeByPathToFrontend", override);
+
+        function override(nodePath, callback)
+        {
+            if (nodePath === pathToIgnore) {
+                setTimeout(callback.bind(null), 0);
+                return;
+            }
+            original(nodePath, callback);
+        }
+    }
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Verify that last selected element is restored properly later, even if
+it failed to do so once.
+</p>
+<div>
+    <span id="inspected"></span>
+</div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href-expected.txt
index b667eaa..67fdede 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href-expected.txt
@@ -3,10 +3,10 @@
 
  javascript:alert('foo') 
 ,bogusSheet1.css
-inspector,elements,bogusSheet2.css
-tests,inspector,inspector-test.js
-tests,inspector,elements-test.js
-http://127.0.0.1/stylesheet.css
 http://127.0.0.1/script.js
+http://127.0.0.1/stylesheet.css
 http://127.0.0.1/target.html
+inspector,elements,bogusSheet2.css
+tests,inspector,elements-test.js
+tests,inspector,inspector-test.js
 
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href.html b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href.html
index d612d37..6dfcb8d 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/elements-panel-rewrite-href.html
@@ -15,6 +15,7 @@
     {
         var innerMapping = InspectorTest.domModel._idToDOMNode;
 
+        var outputLines = [];
         for (var nodeId in innerMapping) {
             var node = innerMapping[nodeId];
             if (node.nodeName() === "LINK" || node.nodeName() === "SCRIPT") {
@@ -25,7 +26,7 @@
                     continue;
                 }
                 if (href.startsWith("http:")) {
-                    InspectorTest.addResult(href);
+                    outputLines.push(href);
                     continue;
                 }
                 var parsedURL = href.asParsedURL();
@@ -36,11 +37,13 @@
                 var split = parsedURL.path.split("/");
                 for (var i = split.length - 1, j = 0; j < 3 && i >= 0; --i, ++j)
                     segments.push(split[i]);
-                InspectorTest.addResult(segments.reverse());
+                outputLines.push(segments.reverse());
             }
             if (node.nodeName() === "A")
-                InspectorTest.addResult(node.resolveURL(node.getAttribute("href")));
+                outputLines.push(node.resolveURL(node.getAttribute("href")));
         }
+        outputLines.sort();
+        InspectorTest.addResult(outputLines.join("\n"));
         InspectorTest.completeTest();
     }
 }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt
index 11c286d..f77d09f 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/debugger-eval-while-paused-throws-expected.txt
@@ -7,7 +7,7 @@
 VM:6 Uncaught Error: injectedObj.func
     at Object.func (<anonymous>:6:23)
     at injectedFunction (<anonymous>:9:28)
-    at eval (eval at evaluate (:119:21), <anonymous>:1:1)
+    at eval (eval at evaluate (:111:21), <anonymous>:1:1)
     at testFunction (test.js:23:5)
 func @ VM:6
 injectedFunction @ VM:9
@@ -16,7 +16,7 @@
 localObj.func()
 test.js:15 Uncaught Error: localObj.func
     at Object.func (test.js:20:19)
-    at eval (eval at evaluate (:119:21), <anonymous>:1:10)
+    at eval (eval at evaluate (:111:21), <anonymous>:1:10)
     at testFunction (test.js:23:5)
 func @ test.js:15
 (anonymous) @ VM:1
@@ -24,7 +24,7 @@
 globalObj.func()
 test.js:6 Uncaught Error: globalObj.func
     at Object.func (test.js:11:15)
-    at eval (eval at evaluate (:119:21), <anonymous>:1:11)
+    at eval (eval at evaluate (:111:21), <anonymous>:1:11)
     at testFunction (test.js:23:5)
 func @ test.js:6
 (anonymous) @ VM:1
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/css/css2-system-fonts-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/css/css2-system-fonts-expected.txt
index 7a5a5fa..03519a1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/css/css2-system-fonts-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/css/css2-system-fonts-expected.txt
@@ -1,7 +1,7 @@
 This tests platform specific system font styles. If any of the styles appear in monospace the test fails.
-caption: normal normal normal normal 13px / normal BlinkMacSystemFont
-icon: normal normal normal normal 13px / normal BlinkMacSystemFont
-menu: normal normal normal normal 13px / normal BlinkMacSystemFont
-message-box: normal normal normal normal 13px / normal BlinkMacSystemFont
-small-caption: normal normal normal normal 11px / normal BlinkMacSystemFont
-status-bar: normal normal normal normal 10px / normal BlinkMacSystemFont
+caption: normal normal normal normal 13px / normal system-ui
+icon: normal normal normal normal 13px / normal system-ui
+menu: normal normal normal normal 13px / normal system-ui
+message-box: normal normal normal normal 13px / normal system-ui
+small-caption: normal normal normal normal 11px / normal system-ui
+status-bar: normal normal normal normal 10px / normal system-ui
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
index dcd40e8..b1ed580 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8PerformanceObserverCustom.cpp
@@ -10,6 +10,7 @@
 #include "bindings/core/v8/V8DOMWrapper.h"
 #include "bindings/core/v8/V8GCController.h"
 #include "bindings/core/v8/V8Performance.h"
+#include "bindings/core/v8/V8PrivateProperty.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/PerformanceObserver.h"
 
@@ -48,12 +49,18 @@
             "The callback provided as parameter 1 is not a function."));
     return;
   }
-  PerformanceObserverCallback* callback = PerformanceObserverCallback::create(
-      info.GetIsolate(), v8::Local<v8::Function>::Cast(info[0]));
+  v8::Local<v8::Function> v8Callback = v8::Local<v8::Function>::Cast(info[0]);
+  PerformanceObserverCallback* callback =
+      PerformanceObserverCallback::create(info.GetIsolate(), v8Callback);
 
   PerformanceObserver* observer = PerformanceObserver::create(
       ScriptState::forReceiverObject(info), performance, callback);
 
+  // TODO(bashi): Don't set private property (and remove this custom
+  // constructor) when we can call setWrapperReference() correctly.
+  // crbug.com/468240.
+  V8PrivateProperty::getPerformanceObserverCallback(info.GetIsolate())
+      .set(info.GetIsolate()->GetCurrentContext(), wrapper, v8Callback);
   v8SetReturnValue(info,
                    V8DOMWrapper::associateObjectWithWrapper(
                        info.GetIsolate(), observer, &wrapperTypeInfo, wrapper));
diff --git a/third_party/WebKit/Source/bindings/scripts/compute_interfaces_info_overall.py b/third_party/WebKit/Source/bindings/scripts/compute_interfaces_info_overall.py
index 6dd0e85..55ebf80 100755
--- a/third_party/WebKit/Source/bindings/scripts/compute_interfaces_info_overall.py
+++ b/third_party/WebKit/Source/bindings/scripts/compute_interfaces_info_overall.py
@@ -81,12 +81,17 @@
 Design doc: http://www.chromium.org/developers/design-documents/idl-build
 """
 
-from collections import defaultdict
-import cPickle as pickle
+# pylint: disable=relative-import
+
 import optparse
 import sys
 
-from utilities import idl_filename_to_component, read_pickle_files, write_pickle_file, merge_dict_recursively, shorten_union_name
+from collections import defaultdict
+from utilities import idl_filename_to_component
+from utilities import merge_dict_recursively
+from utilities import read_pickle_files
+from utilities import shorten_union_name
+from utilities import write_pickle_file
 
 INHERITED_EXTENDED_ATTRIBUTES = set([
     'ActiveScriptWrappable',
diff --git a/third_party/WebKit/Source/bindings/scripts/generate_global_constructors.py b/third_party/WebKit/Source/bindings/scripts/generate_global_constructors.py
index 417f9a8..4b759de7 100755
--- a/third_party/WebKit/Source/bindings/scripts/generate_global_constructors.py
+++ b/third_party/WebKit/Source/bindings/scripts/generate_global_constructors.py
@@ -17,17 +17,25 @@
 Design document: http://www.chromium.org/developers/design-documents/idl-build
 """
 
+# pylint: disable=relative-import
+
 import itertools
 import optparse
 import os
-import cPickle as pickle
 import re
 import sys
 
-from v8_utilities import EXPOSED_EXECUTION_CONTEXT_METHOD
-
 from collections import defaultdict
-from utilities import should_generate_impl_file_from_idl, get_file_contents, idl_filename_to_interface_name, read_file_to_list, write_file, get_interface_extended_attributes_from_idl, get_interface_exposed_arguments, is_callback_interface_from_idl
+from utilities import get_file_contents
+from utilities import get_interface_exposed_arguments
+from utilities import get_interface_extended_attributes_from_idl
+from utilities import idl_filename_to_interface_name
+from utilities import is_callback_interface_from_idl
+from utilities import read_file_to_list
+from utilities import read_pickle_file
+from utilities import should_generate_impl_file_from_idl
+from utilities import write_file
+from v8_utilities import EXPOSED_EXECUTION_CONTEXT_METHOD
 
 interface_name_to_global_names = {}
 global_name_to_constructors = defaultdict(list)
@@ -155,8 +163,7 @@
     interface_name_idl_filename = [(args[i], args[i + 1])
                                    for i in range(0, len(args), 2)]
 
-    with open(options.global_objects_file) as global_objects_file:
-        interface_name_to_global_names.update(pickle.load(global_objects_file))
+    interface_name_to_global_names.update(read_pickle_file(options.global_objects_file))
 
     for idl_filename in idl_files:
         record_global_constructors(idl_filename)
diff --git a/third_party/WebKit/Source/bindings/scripts/generate_init_partial_interfaces.py b/third_party/WebKit/Source/bindings/scripts/generate_init_partial_interfaces.py
index 0cc923ca..2ea53ec 100755
--- a/third_party/WebKit/Source/bindings/scripts/generate_init_partial_interfaces.py
+++ b/third_party/WebKit/Source/bindings/scripts/generate_init_partial_interfaces.py
@@ -5,11 +5,13 @@
 
 """Generate initPartialInterfacesInModules(), which registers partial interfaces in modules to core interfaces."""
 
-import cPickle as pickle
+# pylint: disable=relative-import
+
 from optparse import OptionParser
 import os
 import posixpath
 import sys
+
 from utilities import get_file_contents
 from utilities import idl_filename_to_interface_name
 from utilities import read_idl_files_list_from_file
diff --git a/third_party/WebKit/Source/bindings/scripts/idl_compiler.py b/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
index aa85250..ca066806 100755
--- a/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
+++ b/third_party/WebKit/Source/bindings/scripts/idl_compiler.py
@@ -37,7 +37,6 @@
 import abc
 from optparse import OptionParser
 import os
-import cPickle as pickle
 import sys
 
 from code_generator_v8 import CodeGeneratorDictionaryImpl
diff --git a/third_party/WebKit/Source/bindings/scripts/utilities.py b/third_party/WebKit/Source/bindings/scripts/utilities.py
index a06ff24..a212453f 100644
--- a/third_party/WebKit/Source/bindings/scripts/utilities.py
+++ b/third_party/WebKit/Source/bindings/scripts/utilities.py
@@ -299,8 +299,12 @@
 
 def read_pickle_files(pickle_filenames):
     for pickle_filename in pickle_filenames:
-        with open(pickle_filename) as pickle_file:
-            yield pickle.load(pickle_file)
+        yield read_pickle_file(pickle_filename)
+
+
+def read_pickle_file(pickle_filename):
+    with open(pickle_filename) as pickle_file:
+        return pickle.load(pickle_file)
 
 
 def write_file(new_text, destination_filename):
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index b80fcb8..2d99858c 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -2833,7 +2833,7 @@
     case CSSPropertyFontVariantNumeric:
       return valueForFontVariantNumeric(style);
     case CSSPropertyZIndex:
-      if (style.hasAutoZIndex())
+      if (style.hasAutoZIndex() || !style.isStackingContext())
         return CSSIdentifierValue::create(CSSValueAuto);
       return CSSPrimitiveValue::create(style.zIndex(),
                                        CSSPrimitiveValue::UnitType::Integer);
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
index 4ade9dae..1242991b 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
@@ -39,6 +39,7 @@
 #include "core/css/MediaList.h"
 #include "core/css/MediaQuery.h"
 #include "core/css/MediaValuesDynamic.h"
+#include "core/css/MediaValuesInitialViewport.h"
 #include "core/css/resolver/MediaQueryResult.h"
 #include "core/dom/NodeComputedStyle.h"
 #include "core/frame/FrameHost.h"
@@ -66,21 +67,20 @@
 using FunctionMap = HashMap<StringImpl*, EvalFunc>;
 static FunctionMap* gFunctionMap;
 
-MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
-    : m_expectedResult(mediaFeatureResult) {}
-
-MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType,
-                                         bool mediaFeatureResult)
-    : m_mediaType(acceptedMediaType), m_expectedResult(mediaFeatureResult) {}
+MediaQueryEvaluator::MediaQueryEvaluator(const char* acceptedMediaType)
+    : m_mediaType(acceptedMediaType) {}
 
 MediaQueryEvaluator::MediaQueryEvaluator(LocalFrame* frame)
-    // Doesn't matter when we have m_frame and m_style.
-    : m_expectedResult(false),
-      m_mediaValues(MediaValues::createDynamicIfFrameExists(frame)) {}
+    : m_mediaValues(MediaValues::createDynamicIfFrameExists(frame)) {}
 
 MediaQueryEvaluator::MediaQueryEvaluator(const MediaValues& mediaValues)
-    : m_expectedResult(false),  // Doesn't matter when we have mediaValues.
-      m_mediaValues(mediaValues.copy()) {}
+    : m_mediaValues(mediaValues.copy()) {}
+
+MediaQueryEvaluator::MediaQueryEvaluator(
+    MediaValuesInitialViewport* mediaValues)
+    : m_mediaValues(mediaValues) {
+  DCHECK(mediaValues);
+}
 
 MediaQueryEvaluator::~MediaQueryEvaluator() {}
 
@@ -741,7 +741,7 @@
 
 bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const {
   if (!m_mediaValues || !m_mediaValues->hasValues())
-    return m_expectedResult;
+    return true;
 
   DCHECK(gFunctionMap);
 
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h
index 695117e..56588f3 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h
+++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.h
@@ -39,6 +39,7 @@
 class MediaQueryResult;
 class MediaQuerySet;
 class MediaValues;
+class MediaValuesInitialViewport;
 
 using MediaQueryResultList = HeapVector<Member<MediaQueryResult>>;
 
@@ -60,18 +61,13 @@
  public:
   static void init();
 
-  // Creates evaluator which evaluates only simple media queries
-  // Evaluator returns true for "all", and returns value of \mediaFeatureResult
-  // for any media features.
-
-  explicit MediaQueryEvaluator(bool mediaFeatureResult = false);
+  // Creates evaluator which evaluates to true for all media queries.
+  MediaQueryEvaluator() {}
 
   // Creates evaluator which evaluates only simple media queries
-  // Evaluator returns true for acceptedMediaType and returns value of
-  // \mediafeatureResult for any media features.
-
-  MediaQueryEvaluator(const char* acceptedMediaType,
-                      bool mediaFeatureResult = false);
+  // Evaluator returns true for acceptedMediaType and returns true for any media
+  // features.
+  MediaQueryEvaluator(const char* acceptedMediaType);
 
   // Creates evaluator which evaluates full media queries.
   explicit MediaQueryEvaluator(LocalFrame*);
@@ -80,19 +76,21 @@
   // values.
   explicit MediaQueryEvaluator(const MediaValues&);
 
+  explicit MediaQueryEvaluator(MediaValuesInitialViewport*);
+
   ~MediaQueryEvaluator();
 
   bool mediaTypeMatch(const String& mediaTypeToMatch) const;
 
   // Evaluates a list of media queries.
   bool eval(const MediaQuerySet*,
-            MediaQueryResultList* viewportDependent = 0,
-            MediaQueryResultList* deviceDependent = 0) const;
+            MediaQueryResultList* viewportDependent = nullptr,
+            MediaQueryResultList* deviceDependent = nullptr) const;
 
   // Evaluates media query.
   bool eval(const MediaQuery*,
-            MediaQueryResultList* viewportDependent = 0,
-            MediaQueryResultList* deviceDependent = 0) const;
+            MediaQueryResultList* viewportDependent = nullptr,
+            MediaQueryResultList* deviceDependent = nullptr) const;
 
   // Evaluates media query subexpression, ie "and (media-feature: value)" part.
   bool eval(const MediaQueryExp*) const;
@@ -103,7 +101,6 @@
   const String mediaType() const;
 
   String m_mediaType;
-  bool m_expectedResult;
   Member<MediaValues> m_mediaValues;
 };
 
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
index bca7472..b264896 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluatorTest.cpp
@@ -7,6 +7,7 @@
 #include "core/MediaTypeNames.h"
 #include "core/css/MediaList.h"
 #include "core/css/MediaValuesCached.h"
+#include "core/css/MediaValuesInitialViewport.h"
 #include "core/frame/FrameView.h"
 #include "core/testing/DummyPageHolder.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -213,4 +214,18 @@
   testMQEvaluator(floatNonFriendlyViewportTestCases, mediaQueryEvaluator);
 }
 
+TEST(MediaQueryEvaluatorTest, InitialViewport) {
+  std::unique_ptr<DummyPageHolder> pageHolder =
+      DummyPageHolder::create(IntSize(500, 500));
+  pageHolder->frameView().setMediaType(MediaTypeNames::screen);
+  pageHolder->frameView().setLayoutSizeFixedToFrameSize(false);
+  pageHolder->frameView().setInitialViewportSize(IntSize(500, 500));
+  pageHolder->frameView().setLayoutSize(IntSize(800, 800));
+  pageHolder->frameView().setFrameRect(IntRect(0, 0, 800, 800));
+
+  MediaQueryEvaluator mediaQueryEvaluator(
+      MediaValuesInitialViewport::create(pageHolder->frame()));
+  testMQEvaluator(viewportTestCases, mediaQueryEvaluator);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.cpp b/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.cpp
index 8ed0228..3225a33 100644
--- a/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.cpp
+++ b/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.cpp
@@ -11,7 +11,8 @@
 
 namespace blink {
 
-MediaValues* MediaValuesInitialViewport::create(LocalFrame& frame) {
+MediaValuesInitialViewport* MediaValuesInitialViewport::create(
+    LocalFrame& frame) {
   return new MediaValuesInitialViewport(frame);
 }
 
diff --git a/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.h b/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.h
index cffe9d9..9cf1d21 100644
--- a/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.h
+++ b/third_party/WebKit/Source/core/css/MediaValuesInitialViewport.h
@@ -11,7 +11,7 @@
 
 class CORE_EXPORT MediaValuesInitialViewport final : public MediaValuesDynamic {
  public:
-  static MediaValues* create(LocalFrame&);
+  static MediaValuesInitialViewport* create(LocalFrame&);
 
   double viewportWidth() const override;
   double viewportHeight() const override;
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 175f072..6935b77 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -46,9 +46,11 @@
 #include "core/css/CSSValuePair.h"
 #include "core/css/resolver/FilterOperationResolver.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/UseCounter.h"
 #include "core/style/ClipPathOperation.h"
 #include "core/style/TextSizeAdjust.h"
 #include "core/svg/SVGURIReference.h"
+#include "platform/fonts/FontCache.h"
 #include "platform/transforms/RotateTransformOperation.h"
 #include "platform/transforms/ScaleTransformOperation.h"
 #include "platform/transforms/TranslateTransformOperation.h"
@@ -188,6 +190,12 @@
   if (value.isFontFamilyValue()) {
     genericFamily = FontDescription::NoFamily;
     familyName = AtomicString(toCSSFontFamilyValue(value).value());
+#if OS(MACOSX)
+    if (familyName == FontCache::legacySystemFontFamily()) {
+      UseCounter::count(state.document(), UseCounter::BlinkMacSystemFont);
+      familyName = FontFamilyNames::system_ui;
+    }
+#endif
   } else if (state.document().settings()) {
     genericFamily =
         convertGenericFamily(toCSSIdentifierValue(value).getValueID());
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
index f35858d..70d36aac 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -185,13 +185,10 @@
       m_printMediaType(false),
       m_styleSharingDepth(0) {
   FrameView* view = document.view();
-  if (view) {
-    m_medium = new MediaQueryEvaluator(&view->frame());
-    m_printMediaType =
-        equalIgnoringCase(view->mediaType(), MediaTypeNames::print);
-  } else {
-    m_medium = new MediaQueryEvaluator("all");
-  }
+  DCHECK(view);
+  m_medium = new MediaQueryEvaluator(&view->frame());
+  m_printMediaType =
+      equalIgnoringCase(view->mediaType(), MediaTypeNames::print);
 
   initWatchedSelectorRules();
 }
diff --git a/third_party/WebKit/Source/core/dom/StyleElement.cpp b/third_party/WebKit/Source/core/dom/StyleElement.cpp
index 323e76df..3bc9afe 100644
--- a/third_party/WebKit/Source/core/dom/StyleElement.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleElement.cpp
@@ -172,8 +172,8 @@
   if (isCSS(element, type) && passesContentSecurityPolicyChecks) {
     MediaQuerySet* mediaQueries = MediaQuerySet::create(media());
 
-    MediaQueryEvaluator screenEval("screen", true);
-    MediaQueryEvaluator printEval("print", true);
+    MediaQueryEvaluator screenEval("screen");
+    MediaQueryEvaluator printEval("print");
     if (screenEval.eval(mediaQueries) || printEval.eval(mediaQueries)) {
       m_loading = true;
       TextPosition startPosition =
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp
index a6e24d5..0b2b9003 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.cpp
@@ -39,7 +39,6 @@
 SpellCheckRequest::SpellCheckRequest(
     Range* checkingRange,
     const String& text,
-    TextCheckingProcessType processType,
     const Vector<uint32_t>& documentMarkersInRange,
     const Vector<unsigned>& documentMarkerOffsets,
     int requestNumber)
@@ -49,7 +48,6 @@
           blink::rootEditableElement(*m_checkingRange->startContainer())),
       m_requestData(unrequestedTextCheckingSequence,
                     text,
-                    processType,
                     documentMarkersInRange,
                     documentMarkerOffsets),
       m_requestNumber(requestNumber) {
@@ -74,7 +72,6 @@
 
 // static
 SpellCheckRequest* SpellCheckRequest::create(
-    TextCheckingProcessType processType,
     const EphemeralRange& checkingRange,
     int requestNumber) {
   if (checkingRange.isNull())
@@ -100,8 +97,8 @@
     offsets[i] = markers[i]->startOffset();
   }
 
-  return new SpellCheckRequest(checkingRangeObject, text, processType, hashes,
-                               offsets, requestNumber);
+  return new SpellCheckRequest(checkingRangeObject, text, hashes, offsets,
+                               requestNumber);
 }
 
 const TextCheckingRequestData& SpellCheckRequest::data() const {
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h
index 9c4450e..47a4b2fe 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckRequester.h
@@ -45,8 +45,7 @@
 
 class SpellCheckRequest final : public TextCheckingRequest {
  public:
-  static SpellCheckRequest* create(TextCheckingProcessType,
-                                   const EphemeralRange& checkingRange,
+  static SpellCheckRequest* create(const EphemeralRange& checkingRange,
                                    int requestNumber = 0);
 
   ~SpellCheckRequest() override;
@@ -69,7 +68,6 @@
  private:
   SpellCheckRequest(Range* checkingRange,
                     const String&,
-                    TextCheckingProcessType,
                     const Vector<uint32_t>& documentMarkersInRange,
                     const Vector<unsigned>& documentMarkerOffsets,
                     int requestNumber);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
index f84b61e..4865ae1f 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -519,8 +519,7 @@
   // Check the full paragraph instead if the paragraph is short, which saves
   // the cost on sentence boundary finding.
   if (fullParagraphToCheck.rangeLength() <= kChunkSize) {
-    SpellCheckRequest* request =
-        SpellCheckRequest::create(TextCheckingProcessBatch, paragraphRange, 0);
+    SpellCheckRequest* request = SpellCheckRequest::create(paragraphRange, 0);
     if (request)
       m_spellCheckRequester->requestCheckingFor(request);
     return;
@@ -536,8 +535,8 @@
                                     ? expandEndToSentenceBoundary(chunkRange)
                                     : expandRangeToSentenceBoundary(chunkRange);
 
-    SpellCheckRequest* request = SpellCheckRequest::create(
-        TextCheckingProcessBatch, checkRange, requestNum);
+    SpellCheckRequest* request =
+        SpellCheckRequest::create(checkRange, requestNum);
     if (request)
       m_spellCheckRequester->requestCheckingFor(request);
 
@@ -1004,7 +1003,7 @@
     return;
   const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element);
   m_spellCheckRequester->requestCheckingFor(
-      SpellCheckRequest::create(TextCheckingProcessBatch, rangeToCheck));
+      SpellCheckRequest::create(rangeToCheck));
 }
 
 DEFINE_TRACE(SpellChecker) {
diff --git a/third_party/WebKit/Source/core/fetch/ImageResource.cpp b/third_party/WebKit/Source/core/fetch/ImageResource.cpp
index e4c9359..d40de18 100644
--- a/third_party/WebKit/Source/core/fetch/ImageResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/ImageResource.cpp
@@ -436,6 +436,7 @@
     // document:
     // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1VsqpxoL7aciY/edit?usp=sharing
     clearData();
+    setEncodedSizeMemoryUsage(0);
   }
   Resource::finish(loadFinishTime);
 }
diff --git a/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp b/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp
index 00c2c99..5f02732 100644
--- a/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/ImageResourceTest.cpp
@@ -348,7 +348,9 @@
       nullptr);
   cachedImage->appendData(reinterpret_cast<const char*>(jpeg.data()),
                           jpeg.size());
+  EXPECT_NE(0u, cachedImage->encodedSizeMemoryUsageForTesting());
   cachedImage->finish();
+  EXPECT_EQ(0u, cachedImage->encodedSizeMemoryUsageForTesting());
   EXPECT_FALSE(cachedImage->errorOccurred());
   ASSERT_TRUE(cachedImage->hasImage());
   EXPECT_FALSE(cachedImage->getImage()->isNull());
diff --git a/third_party/WebKit/Source/core/fetch/Resource.cpp b/third_party/WebKit/Source/core/fetch/Resource.cpp
index 46a06cd..797293a 100644
--- a/third_party/WebKit/Source/core/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/core/fetch/Resource.cpp
@@ -304,6 +304,7 @@
     : m_loadFinishTime(0),
       m_identifier(0),
       m_encodedSize(0),
+      m_encodedSizeMemoryUsage(0),
       m_decodedSize(0),
       m_overheadSize(calculateOverheadSize()),
       m_preloadCount(0),
@@ -793,13 +794,18 @@
 }
 
 void Resource::setEncodedSize(size_t encodedSize) {
-  if (encodedSize == m_encodedSize)
+  if (encodedSize == m_encodedSize && encodedSize == m_encodedSizeMemoryUsage)
     return;
   size_t oldSize = size();
   m_encodedSize = encodedSize;
+  m_encodedSizeMemoryUsage = encodedSize;
   memoryCache()->update(this, oldSize, size());
 }
 
+void Resource::setEncodedSizeMemoryUsage(size_t encodedSize) {
+  m_encodedSizeMemoryUsage = encodedSize;
+}
+
 void Resource::didAccessDecodedData() {
   memoryCache()->updateDecodedResource(this, UpdateForAccess);
   memoryCache()->prune();
@@ -861,11 +867,11 @@
   const String dumpName = getMemoryDumpName();
   WebMemoryAllocatorDump* dump =
       memoryDump->createMemoryAllocatorDump(dumpName);
-  dump->addScalar("encoded_size", "bytes", m_encodedSize);
+  dump->addScalar("encoded_size", "bytes", m_encodedSizeMemoryUsage);
   if (hasClientsOrObservers())
-    dump->addScalar("live_size", "bytes", m_encodedSize);
+    dump->addScalar("live_size", "bytes", m_encodedSizeMemoryUsage);
   else
-    dump->addScalar("dead_size", "bytes", m_encodedSize);
+    dump->addScalar("dead_size", "bytes", m_encodedSizeMemoryUsage);
 
   if (m_data)
     m_data->onMemoryDump(dumpName, memoryDump);
diff --git a/third_party/WebKit/Source/core/fetch/Resource.h b/third_party/WebKit/Source/core/fetch/Resource.h
index 02b23892..86e6185d 100644
--- a/third_party/WebKit/Source/core/fetch/Resource.h
+++ b/third_party/WebKit/Source/core/fetch/Resource.h
@@ -169,7 +169,24 @@
   void setStatus(Status status) { m_status = status; }
 
   size_t size() const { return encodedSize() + decodedSize() + overheadSize(); }
+
+  // Returns the size of content (response body) before decoding. Adding a new
+  // usage of this function is not recommended (See the TODO below).
+  //
+  // TODO(hiroshige): Now encodedSize/decodedSize states are inconsistent and
+  // need to be refactored (crbug/643135).
   size_t encodedSize() const { return m_encodedSize; }
+
+  // Returns the current memory usage for the encoded data. Adding a new usage
+  // of this function is not recommended as the same reason as |encodedSize()|.
+  //
+  // |encodedSize()| and |encodedSizeMemoryUsageForTesting()| can return
+  // different values, e.g., when ImageResource purges encoded image data after
+  // finishing loading.
+  size_t encodedSizeMemoryUsageForTesting() const {
+    return m_encodedSizeMemoryUsage;
+  }
+
   size_t decodedSize() const { return m_decodedSize; }
   size_t overheadSize() const { return m_overheadSize; }
 
@@ -319,6 +336,7 @@
   virtual void destroyDecodedDataForFailedRevalidation() {}
 
   void setEncodedSize(size_t);
+  void setEncodedSizeMemoryUsage(size_t);
   void setDecodedSize(size_t);
   void didAccessDecodedData();
 
@@ -401,6 +419,7 @@
   unsigned long m_identifier;
 
   size_t m_encodedSize;
+  size_t m_encodedSizeMemoryUsage;
   size_t m_decodedSize;
 
   // Resource::calculateOverheadSize() is affected by changes in
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 8c7c5fa..67cef05 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1375,6 +1375,7 @@
     WebAudioConstantSourceNode = 1651,
     LoopbackEmbeddedInSecureContext = 1652,
     LoopbackEmbeddedInNonSecureContext = 1653,
+    BlinkMacSystemFont = 1654,
 
     // Add new features immediately above this line. Don't change assigned
     // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm b/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm
index 093eed34..715ea2de 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm
@@ -250,14 +250,14 @@
                   : FontStyleNormal;
   fontWeight = toFontWeight([fontManager weightOfFont:font]);
   fontSize = [font pointSize];
-  fontFamily = @"BlinkMacSystemFont";
+  fontFamily = FontFamilyNames::system_ui;
 }
 
 bool LayoutThemeMac::needsHackForTextControlWithFontFamily(
     const AtomicString& family) const {
   // This hack is only applied on OSX 10.9.
   // https://code.google.com/p/chromium/issues/detail?id=515989#c8
-  return IsOS10_9() && family == "BlinkMacSystemFont";
+  return IsOS10_9() && family == FontFamilyNames::system_ui;
 }
 
 static RGBA32 convertNSColorToColor(NSColor* color) {
@@ -478,7 +478,8 @@
       return true;
     if (!fontSizeMatchesToControlSize(style))
       return true;
-    if (style.getFontDescription().family().family() != "BlinkMacSystemFont")
+    if (style.getFontDescription().family().family() !=
+        FontFamilyNames::system_ui)
       return true;
     if (!style.height().isIntrinsicOrAuto())
       return true;
@@ -644,7 +645,7 @@
 
   NSFont* font = [NSFont
       systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSize]];
-  fontDescription.firstFamily().setFamily(@"BlinkMacSystemFont");
+  fontDescription.firstFamily().setFamily(FontFamilyNames::system_ui);
   fontDescription.setComputedSize([font pointSize] * style.effectiveZoom());
   fontDescription.setSpecifiedSize([font pointSize] * style.effectiveZoom());
 
@@ -980,15 +981,8 @@
     [m_textField.get() setBezeled:YES];
     [m_textField.get() setEditable:YES];
     [m_textField.get() setFocusRingType:NSFocusRingTypeExterior];
-#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
     [m_textField.get() setDrawsBackground:YES];
     [m_textField.get() setBackgroundColor:[NSColor whiteColor]];
-#else
-    // Post-Lion, Blink can be in charge of paintinng the background
-    // thanks to the workaround in place for <rdar://problem/11385461>,
-    // which is implemented above as _coreUIDrawOptionsWithFrame.
-    [m_textField.get() setDrawsBackground:NO];
-#endif
   }
 
   return m_textField.get();
diff --git a/third_party/WebKit/Source/core/paint/BoxPainter.cpp b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
index d0281a0..7ee92e0 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainter.cpp
@@ -112,32 +112,34 @@
 // if possible.
 // |srcRect| is the rect, in the space of the source image, to raster.
 // |destRect| is the rect, in the local layout space of |obj|, to raster.
-inline void updatePreferredRasterScaleFromImage(
+inline void updatePreferredRasterBoundsFromImage(
     const FloatRect srcRect,
     const FloatRect& destRect,
     const LayoutBoxModelObject& obj) {
-  if (!RuntimeEnabledFeatures::preferredImageRasterScaleEnabled())
+  if (!RuntimeEnabledFeatures::preferredImageRasterBoundsEnabled())
     return;
   // Not yet implemented for SPv2.
   if (RuntimeEnabledFeatures::slimmingPaintV2Enabled())
     return;
   if (destRect.width() == 0.0f || destRect.height() == 0.0f)
     return;
-  float widthScale = srcRect.width() / destRect.width();
-  float heightScale = srcRect.height() / destRect.height();
-  float rasterScale = std::min(std::min(widthScale, heightScale), 10.0f);
   if (PaintLayer* paintLayer = obj.layer()) {
     if (paintLayer->compositingState() != PaintsIntoOwnBacking)
       return;
-    paintLayer->graphicsLayerBacking()->setPreferredRasterScale(rasterScale);
+    // TODO(chrishtr): ensure that this rounding does not ever lose any
+    // precision.
+    paintLayer->graphicsLayerBacking()->setPreferredRasterBounds(
+        roundedIntSize(srcRect.size()));
   }
 }
 
-inline void clearPreferredRasterScale(const LayoutBox& obj) {
+inline void clearPreferredRasterBounds(const LayoutBox& obj) {
+  if (!RuntimeEnabledFeatures::preferredImageRasterBoundsEnabled())
+    return;
   if (PaintLayer* paintLayer = obj.layer()) {
     if (paintLayer->compositingState() != PaintsIntoOwnBacking)
       return;
-    paintLayer->graphicsLayerBacking()->clearPreferredRasterScale();
+    paintLayer->graphicsLayerBacking()->clearPreferredRasterBounds();
   }
 }
 
@@ -177,7 +179,7 @@
           DisplayItem::kBoxDecorationBackground))
     return;
 
-  clearPreferredRasterScale(m_layoutBox);
+  clearPreferredRasterBounds(m_layoutBox);
 
   DrawingRecorder recorder(
       paintInfo.context, displayItemClient,
@@ -656,7 +658,7 @@
   context.drawImageRRect(imageContext.image(), border, srcRect,
                          imageContext.compositeOp());
 
-  updatePreferredRasterScaleFromImage(srcRect, border.rect(), obj);
+  updatePreferredRasterBoundsFromImage(srcRect, border.rect(), obj);
 
   return true;
 }
diff --git a/third_party/WebKit/Source/core/paint/ThemePainterMac.mm b/third_party/WebKit/Source/core/paint/ThemePainterMac.mm
index 7afb12ee..5b3f2910 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainterMac.mm
+++ b/third_party/WebKit/Source/core/paint/ThemePainterMac.mm
@@ -62,24 +62,20 @@
                                      const IntRect& r) {
   LocalCurrentGraphicsContext localContext(paintInfo.context, r);
 
-#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
   bool useNSTextFieldCell = o.styleRef().hasAppearance() &&
                             o.styleRef().visitedDependentColor(
                                 CSSPropertyBackgroundColor) == Color::white &&
                             !o.styleRef().hasBackgroundImage();
 
-  // We do not use NSTextFieldCell to draw styled text fields on Lion and
-  // SnowLeopard because there are a number of bugs on those platforms that
-  // require NSTextFieldCell to be in charge of painting its own
-  // background. We need WebCore to paint styled backgrounds, so we'll use
-  // this AppKit SPI function instead.
+  // We do not use NSTextFieldCell to draw styled text fields since it induces a
+  // behavior change while remaining a fragile solution.
+  // https://bugs.chromium.org/p/chromium/issues/detail?id=658085#c3
   if (!useNSTextFieldCell) {
     _NSDrawCarbonThemeBezel(
         r, LayoutTheme::isEnabled(o) && !LayoutTheme::isReadOnlyControl(o),
         YES);
     return false;
   }
-#endif
 
   NSTextFieldCell* textField = m_layoutTheme.textField();
 
diff --git a/third_party/WebKit/Source/core/streams/ReadableStream.js b/third_party/WebKit/Source/core/streams/ReadableStream.js
index a03e652f..ce0745b 100644
--- a/third_party/WebKit/Source/core/streams/ReadableStream.js
+++ b/third_party/WebKit/Source/core/streams/ReadableStream.js
@@ -49,10 +49,6 @@
   const PULL_AGAIN = 0b1000;
   const EXTERNALLY_CONTROLLED = 0b10000;
 
-  const readableStreamControllerCancel =
-      v8.createPrivateSymbol('[[InternalCancel]]');
-  const readableStreamControllerPull = v8.createPrivateSymbol('[[InternalPull]]');
-
   const undefined = global.undefined;
   const Infinity = global.Infinity;
 
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
index 3686992..73777b3 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -329,9 +329,6 @@
                 this._treeOutlines[i].selectDOMNode(null);
         }
 
-        if (!selectedNode && this._lastValidSelectedNode)
-            this._selectedPathOnReset = this._lastValidSelectedNode.path();
-
         this._breadcrumbs.setSelectedNode(selectedNode);
 
         WebInspector.context.setFlavor(WebInspector.DOMNode, selectedNode);
@@ -339,7 +336,10 @@
         if (!selectedNode)
             return;
         selectedNode.setAsInspectedNode();
-        this._lastValidSelectedNode = selectedNode;
+        if (!this._isSettingDefaultSelectedNode) {
+            this._selectedNodeOnReset = selectedNode;
+            this._hasNonDefaultSelectedNode = true;
+        }
 
         var executionContexts = selectedNode.target().runtimeModel.executionContexts();
         var nodeFrameId = selectedNode.frameId();
@@ -382,55 +382,68 @@
             return;
         }
 
+        this._hasNonDefaultSelectedNode = false;
         WebInspector.domBreakpointsSidebarPane.restoreBreakpoints(inspectedRootDocument);
 
-        /**
-         * @this {WebInspector.ElementsPanel}
-         * @param {?WebInspector.DOMNode} candidateFocusNode
-         */
-        function selectNode(candidateFocusNode)
-        {
-            if (!candidateFocusNode)
-                candidateFocusNode = inspectedRootDocument.body || inspectedRootDocument.documentElement;
-
-            if (!candidateFocusNode)
-                return;
-
-            if (!this._pendingNodeReveal) {
-                this.selectDOMNode(candidateFocusNode);
-                if (treeOutline.selectedTreeElement)
-                    treeOutline.selectedTreeElement.expand();
-            }
-        }
-
-        /**
-         * @param {?DOMAgent.NodeId} nodeId
-         * @this {WebInspector.ElementsPanel}
-         */
-        function selectLastSelectedNode(nodeId)
-        {
-            if (this.selectedDOMNode()) {
-                // Focused node has been explicitly set while reaching out for the last selected node.
-                return;
-            }
-            var node = nodeId ? domModel.nodeForId(nodeId) : null;
-            selectNode.call(this, node);
-            this._lastSelectedNodeSelectedForTest();
-        }
-
         if (this._omitDefaultSelection)
             return;
 
-        if (this._selectedPathOnReset)
-            domModel.pushNodeByPathToFrontend(this._selectedPathOnReset, selectLastSelectedNode.bind(this));
-        else
-            selectNode.call(this, null);
-        delete this._selectedPathOnReset;
+        var savedSelectedNodeOnReset = this._selectedNodeOnReset;
+        restoreNode.call(this, domModel, this._selectedNodeOnReset);
+
+        /**
+         * @param {!WebInspector.DOMModel} domModel
+         * @param {?WebInspector.DOMNode} staleNode
+         * @this {WebInspector.ElementsPanel}
+         */
+        function restoreNode(domModel, staleNode)
+        {
+            var nodePath = staleNode ? staleNode.path() : null;
+            if (!nodePath) {
+                onNodeRestored.call(this, null);
+                return;
+            }
+            domModel.pushNodeByPathToFrontend(nodePath, onNodeRestored.bind(this));
+        }
+
+        /**
+         * @param {?DOMAgent.NodeId} restoredNodeId
+         * @this {WebInspector.ElementsPanel}
+         */
+        function onNodeRestored(restoredNodeId)
+        {
+            if (savedSelectedNodeOnReset !== this._selectedNodeOnReset)
+                return;
+            var node = restoredNodeId ? domModel.nodeForId(restoredNodeId) : null;
+            if (!node) {
+                var inspectedDocument = domModel.existingDocument();
+                node = inspectedDocument ? inspectedDocument.body || inspectedDocument.documentElement : null;
+            }
+            this._setDefaultSelectedNode(node);
+            this._lastSelectedNodeSelectedForTest();
+        }
     },
 
     _lastSelectedNodeSelectedForTest: function() { },
 
     /**
+     * @param {?WebInspector.DOMNode} node
+     */
+    _setDefaultSelectedNode: function(node)
+    {
+        if (!node || this._hasNonDefaultSelectedNode || this._pendingNodeReveal)
+            return;
+        var treeOutline = WebInspector.ElementsTreeOutline.forDOMModel(node.domModel());
+        if (!treeOutline)
+            return;
+        this._isSettingDefaultSelectedNode = true;
+        this.selectDOMNode(node);
+        this._isSettingDefaultSelectedNode = false;
+        if (treeOutline.selectedTreeElement)
+            treeOutline.selectedTreeElement.expand();
+    },
+
+    /**
      * @override
      */
     searchCanceled: function()
@@ -719,7 +732,7 @@
 
         var treeOutline = null;
         for (var i = 0; i < this._treeOutlines.length; ++i) {
-            if (this._treeOutlines[i].selectedDOMNode() === this._lastValidSelectedNode)
+            if (this._treeOutlines[i].selectedDOMNode())
                 treeOutline = this._treeOutlines[i];
         }
         if (!treeOutline)
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
index d722dde..2fed09b 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -262,6 +262,7 @@
         if (!this.selectionElement) {
             this.selectionElement = createElement("div");
             this.selectionElement.className = "selection fill";
+            this.selectionElement.style.setProperty("margin-left", this._computeLeftIndent() + "px");
             listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild);
         }
     },
@@ -1079,7 +1080,10 @@
         this._highlightSearchResults();
     },
 
-    updateDecorations: function()
+    /**
+     * @return {number}
+     */
+    _computeLeftIndent: function()
     {
         var treeElement = this.parent;
         var depth = 0;
@@ -1089,7 +1093,12 @@
         }
 
         /** Keep it in sync with elementsTreeOutline.css **/
-        this._gutterContainer.style.left = (-12 * (depth - 2) - (this.isExpandable() ? 1 : 12)) + "px";
+        return -12 * (depth - 2) - (this.isExpandable() ? 1 : 12);
+    },
+
+    updateDecorations: function()
+    {
+        this._gutterContainer.style.left = this._computeLeftIndent() + "px";
 
         if (this.isClosingTag())
             return;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
index 17b34dd1..ed0b17ca 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
@@ -73,7 +73,6 @@
 .elements-disclosure li .selection {
     display: none;
     z-index: -1;
-    margin-left: -10000px;
 }
 
 .elements-disclosure li.hovered:not(.selected) .selection {
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
index dd36b68..1b5778e 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
@@ -83,6 +83,7 @@
 
     this._headerHeight = 0;
     this._timelineHeaderElement = null;
+    this._timelineRequestsAreStale = false;
 
     this._addFilters();
     this._resetSuggestionBuilder();
@@ -293,7 +294,15 @@
             this._timelineWidget.element.classList.add("network-timeline-view");
             this._splitWidget.setMainWidget(this._timelineWidget);
 
-            this._timelineColumn = new WebInspector.NetworkTimelineColumn(this, this._dataGrid);
+            this._timelineColumn = new WebInspector.NetworkTimelineColumn(this._rowHeight, this._headerHeight, this._calculator, this._dataGrid.scrollContainer);
+
+            var dataGridScroller = this._dataGrid.scrollContainer;
+            this._dataGrid.setScrollContainer(this._timelineColumn.getScrollContainer());
+            this._dataGrid.addEventListener(WebInspector.DataGrid.Events.PaddingChanged, () => {
+                this._timelineColumn.setScrollHeight(dataGridScroller.scrollHeight)
+            });
+            this._dataGrid.addEventListener(WebInspector.ViewportDataGrid.Events.ViewportCalculated, this._redrawTimelineColumn.bind(this));
+
             this._timelineColumn.addEventListener(WebInspector.NetworkTimelineColumn.Events.RequestHovered, requestHovered.bind(this));
             this._timelineColumn.show(this._timelineWidget.element);
             this.switchViewMode(false);
@@ -318,6 +327,15 @@
         }
     },
 
+    _redrawTimelineColumn: function()
+    {
+        /** @type {!Array<!WebInspector.NetworkRequest>|undefined} */
+        var requests;
+        if (this._timelineRequestsAreStale)
+            requests = this._getOrderedRequests();
+        this._timelineColumn.update(requests);
+    },
+
     _showRecordingHint: function()
     {
         this._hideRecordingHint();
@@ -586,7 +604,11 @@
         if (!x || this._calculator === x)
             return;
 
-        this._calculator = x;
+        if (this._calculator !== x) {
+            this._calculator = x;
+            if (Runtime.experiments.isEnabled("canvasNetworkTimeline"))
+                this._timelineColumn.setCalculator(this._calculator);
+        }
         this._calculator.reset();
 
         if (this._calculator.startAtZero)
@@ -704,8 +726,18 @@
 
         this._staleRequestIds = {};
         this._updateSummaryBar();
+
         if (Runtime.experiments.isEnabled("canvasNetworkTimeline"))
-            this._timelineColumn.scheduleRefreshData();
+            this._timelineRequestsAreStale = true;
+    },
+
+    _getOrderedRequests: function()
+    {
+        var currentNode = this._dataGrid.rootNode();
+        var requestData = [];
+        while (currentNode = currentNode.traverseNextNode(true))
+            requestData.push(currentNode.request());
+        return requestData;
     },
 
     reset: function()
@@ -924,8 +956,19 @@
     {
         var largeRows = !!this._networkLogLargeRowsSetting.get();
         // TODO(allada) Make these non-magic numbers.
-        this._rowHeight = largeRows ? 41 : 21;
-        this._headerHeight = largeRows ? 31 : 27;
+        var rowHeight = largeRows ? 41 : 21;
+        var headerHeight = largeRows ? 31 : 27;
+        if (this._rowHeight !== rowHeight) {
+            this._rowHeight = rowHeight;
+            if (Runtime.experiments.isEnabled("canvasNetworkTimeline"))
+                this._timelineColumn.setRowHeight(this._rowHeight);
+        }
+        if (this._headerHeight !== headerHeight) {
+            this._headerHeight = headerHeight;
+            if (Runtime.experiments.isEnabled("canvasNetworkTimeline"))
+                this._timelineColumn.setHeaderHeight(this._headerHeight);
+        }
+
         this._dataGrid.element.classList.toggle("small", !largeRows);
         if (Runtime.experiments.isEnabled("canvasNetworkTimeline"))
             this._timelineHeaderElement.classList.toggle("small", !largeRows);
@@ -1169,7 +1212,7 @@
                 this._timelineColumnSortIcon.classList.add("sort-descending");
         }
 
-        this._timelineColumn.scheduleRefreshData();
+        this._timelineRequestsAreStale = true;
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkTimelineColumn.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkTimelineColumn.js
index f14c36d..f7442e6 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkTimelineColumn.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkTimelineColumn.js
@@ -5,10 +5,12 @@
 /**
  * @constructor
  * @extends {WebInspector.VBox}
- * @param {!WebInspector.NetworkLogView} networkLogView
- * @param {!WebInspector.SortableDataGrid} dataGrid
+ * @param {number} rowHeight
+ * @param {number} headerHeight
+ * @param {!WebInspector.NetworkTransferTimeCalculator} calculator
+ * @param {!Element} scrollContainer
  */
-WebInspector.NetworkTimelineColumn = function(networkLogView, dataGrid)
+WebInspector.NetworkTimelineColumn = function(rowHeight, headerHeight, calculator, scrollContainer)
 {
     WebInspector.VBox.call(this, true);
     this.registerRequiredCSS("network/networkTimelineColumn.css");
@@ -24,8 +26,9 @@
     /** @const */
     this._fontSize = 10;
 
-    this._dataGrid = dataGrid;
-    this._networkLogView = networkLogView;
+    this._rowHeight = rowHeight;
+    this._headerHeight = headerHeight;
+    this._calculator = calculator;
 
     this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
     this._popoverHelper.setTimeout(300, 300);
@@ -39,18 +42,14 @@
     this.element.addEventListener("mousemove", this._onMouseMove.bind(this), true);
     this.element.addEventListener("mouseleave", this.setHoveredRequest.bind(this, null), true);
 
-    this._dataGridScrollContainer = this._dataGrid.scrollContainer;
-    this._dataGridScrollContainer.addEventListener("mousewheel", event => {
+    this._boundScrollContainer = scrollContainer;
+    this._boundScrollContainer.addEventListener("mousewheel", event => {
         event.consume(true);
         this._onMouseWheel(event);
     }, true);
 
     // TODO(allada) When timeline canvas moves out of experiment move this to stylesheet.
-    this._dataGridScrollContainer.style.overflow = "hidden";
-    this._dataGrid.setScrollContainer(this._vScrollElement);
-
-    this._dataGrid.addEventListener(WebInspector.ViewportDataGrid.Events.ViewportCalculated, this._update.bind(this));
-    this._dataGrid.addEventListener(WebInspector.DataGrid.Events.PaddingChanged, this._updateHeight.bind(this));
+    this._boundScrollContainer.style.overflow = "hidden";
 
     /** @type {!Array<!WebInspector.NetworkRequest>} */
     this._requestData = [];
@@ -103,7 +102,6 @@
         if (!this._hoveredRequest)
             return;
 
-        var rowHeight = this._networkLogView.rowHeight();
         var range = WebInspector.RequestTimingView.calculateRequestTimeRanges(this._hoveredRequest, 0).find(data => data.name === "total");
         var start = this._timeToPosition(range.start);
         var end = this._timeToPosition(range.end);
@@ -113,7 +111,7 @@
 
         var rowIndex = this._requestData.findIndex(request => this._hoveredRequest === request);
         var barHeight = this._getBarHeight(range.name);
-        var y = this._networkLogView.headerHeight() + (rowHeight * rowIndex - this._vScrollElement.scrollTop) + ((rowHeight - barHeight) / 2);
+        var y = this._headerHeight + (this._rowHeight * rowIndex - this._vScrollElement.scrollTop) + ((this._rowHeight - barHeight) / 2);
 
         if (event.offsetY < y || event.offsetY > y + barHeight)
             return;
@@ -134,29 +132,21 @@
     {
         if (!this._hoveredRequest)
             return;
-        var content = WebInspector.RequestTimingView.createTimingTable(this._hoveredRequest, this._networkLogView.calculator().minimumBoundary());
+        var content = WebInspector.RequestTimingView.createTimingTable(this._hoveredRequest, this._calculator.minimumBoundary());
         popover.showForAnchor(content, anchor);
     },
 
     wasShown: function()
     {
-        this.scheduleUpdate();
+        this.scheduleDraw();
     },
 
-    scheduleRefreshData: function()
+    /**
+     * @return {!Element}
+     */
+    getScrollContainer: function()
     {
-        this._needsRefreshData = true;
-    },
-
-    _refreshDataIfNeeded: function()
-    {
-        if (!this._needsRefreshData)
-            return;
-        this._needsRefreshData = false;
-        var currentNode = this._dataGrid.rootNode();
-        this._requestData = [];
-        while (currentNode = currentNode.traverseNextNode(true))
-            this._requestData.push(currentNode.request());
+        return this._vScrollElement;
     },
 
     /**
@@ -165,7 +155,31 @@
     setHoveredRequest: function(request)
     {
         this._hoveredRequest = request;
-        this.scheduleUpdate();
+        this.scheduleDraw();
+    },
+
+    /**
+     * @param {number} height
+     */
+    setRowHeight: function(height)
+    {
+        this._rowHeight = height;
+    },
+
+    /**
+     * @param {number} height
+     */
+    setHeaderHeight: function(height)
+    {
+        this._headerHeight = height;
+    },
+
+    /**
+     * @param {!WebInspector.NetworkTimeCalculator} calculator
+     */
+    setCalculator: function(calculator)
+    {
+        this._calculator = calculator;
     },
 
     /**
@@ -183,7 +197,7 @@
     _onMouseWheel: function(event)
     {
         this._vScrollElement.scrollTop -= event.wheelDeltaY;
-        this._dataGridScrollContainer.scrollTop = this._vScrollElement.scrollTop;
+        this._boundScrollContainer.scrollTop = this._vScrollElement.scrollTop;
         this._popoverHelper.hidePopover();
 
         var request = this._getRequestFromPoint(event.offsetX, event.offsetY);
@@ -195,7 +209,7 @@
      */
     _onScroll: function(event)
     {
-        this._dataGridScrollContainer.scrollTop = this._vScrollElement.scrollTop;
+        this._boundScrollContainer.scrollTop = this._vScrollElement.scrollTop;
         this._popoverHelper.hidePopover();
     },
 
@@ -206,35 +220,39 @@
      */
     _getRequestFromPoint: function(x, y)
     {
-        var rowHeight = this._networkLogView.rowHeight();
         var scrollTop = this._vScrollElement.scrollTop;
-        return this._requestData[Math.floor((scrollTop + y - this._networkLogView.headerHeight()) / rowHeight)] || null;
+        return this._requestData[Math.floor((scrollTop + y - this._headerHeight) / this._rowHeight)] || null;
     },
 
-    scheduleUpdate: function()
+    scheduleDraw: function()
     {
         if (this._updateRequestID)
             return;
-        this._updateRequestID = this.element.window().requestAnimationFrame(this._update.bind(this));
+        this._updateRequestID = this.element.window().requestAnimationFrame(this.update.bind(this, undefined));
     },
 
-    _update: function()
+    /**
+     * @param {!Array<!WebInspector.NetworkRequest>=} requests
+     */
+    update: function(requests)
     {
+        if (requests)
+            this._requestData = requests;
         this.element.window().cancelAnimationFrame(this._updateRequestID);
         this._updateRequestID = null;
 
-        this._refreshDataIfNeeded();
-
-        this._startTime = this._networkLogView.calculator().minimumBoundary();
-        this._endTime = this._networkLogView.calculator().maximumBoundary();
+        this._startTime = this._calculator.minimumBoundary();
+        this._endTime = this._calculator.maximumBoundary();
         this._resetCanvas();
         this._draw();
     },
 
-    _updateHeight: function()
+    /**
+     * @param {number} height
+     */
+    setScrollHeight: function(height)
     {
-        var totalHeight = this._dataGridScrollContainer.scrollHeight;
-        this._vScrollContent.style.height = totalHeight + "px";
+        this._vScrollContent.style.height = height + "px";
     },
 
     _resetCanvas: function()
@@ -254,7 +272,7 @@
         WebInspector.VBox.prototype.onResize.call(this);
         this._offsetWidth = this.contentElement.offsetWidth;
         this._offsetHeight = this.contentElement.offsetHeight;
-        this.scheduleUpdate();
+        this.scheduleDraw();
     },
 
     /**
@@ -304,22 +322,21 @@
 
     _draw: function()
     {
-        var useTimingBars = !WebInspector.moduleSetting("networkColorCodeResourceTypes").get() && !this._networkLogView.calculator().startAtZero;
+        var useTimingBars = !WebInspector.moduleSetting("networkColorCodeResourceTypes").get() && !this._calculator.startAtZero;
         var requests = this._requestData;
         var context = this._canvas.getContext("2d");
         context.save();
         context.scale(window.devicePixelRatio, window.devicePixelRatio);
-        context.translate(0, this._networkLogView.headerHeight());
+        context.translate(0, this._headerHeight);
         context.rect(0, 0, this._offsetWidth, this._offsetHeight);
         context.clip();
-        var rowHeight = this._networkLogView.rowHeight();
         var scrollTop = this._vScrollElement.scrollTop;
-        var firstRequestIndex = Math.floor(scrollTop / rowHeight);
-        var lastRequestIndex = Math.min(requests.length, firstRequestIndex + Math.ceil(this._offsetHeight / rowHeight));
+        var firstRequestIndex = Math.floor(scrollTop / this._rowHeight);
+        var lastRequestIndex = Math.min(requests.length, firstRequestIndex + Math.ceil(this._offsetHeight / this._rowHeight));
         for (var i = firstRequestIndex; i < lastRequestIndex; i++) {
-            var rowOffset = rowHeight * i;
+            var rowOffset = this._rowHeight * i;
             var request = requests[i];
-            this._decorateRow(context, request, i, rowOffset - scrollTop, rowHeight);
+            this._decorateRow(context, request, i, rowOffset - scrollTop);
             if (useTimingBars)
                 this._drawTimingBars(context, request, rowOffset - scrollTop);
             else
@@ -368,7 +385,7 @@
             if (position <= gridSliceTime * pixelsPerTime)
                 continue;
             var textData = Number.secondsToString(position / pixelsPerTime);
-            context.fillText(textData, drawPosition - context.measureText(textData).width - 2, Math.floor(this._networkLogView.headerHeight() - this._fontSize / 2));
+            context.fillText(textData, drawPosition - context.measureText(textData).width - 2, Math.floor(this._headerHeight - this._fontSize / 2));
         }
         context.restore();
     },
@@ -378,7 +395,7 @@
      */
     _timelineDuration: function()
     {
-        return this._networkLogView.calculator().maximumBoundary() - this._networkLogView.calculator().minimumBoundary();
+        return this._calculator.maximumBoundary() - this._calculator.minimumBoundary();
     },
 
     /**
@@ -459,15 +476,14 @@
         var borderWidth = 1;
 
         context.save();
-        var calculator = this._networkLogView.calculator();
-        var percentages = calculator.computeBarGraphPercentages(request);
+        var percentages = this._calculator.computeBarGraphPercentages(request);
         var drawWidth = this._offsetWidth - this._leftPadding - this._rightPadding;
         var borderOffset = borderWidth % 2 === 0 ? 0 : .5;
         var start = this._leftPadding + Math.floor((percentages.start / 100) * drawWidth) + borderOffset;
         var mid = this._leftPadding + Math.floor((percentages.middle / 100) * drawWidth) + borderOffset;
         var end = this._leftPadding + Math.floor((percentages.end / 100) * drawWidth) + borderOffset;
         var height = this._getBarHeight();
-        y += Math.floor(this._networkLogView.rowHeight() / 2 - height / 2 + borderWidth) - borderWidth / 2;
+        y += Math.floor(this._rowHeight / 2 - height / 2 + borderWidth) - borderWidth / 2;
 
         context.translate(0, y);
         context.fillStyle = this._colorForResourceType(context, request);
@@ -488,7 +504,7 @@
         context.stroke();
 
         if (request === this._hoveredRequest) {
-            var labels = calculator.computeBarGraphLabels(request);
+            var labels = this._calculator.computeBarGraphLabels(request);
             this._drawSimplifiedBarDetails(context, labels.left, labels.right, start, mid, mid + barWidth + borderOffset);
         }
 
@@ -572,7 +588,7 @@
                 lineWidth = 2;
             context.fillStyle = color;
             var height = this._getBarHeight(range.name);
-            var middleBarY = y + Math.floor(this._networkLogView.rowHeight() / 2 - height / 2) + lineWidth / 2;
+            var middleBarY = y + Math.floor(this._rowHeight / 2 - height / 2) + lineWidth / 2;
             var start = this._timeToPosition(range.start);
             var end = this._timeToPosition(range.end);
             context.rect(start, middleBarY, end - start, height - lineWidth);
@@ -591,9 +607,8 @@
      * @param {!WebInspector.NetworkRequest} request
      * @param {number} rowNumber
      * @param {number} y
-     * @param {number} rowHeight
      */
-    _decorateRow: function(context, request, rowNumber, y, rowHeight)
+    _decorateRow: function(context, request, rowNumber, y)
     {
         if (rowNumber % 2 === 1 && this._hoveredRequest !== request)
             return;
@@ -604,7 +619,7 @@
             color = this._rowHoverColor;
 
         context.fillStyle = color;
-        context.rect(0, y, this._offsetWidth, rowHeight);
+        context.rect(0, y, this._offsetWidth, this._rowHeight);
         context.fill();
         context.restore();
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/settingsScreen.css b/third_party/WebKit/Source/devtools/front_end/settings/settingsScreen.css
index aa014ca..8da02f5 100644
--- a/third_party/WebKit/Source/devtools/front_end/settings/settingsScreen.css
+++ b/third_party/WebKit/Source/devtools/front_end/settings/settingsScreen.css
@@ -175,11 +175,6 @@
     margin: 1px 7px 1px 2px;
 }
 
-.help-content option {
-    background-color: #EEEEEE;
-    color: #222;
-}
-
 .settings-window-title {
     font-size: 18px;
     color: rgb(48, 57, 66);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
index 2e686d1..f8834cf 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
@@ -266,6 +266,12 @@
     color: #aaa;
 }
 
+.chrome-select optgroup,
+.chrome-select option {
+    background-color: #EEEEEE;
+    color: #222;
+}
+
 :not(.platform-mac).-theme-with-dark-background ::-webkit-scrollbar,
 :host-context(:not(.platform-mac).-theme-with-dark-background) ::-webkit-scrollbar {
     width: 14px;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/ChartViewport.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/ChartViewport.js
index 2d8ad8a..c33c2cbab 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/ChartViewport.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/ChartViewport.js
@@ -13,17 +13,15 @@
     this.contentElement.addEventListener("mousewheel", this._onMouseWheel.bind(this), false);
     this.contentElement.addEventListener("keydown", this._handleZoomPanKeys.bind(this), false);
 
-    WebInspector.installInertialDragHandle(this.contentElement, this._startDragging.bind(this), this._dragging.bind(this), this._endDragging.bind(this), "-webkit-grabbing", null);
-    WebInspector.installDragHandle(this.contentElement, this._startRangeSelection.bind(this), this._rangeSelectionDragging.bind(this), this._endRangeSelection.bind(this), "text", null);
+    this.viewportElement = this.contentElement.createChild("div", "fill");
+    WebInspector.installInertialDragHandle(this.viewportElement, this._startDragging.bind(this), this._dragging.bind(this), this._endDragging.bind(this), "-webkit-grabbing", null);
+    WebInspector.installDragHandle(this.viewportElement, this._startRangeSelection.bind(this), this._rangeSelectionDragging.bind(this), this._endRangeSelection.bind(this), "text", null);
 
-    /** @private */
     this._vScrollElement = this.contentElement.createChild("div", "flame-chart-v-scroll");
     this._vScrollContent = this._vScrollElement.createChild("div");
     this._vScrollElement.addEventListener("scroll", this._onScroll.bind(this), false);
 
-    /** @private */
     this._selectionOverlay = this.contentElement.createChild("div", "flame-chart-selection-overlay hidden");
-    /** @private */
     this._selectedTimeSpanLabel = this._selectionOverlay.createChild("div", "time-span");
 
     this.reset();
@@ -53,10 +51,10 @@
     _updateScrollBar: function()
     {
         var showScroll = this._totalHeight > this._offsetHeight;
-        if (this._vScrollElement.classList.contains("hidden") === showScroll) {
-            this._vScrollElement.classList.toggle("hidden", !showScroll);
-            this._updateContentElementSize();
-        }
+        if (this._vScrollElement.classList.contains("hidden") !== showScroll)
+            return;
+        this._vScrollElement.classList.toggle("hidden", !showScroll);
+        this._updateContentElementSize();
     },
 
     /**
@@ -72,35 +70,19 @@
     reset: function()
     {
         this._vScrollElement.scrollTop = 0;
-        /** @private */
         this._scrollTop = 0;
-        /** @private */
         this._rangeSelectionStart = 0;
-        /** @private */
         this._rangeSelectionEnd = 0;
-        /** @private */
-        this._scrollTop = 0;
-        /** @private */
         this._isDragging = false;
-        /** @private */
         this._dragStartPointX = 0;
-        /** @private */
         this._dragStartPointY = 0;
-        /** @private */
         this._dragStartScrollTop = 0;
-        /** @private */
         this._timeWindowLeft = 0;
-        /** @private */
         this._timeWindowRight = 0;
-        /** @private */
         this._offsetWidth = 0;
-        /** @private */
         this._offsetHeight = 0;
-        /** @private */
         this._totalHeight = 0;
-        /** @private */
         this._pendingAnimationTimeLeft = 0;
-        /** @private */
         this._pendingAnimationTimeRight = 0;
     },
 
@@ -120,6 +102,7 @@
     {
         this._totalHeight = totalHeight;
         this._vScrollContent.style.height = totalHeight + "px";
+        this._updateScrollBar();
         if (this._scrollTop + this._offsetHeight <= totalHeight)
             return;
         this._scrollTop = Math.max(0, totalHeight - this._offsetHeight);
@@ -192,7 +175,7 @@
         this._dragStartPointX = x;
         this._dragStartPointY = y;
         this._dragStartScrollTop = this._vScrollElement.scrollTop;
-        this.contentElement.style.cursor = "";
+        this.viewportElement.style.cursor = "";
         this.hideHighlight();
         return true;
     },
@@ -437,12 +420,12 @@
      */
     _cancelAnimation: function()
     {
-        if (this._cancelWindowTimesAnimation) {
-            this._timeWindowLeft = this._pendingAnimationTimeLeft;
-            this._timeWindowRight = this._pendingAnimationTimeRight;
-            this._cancelWindowTimesAnimation();
-            delete this._cancelWindowTimesAnimation;
-        }
+        if (!this._cancelWindowTimesAnimation)
+            return;
+        this._timeWindowLeft = this._pendingAnimationTimeLeft;
+        this._timeWindowRight = this._pendingAnimationTimeRight;
+        this._cancelWindowTimesAnimation();
+        delete this._cancelWindowTimesAnimation;
     },
 
     scheduleUpdate: function()
@@ -463,6 +446,7 @@
      */
     setWindowTimes: function(startTime, endTime)
     {
+        this.hideRangeSelection();
         if (this._muteAnimation || this._timeWindowLeft === 0 || this._timeWindowRight === Infinity || (startTime === 0 && endTime === Infinity) || (startTime === Infinity && endTime === Infinity)) {
             // Initial setup.
             this._timeWindowLeft = startTime;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
index 1ea7e10..9573e72 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
@@ -66,7 +66,7 @@
     this._dataProvider = dataProvider;
     this._calculator = new WebInspector.FlameChart.Calculator(dataProvider);
 
-    this._canvas = /** @type {!HTMLCanvasElement} */ (this.contentElement.createChild("canvas"));
+    this._canvas = /** @type {!HTMLCanvasElement} */ (this.viewportElement.createChild("canvas"));
     this._canvas.tabIndex = 1;
     this.setDefaultFocusedElement(this._canvas);
     this._canvas.addEventListener("mousemove", this._onMouseMove.bind(this), false);
@@ -74,10 +74,10 @@
     this._canvas.addEventListener("click", this._onClick.bind(this), false);
     this._canvas.addEventListener("keydown", this._onKeyDown.bind(this), false);
 
-    this._entryInfo = this.contentElement.createChild("div", "flame-chart-entry-info");
-    this._markerHighlighElement = this.contentElement.createChild("div", "flame-chart-marker-highlight-element");
-    this._highlightElement = this.contentElement.createChild("div", "flame-chart-highlight-element");
-    this._selectedElement = this.contentElement.createChild("div", "flame-chart-selected-element");
+    this._entryInfo = this.viewportElement.createChild("div", "flame-chart-entry-info");
+    this._markerHighlighElement = this.viewportElement.createChild("div", "flame-chart-marker-highlight-element");
+    this._highlightElement = this.viewportElement.createChild("div", "flame-chart-highlight-element");
+    this._selectedElement = this.viewportElement.createChild("div", "flame-chart-selected-element");
 
     this._windowLeft = 0.0;
     this._windowRight = 1.0;
@@ -498,7 +498,6 @@
     hideHighlight: function()
     {
         this._entryInfo.removeChildren();
-        this._canvas.style.cursor = "default";
         this._highlightedEntryIndex = -1;
         this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
     },
@@ -577,7 +576,7 @@
             return;
         if (this._coordinatesToGroupIndex(event.offsetX, event.offsetY) >= 0) {
             this.hideHighlight();
-            this._canvas.style.cursor = "pointer";
+            this.viewportElement.style.cursor = "pointer";
             return;
         }
         this._updateHighlight();
@@ -594,8 +593,10 @@
             this.hideHighlight();
             return;
         }
+        if (this.isDragging())
+            return;
         this._updatePopover(entryIndex);
-        this._canvas.style.cursor = this._dataProvider.canJumpToEntry(entryIndex) ? "pointer" : "default";
+        this.viewportElement.style.cursor = this._dataProvider.canJumpToEntry(entryIndex) ? "pointer" : "default";
         this.highlightEntry(entryIndex);
     },
 
@@ -1355,7 +1356,7 @@
         var style = element.style;
         style.left = barX + "px";
         style.backgroundColor = marker.color();
-        this.contentElement.appendChild(element);
+        this.viewportElement.appendChild(element);
     },
 
     /**
@@ -1396,6 +1397,7 @@
                 groups[i].expanded = expanded;
         }
         this._updateLevelPositions();
+        this._updateHeight();
     },
 
     _updateLevelPositions: function()
@@ -1502,7 +1504,7 @@
         style.top = barY + "px";
         style.width = barWidth + "px";
         style.height = this._barHeight - 1 + "px";
-        this.contentElement.appendChild(element);
+        this.viewportElement.appendChild(element);
     },
 
     /**
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index 2cccbc35..b16cd1d4e 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -500,9 +500,6 @@
   if (decision == IgnoreObject)
     return true;
 
-  if (m_layoutObject->isAnonymousBlock())
-    return true;
-
   // If this element is within a parent that cannot have children, it should not
   // be exposed.
   if (isDescendantOfLeafNode()) {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index 7770ea6..ddaf9b3c 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -3690,7 +3690,6 @@
     m_readFramebufferBinding = nullptr;
   }
   if (target) {
-    drawingBuffer()->setFramebufferBinding(target, 0);
     // Have to call drawingBuffer()->bind() here to bind back to internal fbo.
     drawingBuffer()->bind(target);
   }
@@ -4723,4 +4722,12 @@
   return params;
 }
 
+void WebGL2RenderingContextBase::
+    DrawingBufferClientRestorePixelUnpackBufferBinding() {
+  if (!contextGL())
+    return;
+  contextGL()->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
+                          objectOrZero(m_boundPixelUnpackBuffer.get()));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
index 5749eb9c..dc66a508 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -743,6 +743,9 @@
       std::unique_ptr<WebGraphicsContext3DProvider>,
       const CanvasContextCreationAttributes& requestedAttributes);
 
+  // DrawingBuffer::Client implementation.
+  void DrawingBufferClientRestorePixelUnpackBufferBinding() override;
+
   // Helper function to validate target and the attachment combination for
   // getFramebufferAttachmentParameters.  Generate GL error and return false if
   // parameters are illegal.
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index d13ba1e..b93c275 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -717,7 +717,7 @@
   if (!drawingBuffer())
     return nullptr;
 
-  drawingBuffer()->commit();
+  drawingBuffer()->resolveAndBindForReadAndDraw();
   IntSize size = clampedCanvasSize();
   OpacityMode opacityMode =
       creationAttributes().hasAlpha() ? NonOpaque : Opaque;
@@ -1061,7 +1061,7 @@
     NOTREACHED();
   }
   return DrawingBuffer::create(
-      std::move(contextProvider), clampedCanvasSize(), premultipliedAlpha,
+      std::move(contextProvider), this, clampedCanvasSize(), premultipliedAlpha,
       wantAlphaChannel, wantDepthBuffer, wantStencilBuffer, wantAntialiasing,
       preserve, webGLVersion, chromiumImageUsage);
 }
@@ -1092,12 +1092,10 @@
   m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
 
   m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
-  drawingBuffer()->setClearColor(m_clearColor);
   m_scissorEnabled = false;
   m_clearDepth = 1;
   m_clearStencil = 0;
   m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
-  drawingBuffer()->setColorMask(m_colorMask);
 
   GLint numCombinedTextureImageUnits = 0;
   contextGL()->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
@@ -1202,6 +1200,9 @@
   m_supportedTexImageSourceTypes.clear();
   ADD_VALUES_TO_SET(m_supportedTexImageSourceTypes, kSupportedTypesES2);
 
+  // The DrawingBuffer was unable to store the state that dirtied when it was
+  // initialized. Restore it now.
+  drawingBuffer()->restoreAllState();
   activateContext(this);
 }
 
@@ -1384,8 +1385,11 @@
       !drawingBuffer()->defaultBufferRequiresAlphaChannelToBePreserved());
   drawingBuffer()->clearFramebuffers(clearMask);
 
-  restoreStateAfterClear();
-  drawingBuffer()->restoreFramebufferBindings();
+  // Call the DrawingBufferClient method to restore scissor test, mask, and
+  // clear values, because we dirtied them above.
+  DrawingBufferClientRestoreScissorTest();
+  DrawingBufferClientRestoreMaskAndClearValues();
+
   drawingBuffer()->setBufferClearNeeded(false);
 
   return combinedClear ? CombinedClear : JustClear;
@@ -1418,27 +1422,6 @@
                           m_clearColor[3]);
 }
 
-void WebGLRenderingContextBase::restoreClearDepthf() {
-  if (isContextLost())
-    return;
-
-  contextGL()->ClearDepthf(m_clearDepth);
-}
-
-void WebGLRenderingContextBase::restoreClearStencil() {
-  if (isContextLost())
-    return;
-
-  contextGL()->ClearStencil(m_clearStencil);
-}
-
-void WebGLRenderingContextBase::restoreStencilMaskSeparate() {
-  if (isContextLost())
-    return;
-
-  contextGL()->StencilMaskSeparate(GL_FRONT, m_stencilMask);
-}
-
 void WebGLRenderingContextBase::restoreColorMask() {
   if (isContextLost())
     return;
@@ -1447,24 +1430,6 @@
                          m_colorMask[3]);
 }
 
-void WebGLRenderingContextBase::restoreDepthMask() {
-  if (isContextLost())
-    return;
-
-  contextGL()->DepthMask(m_depthMask);
-}
-
-void WebGLRenderingContextBase::restoreStateAfterClear() {
-  // Restore clear-related state items back to what the context had set.
-  restoreScissorEnabled();
-  restoreClearColor();
-  restoreColorMask();
-  restoreClearDepthf();
-  restoreClearStencil();
-  restoreStencilMaskSeparate();
-  restoreDepthMask();
-}
-
 void WebGLRenderingContextBase::markLayerComposited() {
   if (!isContextLost())
     drawingBuffer()->setBufferClearNeeded(true);
@@ -1500,7 +1465,7 @@
   ScopedTexture2DRestorer restorer(this);
   ScopedFramebufferRestorer fboRestorer(this);
 
-  drawingBuffer()->commit();
+  drawingBuffer()->resolveAndBindForReadAndDraw();
   if (!canvas()->buffer()->copyRenderingResultsFromDrawingBuffer(
           drawingBuffer(), sourceBuffer)) {
     // Currently, copyRenderingResultsFromDrawingBuffer is expected to always
@@ -1522,7 +1487,7 @@
     return nullptr;
 
   clearIfComposited();
-  drawingBuffer()->commit();
+  drawingBuffer()->resolveAndBindForReadAndDraw();
   ScopedFramebufferRestorer restorer(this);
   int width, height;
   WTF::ArrayBufferContents contents;
@@ -1570,17 +1535,7 @@
 
   // We don't have to mark the canvas as dirty, since the newly created image
   // buffer will also start off clear (and this matches what reshape will do).
-  drawingBuffer()->reset(IntSize(width, height));
-  restoreStateAfterClear();
-
-  contextGL()->BindTexture(
-      GL_TEXTURE_2D,
-      objectOrZero(
-          m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
-  contextGL()->BindRenderbuffer(GL_RENDERBUFFER,
-                                objectOrZero(m_renderbufferBinding.get()));
-  drawingBuffer()->restoreFramebufferBindings();
-  drawingBuffer()->restorePixelUnpackBufferBindings();
+  drawingBuffer()->resize(IntSize(width, height));
 }
 
 int WebGLRenderingContextBase::drawingBufferWidth() const {
@@ -1601,8 +1556,6 @@
   }
   m_activeTextureUnit = texture - GL_TEXTURE0;
   contextGL()->ActiveTexture(texture);
-
-  drawingBuffer()->setActiveTextureUnit(texture);
 }
 
 void WebGLRenderingContextBase::attachShader(WebGLProgram* program,
@@ -1694,10 +1647,6 @@
   }
   if (!validateAndUpdateBufferBindTarget("bindBuffer", target, buffer))
     return;
-
-  if (target == GL_PIXEL_UNPACK_BUFFER) {
-    drawingBuffer()->setPixelUnpackBufferBinding(objectOrZero(buffer));
-  }
   contextGL()->BindBuffer(target, objectOrZero(buffer));
 }
 
@@ -1737,9 +1686,6 @@
   }
   m_renderbufferBinding = renderBuffer;
   contextGL()->BindRenderbuffer(target, objectOrZero(renderBuffer));
-
-  drawingBuffer()->setRenderbufferBinding(objectOrZero(renderBuffer));
-
   if (renderBuffer)
     renderBuffer->setHasEverBeenBound();
 }
@@ -1763,9 +1709,6 @@
   if (target == GL_TEXTURE_2D) {
     m_textureUnits[m_activeTextureUnit].m_texture2DBinding =
         TraceWrapperMember<WebGLTexture>(this, texture);
-
-    if (!m_activeTextureUnit)
-      drawingBuffer()->setTexture2DBinding(objectOrZero(texture));
   } else if (target == GL_TEXTURE_CUBE_MAP) {
     m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding =
         TraceWrapperMember<WebGLTexture>(this, texture);
@@ -2030,7 +1973,6 @@
   m_clearColor[1] = g;
   m_clearColor[2] = b;
   m_clearColor[3] = a;
-  drawingBuffer()->setClearColor(m_clearColor);
   contextGL()->ClearColor(r, g, b, a);
 }
 
@@ -2058,7 +2000,6 @@
   m_colorMask[1] = green;
   m_colorMask[2] = blue;
   m_colorMask[3] = alpha;
-  drawingBuffer()->setColorMask(m_colorMask);
   contextGL()->ColorMask(red, green, blue, alpha);
 }
 
@@ -2269,10 +2210,8 @@
 }
 
 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer) {
-  GLuint bufferName = objectOrZero(buffer);
   if (!deleteObject(buffer))
     return;
-  drawingBuffer()->notifyBufferDeleted(bufferName);
   removeBoundBuffer(buffer);
 }
 
@@ -2282,7 +2221,6 @@
     return;
   if (framebuffer == m_framebufferBinding) {
     m_framebufferBinding = nullptr;
-    drawingBuffer()->setFramebufferBinding(GL_FRAMEBUFFER, 0);
     // Have to call drawingBuffer()->bind() here to bind back to internal fbo.
     drawingBuffer()->bind(GL_FRAMEBUFFER);
   }
@@ -2300,7 +2238,6 @@
     return;
   if (renderbuffer == m_renderbufferBinding) {
     m_renderbufferBinding = nullptr;
-    drawingBuffer()->setRenderbufferBinding(0);
   }
   if (m_framebufferBinding)
     m_framebufferBinding->removeAttachmentFromBoundFramebuffer(GL_FRAMEBUFFER,
@@ -2324,8 +2261,6 @@
     if (texture == m_textureUnits[i].m_texture2DBinding) {
       m_textureUnits[i].m_texture2DBinding = nullptr;
       maxBoundTextureIndex = i;
-      if (!i)
-        drawingBuffer()->setTexture2DBinding(0);
     }
     if (texture == m_textureUnits[i].m_textureCubeMapBinding) {
       m_textureUnits[i].m_textureCubeMapBinding = nullptr;
@@ -2403,10 +2338,8 @@
     applyStencilTest();
     return;
   }
-  if (cap == GL_SCISSOR_TEST) {
+  if (cap == GL_SCISSOR_TEST)
     m_scissorEnabled = false;
-    drawingBuffer()->setScissorEnabled(m_scissorEnabled);
-  }
   contextGL()->Disable(cap);
 }
 
@@ -2542,10 +2475,8 @@
     applyStencilTest();
     return;
   }
-  if (cap == GL_SCISSOR_TEST) {
+  if (cap == GL_SCISSOR_TEST)
     m_scissorEnabled = true;
-    drawingBuffer()->setScissorEnabled(m_scissorEnabled);
-  }
   contextGL()->Enable(cap);
 }
 
@@ -3946,7 +3877,6 @@
       if (param == 1 || param == 2 || param == 4 || param == 8) {
         if (pname == GL_PACK_ALIGNMENT) {
           m_packAlignment = param;
-          drawingBuffer()->setPackAlignment(param);
         } else {  // GL_UNPACK_ALIGNMENT:
           m_unpackAlignment = param;
         }
@@ -5965,12 +5895,6 @@
   ASSERT(m_contextLostMode != NotLostContext);
   m_autoRecoveryMethod = autoRecoveryMethod;
 
-  // Make absolutely sure we do not refer to an already-deleted texture or
-  // framebuffer.
-  drawingBuffer()->setTexture2DBinding(0);
-  drawingBuffer()->setFramebufferBinding(GL_FRAMEBUFFER, 0);
-  drawingBuffer()->setRenderbufferBinding(0);
-
   detachAndRemoveAllObjects();
 
   // Lose all the extensions.
@@ -6127,6 +6051,62 @@
   }
 }
 
+bool WebGLRenderingContextBase::DrawingBufferClientIsBoundForDraw() {
+  return !m_framebufferBinding;
+}
+
+void WebGLRenderingContextBase::DrawingBufferClientRestoreScissorTest() {
+  if (!contextGL())
+    return;
+  if (m_scissorEnabled)
+    contextGL()->Enable(GL_SCISSOR_TEST);
+  else
+    contextGL()->Disable(GL_SCISSOR_TEST);
+}
+
+void WebGLRenderingContextBase::DrawingBufferClientRestoreMaskAndClearValues() {
+  if (!contextGL())
+    return;
+  contextGL()->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2],
+                         m_colorMask[3]);
+  contextGL()->DepthMask(m_depthMask);
+  contextGL()->StencilMaskSeparate(GL_FRONT, m_stencilMask);
+
+  contextGL()->ClearColor(m_clearColor[0], m_clearColor[1], m_clearColor[2],
+                          m_clearColor[3]);
+  contextGL()->ClearDepthf(m_clearDepth);
+  contextGL()->ClearStencil(m_clearStencil);
+}
+
+void WebGLRenderingContextBase::DrawingBufferClientRestorePixelPackAlignment() {
+  if (!contextGL())
+    return;
+  contextGL()->PixelStorei(GL_PACK_ALIGNMENT, m_packAlignment);
+}
+
+void WebGLRenderingContextBase::DrawingBufferClientRestoreTexture2DBinding() {
+  if (!contextGL())
+    return;
+  restoreCurrentTexture2D();
+}
+
+void WebGLRenderingContextBase::
+    DrawingBufferClientRestoreRenderbufferBinding() {
+  if (!contextGL())
+    return;
+  contextGL()->BindRenderbuffer(GL_RENDERBUFFER,
+                                objectOrZero(m_renderbufferBinding.get()));
+}
+
+void WebGLRenderingContextBase::DrawingBufferClientRestoreFramebufferBinding() {
+  if (!contextGL())
+    return;
+  restoreCurrentFramebuffer();
+}
+
+void WebGLRenderingContextBase::
+    DrawingBufferClientRestorePixelUnpackBufferBinding() {}
+
 ScriptValue WebGLRenderingContextBase::getBooleanParameter(
     ScriptState* scriptState,
     GLenum pname) {
@@ -7420,9 +7400,6 @@
     m_framebufferBinding = buffer;
     applyStencilTest();
   }
-  drawingBuffer()->setFramebufferBinding(
-      target, objectOrZero(getFramebufferBinding(target)));
-
   if (!buffer) {
     // Instead of binding fb 0, bind the drawing buffer.
     drawingBuffer()->bind(target);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index d7d4b251..c45c91b 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -133,7 +133,8 @@
   const bool m_requiresEmulation;
 };
 
-class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext {
+class MODULES_EXPORT WebGLRenderingContextBase : public CanvasRenderingContext,
+                                                 public DrawingBuffer::Client {
   WTF_MAKE_NONCOPYABLE(WebGLRenderingContextBase);
 
  public:
@@ -546,11 +547,7 @@
   void restoreScissorEnabled();
   void restoreScissorBox();
   void restoreClearColor();
-  void restoreClearDepthf();
-  void restoreClearStencil();
-  void restoreStencilMaskSeparate();
   void restoreColorMask();
-  void restoreDepthMask();
 
   gpu::gles2::GLES2Interface* contextGL() const {
     DrawingBuffer* d = drawingBuffer();
@@ -622,6 +619,7 @@
   friend class WebGLCompressedTextureS3TCsRGB;
   friend class WebGLRenderingContextErrorMessageCallback;
   friend class WebGLVertexArrayObjectBase;
+  friend class ScopedDrawingBufferBinder;
   friend class ScopedTexture2DRestorer;
   friend class ScopedFramebufferRestorer;
   // To allow V8WebGL[2]RenderingContext to call visitChildDOMWrappers.
@@ -648,6 +646,16 @@
   WebLayer* platformLayer() const override;
   void stop() override;
 
+  // DrawingBuffer::Client implementation.
+  bool DrawingBufferClientIsBoundForDraw() override;
+  void DrawingBufferClientRestoreScissorTest() override;
+  void DrawingBufferClientRestoreMaskAndClearValues() override;
+  void DrawingBufferClientRestorePixelPackAlignment() override;
+  void DrawingBufferClientRestoreTexture2DBinding() override;
+  void DrawingBufferClientRestoreRenderbufferBinding() override;
+  void DrawingBufferClientRestoreFramebufferBinding() override;
+  void DrawingBufferClientRestorePixelUnpackBufferBinding() override;
+
   void addSharedObject(WebGLSharedObject*);
   void addContextObject(WebGLContextObject*);
   void detachAndRemoveAllObjects();
@@ -918,7 +926,7 @@
           m_readFramebufferBinding(framebufferBinding) {
       // Commit DrawingBuffer if needed (e.g., for multisampling)
       if (!m_readFramebufferBinding && m_drawingBuffer)
-        m_drawingBuffer->commit();
+        m_drawingBuffer->resolveAndBindForReadAndDraw();
     }
 
     ~ScopedDrawingBufferBinder() {
@@ -978,9 +986,6 @@
   };
   HowToClear clearIfComposited(GLbitfield clearMask = 0);
 
-  // Helper to restore state that clearing the framebuffer may destroy.
-  void restoreStateAfterClear();
-
   // Convert texture internal format.
   GLenum convertTexInternalFormat(GLenum internalformat, GLenum type);
 
diff --git a/third_party/WebKit/Source/modules/webmidi/BUILD.gn b/third_party/WebKit/Source/modules/webmidi/BUILD.gn
index 88893b3..b762380 100644
--- a/third_party/WebKit/Source/modules/webmidi/BUILD.gn
+++ b/third_party/WebKit/Source/modules/webmidi/BUILD.gn
@@ -31,4 +31,8 @@
     "NavigatorWebMIDI.cpp",
     "NavigatorWebMIDI.h",
   ]
+
+  deps = [
+    "//media/midi:mojo_blink_cpp_sources",
+  ]
 }
diff --git a/third_party/WebKit/Source/modules/webmidi/DEPS b/third_party/WebKit/Source/modules/webmidi/DEPS
index d9525ab..15977bd 100644
--- a/third_party/WebKit/Source/modules/webmidi/DEPS
+++ b/third_party/WebKit/Source/modules/webmidi/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
     "+bindings",
     "+core",
+    "+media/midi/midi_service.mojom-blink.h",
     "-modules",
     "+modules/EventModules.h",
     "+modules/EventTargetModules.h",
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccess.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIAccess.cpp
index 53fad60..df7fddf 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccess.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccess.cpp
@@ -45,7 +45,7 @@
 
 namespace blink {
 
-using PortState = MIDIAccessor::MIDIPortState;
+using midi::mojom::PortState;
 
 MIDIAccess::MIDIAccess(
     std::unique_ptr<MIDIAccessor> accessor,
@@ -97,7 +97,7 @@
   HashSet<String> ids;
   for (size_t i = 0; i < m_inputs.size(); ++i) {
     MIDIInput* input = m_inputs[i];
-    if (input->getState() != PortState::MIDIPortStateDisconnected) {
+    if (input->getState() != PortState::DISCONNECTED) {
       inputs.append(input);
       ids.add(input->id());
     }
@@ -114,7 +114,7 @@
   HashSet<String> ids;
   for (size_t i = 0; i < m_outputs.size(); ++i) {
     MIDIOutput* output = m_outputs[i];
-    if (output->getState() != PortState::MIDIPortStateDisconnected) {
+    if (output->getState() != PortState::DISCONNECTED) {
       outputs.append(output);
       ids.add(output->id());
     }
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccess.h b/third_party/WebKit/Source/modules/webmidi/MIDIAccess.h
index a8319f85..32b81a7 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccess.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccess.h
@@ -34,6 +34,7 @@
 #include "bindings/core/v8/ActiveScriptWrappable.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "core/dom/ActiveDOMObject.h"
+#include "media/midi/midi_service.mojom-blink.h"
 #include "modules/EventTargetModules.h"
 #include "modules/webmidi/MIDIAccessInitializer.h"
 #include "modules/webmidi/MIDIAccessor.h"
@@ -98,16 +99,16 @@
                        const String& manufacturer,
                        const String& name,
                        const String& version,
-                       MIDIAccessor::MIDIPortState) override;
+                       midi::mojom::PortState) override;
   void didAddOutputPort(const String& id,
                         const String& manufacturer,
                         const String& name,
                         const String& version,
-                        MIDIAccessor::MIDIPortState) override;
+                        midi::mojom::PortState) override;
   void didSetInputPortState(unsigned portIndex,
-                            MIDIAccessor::MIDIPortState) override;
+                            midi::mojom::PortState) override;
   void didSetOutputPortState(unsigned portIndex,
-                             MIDIAccessor::MIDIPortState) override;
+                             midi::mojom::PortState) override;
   void didStartSession(midi::mojom::Result) override {
     // This method is for MIDIAccess initialization: MIDIAccessInitializer
     // has the implementation.
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp
index 849878f..cb81adc 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.cpp
@@ -22,8 +22,7 @@
 
 namespace blink {
 
-using PortState = WebMIDIAccessorClient::MIDIPortState;
-
+using midi::mojom::PortState;
 using midi::mojom::Result;
 using mojom::blink::PermissionStatus;
 
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.h b/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.h
index 09a95e88..6641e36 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccessInitializer.h
@@ -7,6 +7,7 @@
 
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "media/midi/midi_service.mojom-blink.h"
 #include "modules/ModulesExport.h"
 #include "modules/webmidi/MIDIAccessor.h"
 #include "modules/webmidi/MIDIAccessorClient.h"
@@ -31,14 +32,14 @@
     String name;
     MIDIPort::TypeCode type;
     String version;
-    MIDIAccessor::MIDIPortState state;
+    midi::mojom::PortState state;
 
     PortDescriptor(const String& id,
                    const String& manufacturer,
                    const String& name,
                    MIDIPort::TypeCode type,
                    const String& version,
-                   MIDIAccessor::MIDIPortState state)
+                   midi::mojom::PortState state)
         : id(id),
           manufacturer(manufacturer),
           name(name),
@@ -67,16 +68,16 @@
                        const String& manufacturer,
                        const String& name,
                        const String& version,
-                       MIDIAccessor::MIDIPortState) override;
+                       midi::mojom::PortState) override;
   void didAddOutputPort(const String& id,
                         const String& manufacturer,
                         const String& name,
                         const String& version,
-                        MIDIAccessor::MIDIPortState) override;
+                        midi::mojom::PortState) override;
   void didSetInputPortState(unsigned portIndex,
-                            MIDIAccessor::MIDIPortState) override;
+                            midi::mojom::PortState) override;
   void didSetOutputPortState(unsigned portIndex,
-                             MIDIAccessor::MIDIPortState) override;
+                             midi::mojom::PortState) override;
   void didStartSession(midi::mojom::Result) override;
   void didReceiveMIDIData(unsigned portIndex,
                           const unsigned char* data,
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.cpp
index 851dc5ab..1499e52 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.cpp
@@ -37,6 +37,7 @@
 #include <memory>
 
 using blink::WebString;
+using midi::mojom::PortState;
 using midi::mojom::Result;
 
 namespace blink {
@@ -69,7 +70,7 @@
                                    const WebString& manufacturer,
                                    const WebString& name,
                                    const WebString& version,
-                                   MIDIPortState state) {
+                                   PortState state) {
   m_client->didAddInputPort(id, manufacturer, name, version, state);
 }
 
@@ -77,17 +78,15 @@
                                     const WebString& manufacturer,
                                     const WebString& name,
                                     const WebString& version,
-                                    MIDIPortState state) {
+                                    PortState state) {
   m_client->didAddOutputPort(id, manufacturer, name, version, state);
 }
 
-void MIDIAccessor::didSetInputPortState(unsigned portIndex,
-                                        MIDIPortState state) {
+void MIDIAccessor::didSetInputPortState(unsigned portIndex, PortState state) {
   m_client->didSetInputPortState(portIndex, state);
 }
 
-void MIDIAccessor::didSetOutputPortState(unsigned portIndex,
-                                         MIDIPortState state) {
+void MIDIAccessor::didSetOutputPortState(unsigned portIndex, PortState state) {
   m_client->didSetOutputPortState(portIndex, state);
 }
 
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.h b/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.h
index c23ff5ad..5fa679a 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccessor.h
@@ -31,6 +31,7 @@
 #ifndef MIDIAccessor_h
 #define MIDIAccessor_h
 
+#include "media/midi/midi_service.mojom-blink.h"
 #include "public/platform/modules/webmidi/WebMIDIAccessor.h"
 #include "public/platform/modules/webmidi/WebMIDIAccessorClient.h"
 #include "wtf/Allocator.h"
@@ -63,14 +64,16 @@
                        const WebString& manufacturer,
                        const WebString& name,
                        const WebString& version,
-                       MIDIPortState) override;
+                       midi::mojom::PortState) override;
   void didAddOutputPort(const WebString& id,
                         const WebString& manufacturer,
                         const WebString& name,
                         const WebString& version,
-                        MIDIPortState) override;
-  void didSetInputPortState(unsigned portIndex, MIDIPortState) override;
-  void didSetOutputPortState(unsigned portIndex, MIDIPortState) override;
+                        midi::mojom::PortState) override;
+  void didSetInputPortState(unsigned portIndex,
+                            midi::mojom::PortState) override;
+  void didSetOutputPortState(unsigned portIndex,
+                             midi::mojom::PortState) override;
   void didStartSession(midi::mojom::Result) override;
   void didReceiveMIDIData(unsigned portIndex,
                           const unsigned char* data,
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIAccessorClient.h b/third_party/WebKit/Source/modules/webmidi/MIDIAccessorClient.h
index 5aea85f2..6dc017c 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIAccessorClient.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIAccessorClient.h
@@ -31,6 +31,7 @@
 #ifndef MIDIAccessorClient_h
 #define MIDIAccessorClient_h
 
+#include "media/midi/midi_service.mojom-blink.h"
 #include "modules/webmidi/MIDIAccessor.h"
 #include "wtf/Forward.h"
 
@@ -42,16 +43,16 @@
                                const String& manufacturer,
                                const String& name,
                                const String& version,
-                               MIDIAccessor::MIDIPortState) = 0;
+                               midi::mojom::PortState) = 0;
   virtual void didAddOutputPort(const String& id,
                                 const String& manufacturer,
                                 const String& name,
                                 const String& version,
-                                MIDIAccessor::MIDIPortState) = 0;
+                                midi::mojom::PortState) = 0;
   virtual void didSetInputPortState(unsigned portIndex,
-                                    MIDIAccessor::MIDIPortState) = 0;
+                                    midi::mojom::PortState) = 0;
   virtual void didSetOutputPortState(unsigned portIndex,
-                                     MIDIAccessor::MIDIPortState) = 0;
+                                     midi::mojom::PortState) = 0;
 
   virtual void didStartSession(midi::mojom::Result) = 0;
   virtual void didReceiveMIDIData(unsigned portIndex,
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIInput.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIInput.cpp
index 1414fe7d..ba94909 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIInput.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIInput.cpp
@@ -36,7 +36,7 @@
 
 namespace blink {
 
-using PortState = MIDIAccessor::MIDIPortState;
+using midi::mojom::PortState;
 
 MIDIInput* MIDIInput::create(MIDIAccess* access,
                              const String& id,
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIInput.h b/third_party/WebKit/Source/modules/webmidi/MIDIInput.h
index aca3960..2d2e713 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIInput.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIInput.h
@@ -31,6 +31,7 @@
 #ifndef MIDIInput_h
 #define MIDIInput_h
 
+#include "media/midi/midi_service.mojom-blink.h"
 #include "modules/EventTargetModules.h"
 #include "modules/webmidi/MIDIAccessor.h"
 #include "modules/webmidi/MIDIPort.h"
@@ -48,7 +49,7 @@
                            const String& manufacturer,
                            const String& name,
                            const String& version,
-                           MIDIAccessor::MIDIPortState);
+                           midi::mojom::PortState);
   ~MIDIInput() override {}
 
   EventListener* onmidimessage();
@@ -78,7 +79,7 @@
             const String& manufacturer,
             const String& name,
             const String& version,
-            MIDIAccessor::MIDIPortState);
+            midi::mojom::PortState);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIOutput.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIOutput.cpp
index 73103df..21402a9ef 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIOutput.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIOutput.cpp
@@ -36,11 +36,12 @@
 #include "core/frame/LocalDOMWindow.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
+#include "media/midi/midi_service.mojom-blink.h"
 #include "modules/webmidi/MIDIAccess.h"
 
-namespace blink {
+using midi::mojom::PortState;
 
-using PortState = MIDIAccessor::MIDIPortState;
+namespace blink {
 
 namespace {
 
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIOutput.h b/third_party/WebKit/Source/modules/webmidi/MIDIOutput.h
index 6f659635..ac92865c 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIOutput.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIOutput.h
@@ -49,7 +49,7 @@
                             const String& manufacturer,
                             const String& name,
                             const String& version,
-                            MIDIAccessor::MIDIPortState);
+                            midi::mojom::PortState);
   ~MIDIOutput() override;
 
   void send(DOMUint8Array*, double timestamp, ExceptionState&);
@@ -68,7 +68,7 @@
              const String& manufacturer,
              const String& name,
              const String& version,
-             MIDIAccessor::MIDIPortState);
+             midi::mojom::PortState);
 
   unsigned m_portIndex;
 };
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIPort.cpp b/third_party/WebKit/Source/modules/webmidi/MIDIPort.cpp
index 4d9ca45e..9d9e90cdf 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIPort.cpp
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIPort.cpp
@@ -35,9 +35,9 @@
 #include "modules/webmidi/MIDIAccess.h"
 #include "modules/webmidi/MIDIConnectionEvent.h"
 
-namespace blink {
+using midi::mojom::PortState;
 
-using PortState = MIDIAccessor::MIDIPortState;
+namespace blink {
 
 MIDIPort::MIDIPort(MIDIAccess* access,
                    const String& id,
@@ -57,8 +57,7 @@
       m_connection(ConnectionStateClosed) {
   DCHECK(access);
   DCHECK(type == TypeInput || type == TypeOutput);
-  DCHECK(state == PortState::MIDIPortStateDisconnected ||
-         state == PortState::MIDIPortStateConnected);
+  DCHECK(state == PortState::DISCONNECTED || state == PortState::CONNECTED);
   m_state = state;
 }
 
@@ -76,9 +75,12 @@
 
 String MIDIPort::state() const {
   switch (m_state) {
-    case PortState::MIDIPortStateDisconnected:
+    case PortState::DISCONNECTED:
       return "disconnected";
-    case PortState::MIDIPortStateConnected:
+    case PortState::CONNECTED:
+      return "connected";
+    case PortState::OPENED:
+      NOTREACHED();
       return "connected";
   }
   return emptyString();
@@ -110,21 +112,19 @@
 
 void MIDIPort::setState(PortState state) {
   switch (state) {
-    case PortState::MIDIPortStateDisconnected:
+    case PortState::DISCONNECTED:
       switch (m_connection) {
         case ConnectionStateOpen:
         case ConnectionStatePending:
-          setStates(PortState::MIDIPortStateDisconnected,
-                    ConnectionStatePending);
+          setStates(PortState::DISCONNECTED, ConnectionStatePending);
           break;
         case ConnectionStateClosed:
           // Will do nothing.
-          setStates(PortState::MIDIPortStateDisconnected,
-                    ConnectionStateClosed);
+          setStates(PortState::DISCONNECTED, ConnectionStateClosed);
           break;
       }
       break;
-    case PortState::MIDIPortStateConnected:
+    case PortState::CONNECTED:
       switch (m_connection) {
         case ConnectionStateOpen:
           NOTREACHED();
@@ -132,14 +132,17 @@
         case ConnectionStatePending:
           // We do not use |setStates| in order not to dispatch events twice.
           // |open| calls |setStates|.
-          m_state = PortState::MIDIPortStateConnected;
+          m_state = PortState::CONNECTED;
           open();
           break;
         case ConnectionStateClosed:
-          setStates(PortState::MIDIPortStateConnected, ConnectionStateClosed);
+          setStates(PortState::CONNECTED, ConnectionStateClosed);
           break;
       }
       break;
+    case PortState::OPENED:
+      NOTREACHED();
+      break;
   }
 }
 
@@ -170,14 +173,17 @@
 
 void MIDIPort::open() {
   switch (m_state) {
-    case PortState::MIDIPortStateDisconnected:
+    case PortState::DISCONNECTED:
       setStates(m_state, ConnectionStatePending);
       break;
-    case PortState::MIDIPortStateConnected:
+    case PortState::CONNECTED:
       // TODO(toyoshim): Add blink API to perform a real open and close
       // operation.
       setStates(m_state, ConnectionStateOpen);
       break;
+    case PortState::OPENED:
+      NOTREACHED();
+      break;
   }
 }
 
@@ -195,8 +201,7 @@
 }
 
 void MIDIPort::setStates(PortState state, ConnectionState connection) {
-  DCHECK(state != PortState::MIDIPortStateDisconnected ||
-         connection != ConnectionStateOpen);
+  DCHECK(state != PortState::DISCONNECTED || connection != ConnectionStateOpen);
   if (m_state == state && m_connection == connection)
     return;
   m_state = state;
diff --git a/third_party/WebKit/Source/modules/webmidi/MIDIPort.h b/third_party/WebKit/Source/modules/webmidi/MIDIPort.h
index 6059368..2a5f0dc 100644
--- a/third_party/WebKit/Source/modules/webmidi/MIDIPort.h
+++ b/third_party/WebKit/Source/modules/webmidi/MIDIPort.h
@@ -35,6 +35,7 @@
 #include "bindings/core/v8/ScriptPromise.h"
 #include "core/dom/ActiveDOMObject.h"
 #include "core/dom/ExceptionCode.h"
+#include "media/midi/midi_service.mojom-blink.h"
 #include "modules/EventTargetModules.h"
 #include "modules/webmidi/MIDIAccessor.h"
 #include "platform/heap/Handle.h"
@@ -72,8 +73,8 @@
   ScriptPromise close(ScriptState*);
 
   MIDIAccess* midiAccess() const { return m_access; }
-  MIDIAccessor::MIDIPortState getState() const { return m_state; }
-  void setState(MIDIAccessor::MIDIPortState);
+  midi::mojom::PortState getState() const { return m_state; }
+  void setState(midi::mojom::PortState);
   ConnectionState getConnection() const { return m_connection; }
 
   DECLARE_VIRTUAL_TRACE();
@@ -101,7 +102,7 @@
            const String& name,
            TypeCode,
            const String& version,
-           MIDIAccessor::MIDIPortState);
+           midi::mojom::PortState);
 
   void open();
 
@@ -109,7 +110,7 @@
   ScriptPromise accept(ScriptState*);
   ScriptPromise reject(ScriptState*, ExceptionCode, const String& message);
 
-  void setStates(MIDIAccessor::MIDIPortState, ConnectionState);
+  void setStates(midi::mojom::PortState, ConnectionState);
 
   String m_id;
   String m_manufacturer;
@@ -117,7 +118,7 @@
   TypeCode m_type;
   String m_version;
   Member<MIDIAccess> m_access;
-  MIDIAccessor::MIDIPortState m_state;
+  midi::mojom::PortState m_state;
   ConnectionState m_connection;
 };
 
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 2790eae..905f5a9 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -167,7 +167,7 @@
 PassiveEventListenersDueToFling status=experimental
 PassPaintVisualRectToCompositor
 PaymentRequest status=experimental
-PaymentRequestPayerName status=experimental
+PaymentRequestPayerName status=stable
 PerformanceObserver status=stable
 PermissionDelegation status=test
 Permissions status=stable
@@ -176,7 +176,7 @@
 // For temporary compat testing of Edge-like model - crbug.com/640700
 PointerEventV1SpecCapturing
 PreciseMemoryInfo
-PreferredImageRasterScale settable_from_internals=True
+PreferredImageRasterBounds settable_from_internals=True
 // This feature is deprecated and we are evangelizing affected sites.
 // See https://crbug.com/346236 for current status.
 PrefixedVideoFullscreen status=stable
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.cpp b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
index 7a24d76..2844a92 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
@@ -98,6 +98,21 @@
   return &globalFontCache;
 }
 
+#if !OS(MACOSX)
+FontPlatformData* FontCache::systemFontPlatformData(
+    const FontDescription& fontDescription) {
+  const AtomicString& family = FontCache::systemFontFamily();
+#if OS(LINUX)
+  if (family.isEmpty() || family == FontFamilyNames::system_ui)
+    return nullptr;
+#else
+  DCHECK(!family.isEmpty() && family != FontFamilyNames::system_ui);
+#endif
+  return getFontPlatformData(fontDescription, FontFaceCreationParams(family),
+                             true);
+}
+#endif
+
 FontPlatformData* FontCache::getFontPlatformData(
     const FontDescription& fontDescription,
     const FontFaceCreationParams& creationParams,
@@ -107,28 +122,12 @@
     platformInit();
   }
 
-  if (creationParams.creationType() == CreateFontByFamily) {
-#if OS(MACOSX)
-    if (creationParams.family() == FontCache::legacySystemFontFamily()) {
-      return getFontPlatformData(
-          fontDescription, FontFaceCreationParams(FontFamilyNames::system_ui),
-          true);
-    }
-#else
-    if (creationParams.family() == FontFamilyNames::system_ui) {
-      const AtomicString& actualFamily = FontCache::systemFontFamily();
-#if OS(LINUX)
-      if (actualFamily.isEmpty() || actualFamily == FontFamilyNames::system_ui)
-        return nullptr;
-#else
-      DCHECK(!actualFamily.isEmpty() &&
-             actualFamily != FontFamilyNames::system_ui);
-#endif
-      return getFontPlatformData(fontDescription,
-                                 FontFaceCreationParams(actualFamily), true);
-    }
-#endif
+#if !OS(MACOSX)
+  if (creationParams.creationType() == CreateFontByFamily &&
+      creationParams.family() == FontFamilyNames::system_ui) {
+    return systemFontPlatformData(fontDescription);
   }
+#endif
 
   float size = fontDescription.effectiveFontSize();
   unsigned roundedSize = size * FontCacheKey::precisionMultiplier();
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.h b/third_party/WebKit/Source/platform/fonts/FontCache.h
index e984c6fd..60d11785 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.h
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.h
@@ -210,6 +210,9 @@
   FontPlatformData* getFontPlatformData(const FontDescription&,
                                         const FontFaceCreationParams&,
                                         bool checkingAlternateName = false);
+#if !OS(MACOSX)
+  FontPlatformData* systemFontPlatformData(const FontDescription&);
+#endif
 
   // These methods are implemented by each platform.
   std::unique_ptr<FontPlatformData> createFontPlatformData(
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 7fe49b03..d7de310 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -110,8 +110,7 @@
       m_contentsLayerId(0),
       m_scrollableArea(nullptr),
       m_renderingContext3d(0),
-      m_preferredRasterScale(1.0f),
-      m_hasPreferredRasterScale(false) {
+      m_hasPreferredRasterBounds(false) {
 #if ENABLE(ASSERT)
   if (m_client)
     m_client->verifyNotPainting();
@@ -151,16 +150,16 @@
   m_layer->layer()->setHasWillChangeTransformHint(hasWillChangeTransform);
 }
 
-void GraphicsLayer::setPreferredRasterScale(float preferredRasterScale) {
-  m_preferredRasterScale = preferredRasterScale;
-  m_hasPreferredRasterScale = true;
-  m_layer->layer()->setPreferredRasterScale(preferredRasterScale);
+void GraphicsLayer::setPreferredRasterBounds(const IntSize& bounds) {
+  m_preferredRasterBounds = bounds;
+  m_hasPreferredRasterBounds = true;
+  m_layer->layer()->setPreferredRasterBounds(bounds);
 }
 
-void GraphicsLayer::clearPreferredRasterScale() {
-  m_preferredRasterScale = 1.0f;
-  m_hasPreferredRasterScale = false;
-  m_layer->layer()->clearPreferredRasterScale();
+void GraphicsLayer::clearPreferredRasterBounds() {
+  m_preferredRasterBounds = IntSize();
+  m_hasPreferredRasterBounds = false;
+  m_layer->layer()->clearPreferredRasterBounds();
 }
 
 void GraphicsLayer::setParent(GraphicsLayer* layer) {
@@ -687,8 +686,10 @@
     json->setString("backfaceVisibility",
                     m_backfaceVisibility ? "visible" : "hidden");
 
-  if (m_hasPreferredRasterScale)
-    json->setDouble("preferredRasterScale", m_preferredRasterScale);
+  if (m_hasPreferredRasterBounds) {
+    json->setArray("preferredRasterBounds",
+                   sizeAsJSONArray(m_preferredRasterBounds));
+  }
 
   if (flags & LayerTreeIncludesDebugInfo)
     json->setString("client", pointerAsString(m_client));
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
index a0dcd7a..b5b2165 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -278,8 +278,9 @@
 
   void setHasWillChangeTransformHint(bool);
 
-  void setPreferredRasterScale(float);
-  void clearPreferredRasterScale();
+  // See comments in cc::Layer::SetPreferredRasterBounds.
+  void setPreferredRasterBounds(const IntSize&);
+  void clearPreferredRasterBounds();
 
  protected:
   String debugName(cc::Layer*) const;
@@ -398,8 +399,8 @@
   std::unique_ptr<PaintController> m_paintController;
 
   IntRect m_previousInterestRect;
-  float m_preferredRasterScale;
-  bool m_hasPreferredRasterScale;
+  IntSize m_preferredRasterBounds;
+  bool m_hasPreferredRasterBounds;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
index 0f9a35d..84c5cc7b 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -59,36 +59,13 @@
 
 const float s_resourceAdjustedRatio = 0.5;
 
-class ScopedTextureUnit0BindingRestorer {
-  STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(ScopedTextureUnit0BindingRestorer);
-
- public:
-  ScopedTextureUnit0BindingRestorer(gpu::gles2::GLES2Interface* gl,
-                                    GLenum activeTextureUnit,
-                                    GLuint textureUnitZeroId)
-      : m_gl(gl),
-        m_oldActiveTextureUnit(activeTextureUnit),
-        m_oldTextureUnitZeroId(textureUnitZeroId) {
-    m_gl->ActiveTexture(GL_TEXTURE0);
-  }
-  ~ScopedTextureUnit0BindingRestorer() {
-    m_gl->BindTexture(GL_TEXTURE_2D, m_oldTextureUnitZeroId);
-    m_gl->ActiveTexture(m_oldActiveTextureUnit);
-  }
-
- private:
-  gpu::gles2::GLES2Interface* m_gl;
-  GLenum m_oldActiveTextureUnit;
-  GLuint m_oldTextureUnitZeroId;
-};
-
 static bool shouldFailDrawingBufferCreationForTesting = false;
 
 }  // namespace
 
 PassRefPtr<DrawingBuffer> DrawingBuffer::create(
     std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
+    Client* client,
     const IntSize& size,
     bool premultipliedAlpha,
     bool wantAlphaChannel,
@@ -135,7 +112,7 @@
     extensionsUtil->ensureExtensionEnabled("GL_EXT_discard_framebuffer");
 
   RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(
-      std::move(contextProvider), std::move(extensionsUtil),
+      std::move(contextProvider), std::move(extensionsUtil), client,
       discardFramebufferSupported, wantAlphaChannel, premultipliedAlpha,
       preserve, webGLVersion, wantDepthBuffer, wantStencilBuffer,
       chromiumImageUsage));
@@ -153,6 +130,7 @@
 DrawingBuffer::DrawingBuffer(
     std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
     std::unique_ptr<Extensions3DUtil> extensionsUtil,
+    Client* client,
     bool discardFramebufferSupported,
     bool wantAlphaChannel,
     bool premultipliedAlpha,
@@ -161,7 +139,8 @@
     bool wantDepth,
     bool wantStencil,
     ChromiumImageUsage chromiumImageUsage)
-    : m_preserveDrawingBuffer(preserve),
+    : m_client(client),
+      m_preserveDrawingBuffer(preserve),
       m_webGLVersion(webGLVersion),
       m_contextProvider(std::move(contextProvider)),
       m_gl(m_contextProvider->contextGL()),
@@ -173,8 +152,6 @@
       m_wantDepth(wantDepth),
       m_wantStencil(wantStencil),
       m_chromiumImageUsage(chromiumImageUsage) {
-  memset(m_colorMask, 0, 4 * sizeof(GLboolean));
-  memset(m_clearColor, 0, 4 * sizeof(GLfloat));
   // Used by browser tests to detect the use of a DrawingBuffer.
   TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation",
                        TRACE_EVENT_SCOPE_GLOBAL);
@@ -228,7 +205,7 @@
 }
 
 bool DrawingBuffer::requiresAlphaChannelToBePreserved() {
-  return !m_drawFramebufferBinding &&
+  return m_client->DrawingBufferClientIsBoundForDraw() &&
          defaultBufferRequiresAlphaChannelToBePreserved();
 }
 
@@ -264,6 +241,7 @@
 bool DrawingBuffer::PrepareTextureMailbox(
     cc::TextureMailbox* outMailbox,
     std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback) {
+  ScopedStateRestorer scopedStateRestorer(this);
   bool forceGpuResult = false;
   return prepareTextureMailboxInternal(outMailbox, outReleaseCallback,
                                        forceGpuResult);
@@ -298,7 +276,7 @@
 
   // Resolve the multisampled buffer into m_backColorBuffer texture.
   if (m_antiAliasingMode != None)
-    commit();
+    resolveMultisampleFramebufferInternal();
 
   if (m_softwareRendering && !forceGpuResult) {
     return finishPrepareTextureMailboxSoftware(outMailbox, outReleaseCallback);
@@ -343,14 +321,10 @@
     cc::TextureMailbox* outMailbox,
     std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback) {
   if (m_webGLVersion > WebGL1) {
+    m_stateRestorer->setPixelUnpackBufferBindingDirty();
     m_gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
   }
 
-  // We must restore the texture binding since creating new textures,
-  // consuming and producing mailboxes changes it.
-  ScopedTextureUnit0BindingRestorer restorer(m_gl, m_activeTextureUnit,
-                                             m_texture2DBinding);
-
   // Specify the buffer that we will put in the mailbox.
   RefPtr<ColorBuffer> colorBufferForMailbox;
   if (m_preserveDrawingBuffer == Discard) {
@@ -366,6 +340,7 @@
     if (m_discardFramebufferSupported) {
       const GLenum attachments[3] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
                                      GL_STENCIL_ATTACHMENT};
+      m_stateRestorer->setFramebufferBindingDirty();
       m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
       m_gl->DiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments);
     }
@@ -413,9 +388,6 @@
   // Point |m_frontColorBuffer| to the buffer that we are now presenting.
   m_frontColorBuffer = colorBufferForMailbox;
 
-  // Restore any state that we may have dirtied, and update dirty bits.
-  restoreFramebufferBindings();
-  restorePixelUnpackBufferBindings();
   m_contentsChanged = false;
   setBufferClearNeeded(true);
   return true;
@@ -464,6 +436,8 @@
 }
 
 PassRefPtr<StaticBitmapImage> DrawingBuffer::transferToStaticBitmapImage() {
+  ScopedStateRestorer scopedStateRestorer(this);
+
   // This can be null if the context is lost before the first call to
   // grContext().
   GrContext* grContext = m_contextProvider->grContext();
@@ -617,18 +591,35 @@
 }
 
 DrawingBuffer::ColorBuffer::~ColorBuffer() {
-  gpu::gles2::GLES2Interface* gl = drawingBuffer->contextGL();
+  gpu::gles2::GLES2Interface* gl = drawingBuffer->m_gl;
   if (receiveSyncToken.HasData())
     gl->WaitSyncTokenCHROMIUM(receiveSyncToken.GetConstData());
   if (imageId) {
     gl->BindTexture(parameters.target, textureId);
     gl->ReleaseTexImage2DCHROMIUM(parameters.target, imageId);
     gl->DestroyImageCHROMIUM(imageId);
+    switch (parameters.target) {
+      case GL_TEXTURE_2D:
+        // Restore the texture binding for GL_TEXTURE_2D, since the client will
+        // expect the previous state.
+        if (drawingBuffer->m_client)
+          drawingBuffer->m_client->DrawingBufferClientRestoreTexture2DBinding();
+        break;
+      case GC3D_TEXTURE_RECTANGLE_ARB:
+        // Rectangle textures aren't exposed to WebGL, so don't bother
+        // restoring this state (there is no meaningful way to restore it).
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
   }
   gl->DeleteTextures(1, &textureId);
 }
 
 bool DrawingBuffer::initialize(const IntSize& size, bool useMultisampling) {
+  ScopedStateRestorer scopedStateRestorer(this);
+
   if (m_gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR) {
     // Need to try to restore the context again later.
     return false;
@@ -660,6 +651,7 @@
       m_antiAliasingMode == ScreenSpaceAntialiasing;
   m_sampleCount = std::min(4, maxSampleCount);
 
+  m_stateRestorer->setFramebufferBindingDirty();
   m_gl->GenFramebuffers(1, &m_fbo);
   m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
   if (wantExplicitResolve()) {
@@ -667,7 +659,7 @@
     m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
     m_gl->GenRenderbuffers(1, &m_multisampleRenderbuffer);
   }
-  if (!reset(size))
+  if (!resizeFramebufferInternal(size))
     return false;
 
   if (m_depthStencilBuffer) {
@@ -692,11 +684,11 @@
                                           bool premultiplyAlpha,
                                           bool flipY,
                                           SourceDrawingBuffer sourceBuffer) {
+  ScopedStateRestorer scopedStateRestorer(this);
+
   if (m_contentsChanged) {
-    if (m_antiAliasingMode != None) {
-      commit();
-      restoreFramebufferBindings();
-    }
+    if (m_antiAliasingMode != None)
+      resolveMultisampleFramebufferInternal();
     m_gl->Flush();
   }
 
@@ -752,10 +744,6 @@
   return true;
 }
 
-GLuint DrawingBuffer::framebuffer() const {
-  return m_fbo;
-}
-
 WebLayer* DrawingBuffer::platformLayer() {
   if (!m_layer) {
     m_layer =
@@ -809,6 +797,8 @@
 
   if (m_layer)
     GraphicsLayer::unregisterContentsLayer(m_layer->layer());
+
+  m_client = nullptr;
 }
 
 bool DrawingBuffer::resizeDefaultFramebuffer(const IntSize& size) {
@@ -818,6 +808,8 @@
   attachColorBufferToReadFramebuffer();
 
   if (wantExplicitResolve()) {
+    m_stateRestorer->setFramebufferBindingDirty();
+    m_stateRestorer->setRenderbufferBindingDirty();
     m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
     m_gl->BindRenderbuffer(GL_RENDERBUFFER, m_multisampleRenderbuffer);
     m_gl->RenderbufferStorageMultisampleCHROMIUM(
@@ -832,6 +824,8 @@
   }
 
   if (wantDepthOrStencil()) {
+    m_stateRestorer->setFramebufferBindingDirty();
+    m_stateRestorer->setRenderbufferBindingDirty();
     m_gl->BindFramebuffer(GL_FRAMEBUFFER,
                           m_multisampleFBO ? m_multisampleFBO : m_fbo);
     if (!m_depthStencilBuffer)
@@ -858,17 +852,25 @@
   }
 
   if (wantExplicitResolve()) {
+    m_stateRestorer->setFramebufferBindingDirty();
     m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
     if (m_gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
       return false;
   }
 
+  m_stateRestorer->setFramebufferBindingDirty();
   m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
   return m_gl->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
          GL_FRAMEBUFFER_COMPLETE;
 }
 
 void DrawingBuffer::clearFramebuffers(GLbitfield clearMask) {
+  ScopedStateRestorer scopedStateRestorer(this);
+  clearFramebuffersInternal(clearMask);
+}
+
+void DrawingBuffer::clearFramebuffersInternal(GLbitfield clearMask) {
+  m_stateRestorer->setFramebufferBindingDirty();
   // We will clear the multisample FBO, but we also need to clear the
   // non-multisampled buffer.
   if (m_multisampleFBO) {
@@ -897,7 +899,12 @@
   return adjustedSize;
 }
 
-bool DrawingBuffer::reset(const IntSize& newSize) {
+bool DrawingBuffer::resize(const IntSize& newSize) {
+  ScopedStateRestorer scopedStateRestorer(this);
+  return resizeFramebufferInternal(newSize);
+}
+
+bool DrawingBuffer::resizeFramebufferInternal(const IntSize& newSize) {
   CHECK(!newSize.isEmpty());
   IntSize adjustedSize = adjustSize(newSize, m_size, m_maxTextureSize);
   if (adjustedSize.isEmpty())
@@ -922,6 +929,7 @@
       return false;
   }
 
+  m_stateRestorer->setClearStateDirty();
   m_gl->Disable(GL_SCISSOR_TEST);
   m_gl->ClearColor(0, 0, 0,
                    defaultBufferRequiresAlphaChannelToBePreserved() ? 1 : 0);
@@ -939,17 +947,25 @@
     m_gl->StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
   }
 
-  clearFramebuffers(clearMask);
+  clearFramebuffersInternal(clearMask);
   return true;
 }
 
-void DrawingBuffer::commit() {
+void DrawingBuffer::resolveAndBindForReadAndDraw() {
+  {
+    ScopedStateRestorer scopedStateRestorer(this);
+    resolveMultisampleFramebufferInternal();
+  }
+  m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
+}
+
+void DrawingBuffer::resolveMultisampleFramebufferInternal() {
+  m_stateRestorer->setFramebufferBindingDirty();
   if (wantExplicitResolve() && !m_contentsChangeCommitted) {
+    m_stateRestorer->setClearStateDirty();
     m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_multisampleFBO);
     m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, m_fbo);
-
-    if (m_scissorEnabled)
-      m_gl->Disable(GL_SCISSOR_TEST);
+    m_gl->Disable(GL_SCISSOR_TEST);
 
     int width = m_size.width();
     int height = m_size.height();
@@ -968,52 +984,27 @@
             .disable_multisampling_color_mask_usage) {
       m_gl->ClearColor(0, 0, 0, 1);
       m_gl->ColorMask(false, false, false, true);
-      m_gl->Clear(GL_COLOR_BUFFER_BIT);
-
-      m_gl->ClearColor(m_clearColor[0], m_clearColor[1], m_clearColor[2],
-                       m_clearColor[3]);
-      m_gl->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2],
-                      m_colorMask[3]);
     }
-
-    if (m_scissorEnabled)
-      m_gl->Enable(GL_SCISSOR_TEST);
   }
 
   m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
-  if (m_antiAliasingMode == ScreenSpaceAntialiasing) {
+  if (m_antiAliasingMode == ScreenSpaceAntialiasing)
     m_gl->ApplyScreenSpaceAntialiasingCHROMIUM();
-  }
   m_contentsChangeCommitted = true;
 }
 
-void DrawingBuffer::restorePixelUnpackBufferBindings() {
-  if (m_webGLVersion > WebGL1) {
-    m_gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pixelUnpackBufferBinding);
-  }
+void DrawingBuffer::restoreFramebufferBindings() {
+  m_client->DrawingBufferClientRestoreFramebufferBinding();
 }
 
-void DrawingBuffer::restoreFramebufferBindings() {
-  if (m_drawFramebufferBinding && m_readFramebufferBinding) {
-    if (m_drawFramebufferBinding == m_readFramebufferBinding) {
-      m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_readFramebufferBinding);
-    } else {
-      m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER, m_readFramebufferBinding);
-      m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFramebufferBinding);
-    }
-    return;
-  }
-  if (!m_drawFramebufferBinding && !m_readFramebufferBinding) {
-    bind(GL_FRAMEBUFFER);
-    return;
-  }
-  if (!m_drawFramebufferBinding) {
-    bind(GL_DRAW_FRAMEBUFFER);
-    m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER, m_readFramebufferBinding);
-  } else {
-    bind(GL_READ_FRAMEBUFFER);
-    m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFramebufferBinding);
-  }
+void DrawingBuffer::restoreAllState() {
+  m_client->DrawingBufferClientRestoreScissorTest();
+  m_client->DrawingBufferClientRestoreMaskAndClearValues();
+  m_client->DrawingBufferClientRestorePixelPackAlignment();
+  m_client->DrawingBufferClientRestoreTexture2DBinding();
+  m_client->DrawingBufferClientRestoreRenderbufferBinding();
+  m_client->DrawingBufferClientRestoreFramebufferBinding();
+  m_client->DrawingBufferClientRestorePixelUnpackBufferBinding();
 }
 
 bool DrawingBuffer::multisample() const {
@@ -1025,15 +1016,13 @@
                         wantExplicitResolve() ? m_multisampleFBO : m_fbo);
 }
 
-void DrawingBuffer::setPackAlignment(GLint param) {
-  m_packAlignment = param;
-}
-
 bool DrawingBuffer::paintRenderingResultsToImageData(
     int& width,
     int& height,
     SourceDrawingBuffer sourceBuffer,
     WTF::ArrayBufferContents& contents) {
+  ScopedStateRestorer scopedStateRestorer(this);
+
   ASSERT(!m_premultipliedAlpha);
   width = size().width();
   height = size().height();
@@ -1049,6 +1038,7 @@
                                   WTF::ArrayBufferContents::DontInitialize);
 
   GLuint fbo = 0;
+  m_stateRestorer->setFramebufferBindingDirty();
   if (sourceBuffer == FrontBuffer && m_frontColorBuffer) {
     m_gl->GenFramebuffers(1, &fbo);
     m_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
@@ -1056,7 +1046,7 @@
                                m_frontColorBuffer->parameters.target,
                                m_frontColorBuffer->textureId, 0);
   } else {
-    m_gl->BindFramebuffer(GL_FRAMEBUFFER, framebuffer());
+    m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
   }
 
   readBackFramebuffer(static_cast<unsigned char*>(pixels.data()), width, height,
@@ -1069,8 +1059,6 @@
     m_gl->DeleteFramebuffers(1, &fbo);
   }
 
-  restoreFramebufferBindings();
-
   pixels.transfer(contents);
   return true;
 }
@@ -1080,11 +1068,9 @@
                                         int height,
                                         ReadbackOrder readbackOrder,
                                         WebGLImageConversion::AlphaOp op) {
-  if (m_packAlignment > 4)
-    m_gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
+  m_stateRestorer->setPixelPackAlignmentDirty();
+  m_gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
   m_gl->ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-  if (m_packAlignment > 4)
-    m_gl->PixelStorei(GL_PACK_ALIGNMENT, m_packAlignment);
 
   size_t bufferSize = 4 * width * height;
 
@@ -1126,6 +1112,9 @@
 
 RefPtr<DrawingBuffer::ColorBuffer> DrawingBuffer::createColorBuffer(
     const IntSize& size) {
+  m_stateRestorer->setFramebufferBindingDirty();
+  m_stateRestorer->setTextureBindingDirty();
+
   // Select the Parameters for the texture object. Allocate the backing
   // GpuMemoryBuffer and GLImage, if one is going to be used.
   ColorBufferParameters parameters;
@@ -1178,6 +1167,8 @@
   if (imageId && !m_wantAlphaChannel &&
       contextProvider()->getCapabilities().chromium_image_rgb_emulation) {
     GLuint fbo = 0;
+
+    m_stateRestorer->setClearStateDirty();
     m_gl->GenFramebuffers(1, &fbo);
     m_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
     m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@@ -1188,17 +1179,15 @@
     m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                parameters.target, 0, 0);
     m_gl->DeleteFramebuffers(1, &fbo);
-    restoreFramebufferBindings();
-    m_gl->ClearColor(m_clearColor[0], m_clearColor[1], m_clearColor[2],
-                     m_clearColor[3]);
-    m_gl->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2],
-                    m_colorMask[3]);
   }
 
   return adoptRef(new ColorBuffer(this, parameters, size, textureId, imageId));
 }
 
 void DrawingBuffer::attachColorBufferToReadFramebuffer() {
+  m_stateRestorer->setFramebufferBindingDirty();
+  m_stateRestorer->setTextureBindingDirty();
+
   m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
 
   GLenum target = m_backColorBuffer->parameters.target;
@@ -1212,9 +1201,6 @@
   else
     m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, id,
                                0);
-
-  restoreTextureBindings();
-  restoreFramebufferBindings();
 }
 
 bool DrawingBuffer::wantExplicitResolve() {
@@ -1239,11 +1225,33 @@
   return GL_RGB8_OES;
 }
 
-void DrawingBuffer::restoreTextureBindings() {
-  // This class potentially modifies the bindings for GL_TEXTURE_2D and
-  // GL_TEXTURE_RECTANGLE. Only GL_TEXTURE_2D needs to be restored since
-  // the public interface for WebGL does not support GL_TEXTURE_RECTANGLE.
-  m_gl->BindTexture(GL_TEXTURE_2D, m_texture2DBinding);
+DrawingBuffer::ScopedStateRestorer::ScopedStateRestorer(
+    DrawingBuffer* drawingBuffer)
+    : m_drawingBuffer(drawingBuffer) {
+  DCHECK(!m_drawingBuffer->m_stateRestorer);
+  m_drawingBuffer->m_stateRestorer = this;
+}
+
+DrawingBuffer::ScopedStateRestorer::~ScopedStateRestorer() {
+  m_drawingBuffer->m_stateRestorer = nullptr;
+  Client* client = m_drawingBuffer->m_client;
+  if (!client)
+    return;
+
+  if (m_clearStateDirty) {
+    client->DrawingBufferClientRestoreScissorTest();
+    client->DrawingBufferClientRestoreMaskAndClearValues();
+  }
+  if (m_pixelPackAlignmentDirty)
+    client->DrawingBufferClientRestorePixelPackAlignment();
+  if (m_textureBindingDirty)
+    client->DrawingBufferClientRestoreTexture2DBinding();
+  if (m_renderbufferBindingDirty)
+    client->DrawingBufferClientRestoreRenderbufferBinding();
+  if (m_framebufferBindingDirty)
+    client->DrawingBufferClientRestoreFramebufferBinding();
+  if (m_pixelUnpackBufferBindingDirty)
+    client->DrawingBufferClientRestorePixelUnpackBufferBinding();
 }
 
 bool DrawingBuffer::shouldUseChromiumImage() {
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
index 1033db4e..0bc3e68c 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
@@ -77,6 +77,21 @@
   WTF_MAKE_NONCOPYABLE(DrawingBuffer);
 
  public:
+  class Client {
+   public:
+    // Returns true if the DrawingBuffer is currently bound for draw.
+    virtual bool DrawingBufferClientIsBoundForDraw() = 0;
+    virtual void DrawingBufferClientRestoreScissorTest() = 0;
+    // Restores the mask and clear value for color, depth, and stencil buffers.
+    virtual void DrawingBufferClientRestoreMaskAndClearValues() = 0;
+    virtual void DrawingBufferClientRestorePixelPackAlignment() = 0;
+    // Restores the GL_TEXTURE_2D binding for the active texture unit only.
+    virtual void DrawingBufferClientRestoreTexture2DBinding() = 0;
+    virtual void DrawingBufferClientRestoreRenderbufferBinding() = 0;
+    virtual void DrawingBufferClientRestoreFramebufferBinding() = 0;
+    virtual void DrawingBufferClientRestorePixelUnpackBufferBinding() = 0;
+  };
+
   enum PreserveDrawingBuffer {
     Preserve,
     Discard,
@@ -93,6 +108,7 @@
 
   static PassRefPtr<DrawingBuffer> create(
       std::unique_ptr<WebGraphicsContext3DProvider>,
+      Client*,
       const IntSize&,
       bool premultipliedAlpha,
       bool wantAlphaChannel,
@@ -110,8 +126,6 @@
   void beginDestruction();
 
   // Issues a glClear() on all framebuffers associated with this DrawingBuffer.
-  // The caller is responsible for making the context current and setting the
-  // clear values and masks. Modifies the framebuffer binding.
   void clearFramebuffers(GLbitfield clearMask);
 
   // Indicates whether the DrawingBuffer internally allocated a packed
@@ -130,86 +144,21 @@
                             int maxTextureSize);
 
   // Resizes (or allocates if necessary) all buffers attached to the default
-  // framebuffer. Returns whether the operation was successful. Leaves GL
-  // bindings dirtied.
-  bool reset(const IntSize&);
+  // framebuffer. Returns whether the operation was successful.
+  bool resize(const IntSize&);
 
   // Bind the default framebuffer to |target|. |target| must be
   // GL_FRAMEBUFFER, GL_READ_FRAMEBUFFER, or GL_DRAW_FRAMEBUFFER.
   void bind(GLenum target);
   IntSize size() const { return m_size; }
 
-  // Copies the multisample color buffer to the normal color buffer and leaves
-  // m_fbo bound.
-  void commit();
-
-  // commit should copy the full multisample buffer, and not respect the
-  // current scissor bounds. Track the state of the scissor test so that it
-  // can be disabled during calls to commit.
-  void setScissorEnabled(bool scissorEnabled) {
-    m_scissorEnabled = scissorEnabled;
-  }
-
-  // The DrawingBuffer needs to track the texture bound to texture unit 0.
-  // The bound texture is tracked to avoid costly queries during rendering.
-  void setTexture2DBinding(GLuint texture) { m_texture2DBinding = texture; }
-
-  void setPixelUnpackBufferBinding(GLuint buffer) {
-    DCHECK(m_webGLVersion > WebGL1);
-    m_pixelUnpackBufferBinding = buffer;
-  }
-
-  void notifyBufferDeleted(GLuint buffer) {
-    if (m_webGLVersion > WebGL1 && buffer == m_pixelUnpackBufferBinding) {
-      setPixelUnpackBufferBinding(0);
-    }
-  }
-
-  // The DrawingBuffer needs to track the currently bound framebuffer so it
-  // restore the binding when needed.
-  void setFramebufferBinding(GLenum target, GLuint fbo) {
-    switch (target) {
-      case GL_FRAMEBUFFER:
-        m_drawFramebufferBinding = fbo;
-        m_readFramebufferBinding = fbo;
-        break;
-      case GL_DRAW_FRAMEBUFFER:
-        m_drawFramebufferBinding = fbo;
-        break;
-      case GL_READ_FRAMEBUFFER:
-        m_readFramebufferBinding = fbo;
-        break;
-      default:
-        ASSERT(0);
-    }
-  }
-
-  // The DrawingBuffer needs to track the color mask and clear color so that
-  // it can restore it when needed.
-  void setClearColor(GLfloat* clearColor) {
-    memcpy(m_clearColor, clearColor, 4 * sizeof(GLfloat));
-  }
-
-  void setColorMask(GLboolean* colorMask) {
-    memcpy(m_colorMask, colorMask, 4 * sizeof(GLboolean));
-  }
-
-  // The DrawingBuffer needs to track the currently bound renderbuffer so it
-  // restore the binding when needed.
-  void setRenderbufferBinding(GLuint renderbuffer) {
-    m_renderbufferBinding = renderbuffer;
-  }
-
-  // Track the currently active texture unit. Texture unit 0 is used as host for
-  // a scratch texture.
-  void setActiveTextureUnit(GLint textureUnit) {
-    m_activeTextureUnit = textureUnit;
-  }
+  // Resolves the multisample color buffer to the normal color buffer and leaves
+  // the resolved color buffer bound to GL_READ_FRAMEBUFFER and
+  // GL_DRAW_FRAMEBUFFER.
+  void resolveAndBindForReadAndDraw();
 
   bool multisample() const;
 
-  GLuint framebuffer() const;
-
   bool discardFramebufferSupported() const {
     return m_discardFramebufferSupported;
   }
@@ -246,7 +195,6 @@
   // DrawingBuffer.
   PassRefPtr<StaticBitmapImage> transferToStaticBitmapImage();
 
-  // Destroys the TEXTURE_2D binding for the owned context
   bool copyToPlatformTexture(gpu::gles2::GLES2Interface*,
                              GLuint texture,
                              GLenum internalFormat,
@@ -256,8 +204,6 @@
                              bool flipY,
                              SourceDrawingBuffer);
 
-  void setPackAlignment(GLint param);
-
   bool paintRenderingResultsToImageData(int&,
                                         int&,
                                         SourceDrawingBuffer,
@@ -268,13 +214,11 @@
     return m_antiAliasingMode == MSAAExplicitResolve;
   }
 
-  void restorePixelUnpackBufferBindings();
-
-  // Bind to m_drawFramebufferBinding or m_readFramebufferBinding if it's not 0.
-  // Otherwise, bind to the default FBO.
+  // Rebind the read and draw framebuffers that WebGL is expecting.
   void restoreFramebufferBindings();
 
-  void restoreTextureBindings();
+  // Restore all state that may have been dirtied by any call.
+  void restoreAllState();
 
   void addNewMailboxCallback(std::unique_ptr<WTF::Closure> closure) {
     m_newMailboxCallback = std::move(closure);
@@ -283,6 +227,7 @@
  protected:  // For unittests
   DrawingBuffer(std::unique_ptr<WebGraphicsContext3DProvider>,
                 std::unique_ptr<Extensions3DUtil>,
+                Client*,
                 bool discardFramebufferSupported,
                 bool wantAlphaChannel,
                 bool premultipliedAlpha,
@@ -303,6 +248,36 @@
   Vector<RecycledBitmap> m_recycledBitmaps;
 
  private:
+  friend class ScopedStateRestorer;
+  friend class ColorBuffer;
+
+  // This structure should wrap all public entrypoints that may modify GL state.
+  // It will restore all state when it drops out of scope.
+  class ScopedStateRestorer {
+   public:
+    ScopedStateRestorer(DrawingBuffer*);
+    ~ScopedStateRestorer();
+
+    // Mark parts of the state that are dirty and need to be restored.
+    void setClearStateDirty() { m_clearStateDirty = true; }
+    void setPixelPackAlignmentDirty() { m_pixelPackAlignmentDirty = true; }
+    void setTextureBindingDirty() { m_textureBindingDirty = true; }
+    void setRenderbufferBindingDirty() { m_renderbufferBindingDirty = true; }
+    void setFramebufferBindingDirty() { m_framebufferBindingDirty = true; }
+    void setPixelUnpackBufferBindingDirty() {
+      m_pixelUnpackBufferBindingDirty = true;
+    }
+
+   private:
+    RefPtr<DrawingBuffer> m_drawingBuffer;
+    bool m_clearStateDirty = false;
+    bool m_pixelPackAlignmentDirty = false;
+    bool m_textureBindingDirty = false;
+    bool m_renderbufferBindingDirty = false;
+    bool m_framebufferBindingDirty = false;
+    bool m_pixelUnpackBufferBindingDirty = false;
+  };
+
   // All parameters necessary to generate the texture for the ColorBuffer.
   struct ColorBufferParameters {
     DISALLOW_NEW();
@@ -349,6 +324,15 @@
     WTF_MAKE_NONCOPYABLE(ColorBuffer);
   };
 
+  // The same as clearFramebuffers(), but leaves GL state dirty.
+  void clearFramebuffersInternal(GLbitfield clearMask);
+
+  // The same as reset(), but leaves GL state dirty.
+  bool resizeFramebufferInternal(const IntSize&);
+
+  // The same as commit(), but leaves GL state dirty.
+  void resolveMultisampleFramebufferInternal();
+
   bool prepareTextureMailboxInternal(
       cc::TextureMailbox* outMailbox,
       std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback,
@@ -434,17 +418,11 @@
   // The format to use when creating a multisampled renderbuffer.
   GLenum getMultisampledRenderbufferFormat();
 
+  // Weak, reset by beginDestruction.
+  Client* m_client = nullptr;
+
   const PreserveDrawingBuffer m_preserveDrawingBuffer;
   const WebGLVersion m_webGLVersion;
-  bool m_scissorEnabled = false;
-  GLuint m_texture2DBinding = 0;
-  GLuint m_pixelUnpackBufferBinding = 0;
-  GLuint m_drawFramebufferBinding = 0;
-  GLuint m_readFramebufferBinding = 0;
-  GLuint m_renderbufferBinding = 0;
-  GLenum m_activeTextureUnit = GL_TEXTURE0;
-  GLfloat m_clearColor[4];
-  GLboolean m_colorMask[4];
 
   std::unique_ptr<WebGraphicsContext3DProvider> m_contextProvider;
   // Lifetime is tied to the m_contextProvider.
@@ -460,6 +438,11 @@
 
   std::unique_ptr<WTF::Closure> m_newMailboxCallback;
 
+  // The current state restorer, which is used to track state dirtying. It is in
+  // error to dirty state shared with WebGL while there is no existing state
+  // restorer. It is also in error to instantiate two state restorers at once.
+  ScopedStateRestorer* m_stateRestorer = nullptr;
+
   // This is used when the user requests either a depth or stencil buffer.
   GLuint m_depthStencilBuffer = 0;
 
@@ -506,7 +489,6 @@
 
   int m_maxTextureSize = 0;
   int m_sampleCount = 0;
-  int m_packAlignment = 4;
   bool m_destructionInProgress = false;
   bool m_isHidden = false;
   SkFilterQuality m_filterQuality = kLow_SkFilterQuality;
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
index f53a596..e45248ac 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
@@ -54,7 +54,7 @@
             new WebGraphicsContext3DProviderSoftwareRenderingForTests(
                 std::move(gl)));
     m_drawingBuffer = DrawingBufferForTests::create(
-        std::move(provider), initialSize, DrawingBuffer::Preserve);
+        std::move(provider), nullptr, initialSize, DrawingBuffer::Preserve);
     CHECK(m_drawingBuffer);
   }
 
@@ -70,7 +70,7 @@
   IntSize initialSize(InitialWidth, InitialHeight);
   IntSize alternateSize(InitialWidth, AlternateHeight);
 
-  m_drawingBuffer->reset(initialSize);
+  m_drawingBuffer->resize(initialSize);
   m_drawingBuffer->markContentsChanged();
   m_drawingBuffer->PrepareTextureMailbox(
       &textureMailbox, &releaseCallback1);  // create a bitmap.
@@ -87,7 +87,7 @@
       gpu::SyncToken(),
       false /* lostResource */);  // release bitmap to the recycling queue
   EXPECT_EQ(1, m_drawingBuffer->recycledBitmapCount());
-  m_drawingBuffer->reset(alternateSize);
+  m_drawingBuffer->resize(alternateSize);
   m_drawingBuffer->markContentsChanged();
   // Regression test for crbug.com/647896 - Next line must not crash
   m_drawingBuffer->PrepareTextureMailbox(
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
index ca2d941..2102dd9 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
@@ -56,18 +56,62 @@
     std::unique_ptr<GLES2InterfaceForTests> gl =
         wrapUnique(new GLES2InterfaceForTests);
     m_gl = gl.get();
+    SetAndSaveRestoreState(false);
     std::unique_ptr<WebGraphicsContext3DProviderForTests> provider =
         wrapUnique(new WebGraphicsContext3DProviderForTests(std::move(gl)));
     m_drawingBuffer = DrawingBufferForTests::create(
-        std::move(provider), initialSize, DrawingBuffer::Preserve);
+        std::move(provider), m_gl, initialSize, DrawingBuffer::Preserve);
     CHECK(m_drawingBuffer);
   }
 
+  // Initialize GL state with unusual values, to verify that they are restored.
+  // The |invert| parameter will reverse all boolean parameters, so that all
+  // values are tested.
+  void SetAndSaveRestoreState(bool invert) {
+    GLboolean scissorEnabled = !invert;
+    GLfloat clearColor[4] = {0.1, 0.2, 0.3, 0.4};
+    GLfloat clearDepth = 0.8;
+    GLint clearStencil = 37;
+    GLboolean colorMask[4] = {invert, !invert, !invert, invert};
+    GLboolean depthMask = invert;
+    GLboolean stencilMask = invert;
+    GLint packAlignment = 7;
+    GLuint activeTexture2DBinding = 0xbeef1;
+    GLuint renderbufferBinding = 0xbeef2;
+    GLuint drawFramebufferBinding = 0xbeef3;
+    GLuint readFramebufferBinding = 0xbeef4;
+    GLuint pixelUnpackBufferBinding = 0xbeef5;
+
+    if (scissorEnabled)
+      m_gl->Enable(GL_SCISSOR_TEST);
+    else
+      m_gl->Disable(GL_SCISSOR_TEST);
+
+    m_gl->ClearColor(clearColor[0], clearColor[1], clearColor[2],
+                     clearColor[3]);
+    m_gl->ClearDepthf(clearDepth);
+    m_gl->ClearStencil(clearStencil);
+    m_gl->ColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
+    m_gl->DepthMask(depthMask);
+    m_gl->StencilMask(stencilMask);
+    m_gl->PixelStorei(GL_PACK_ALIGNMENT, packAlignment);
+    m_gl->BindTexture(GL_TEXTURE_2D, activeTexture2DBinding);
+    m_gl->BindRenderbuffer(GL_RENDERBUFFER, renderbufferBinding);
+    m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, drawFramebufferBinding);
+    m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER, readFramebufferBinding);
+    m_gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelUnpackBufferBinding);
+
+    m_gl->SaveState();
+  }
+
+  void VerifyStateWasRestored() { m_gl->VerifyStateHasNotChangedSinceSave(); }
+
   GLES2InterfaceForTests* m_gl;
   RefPtr<DrawingBufferForTests> m_drawingBuffer;
 };
 
 TEST_F(DrawingBufferTest, verifyResizingProperlyAffectsMailboxes) {
+  VerifyStateWasRestored();
   cc::TextureMailbox textureMailbox;
   std::unique_ptr<cc::SingleReleaseCallback> releaseCallback;
 
@@ -78,33 +122,42 @@
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox,
                                                      &releaseCallback));
+  VerifyStateWasRestored();
   EXPECT_EQ(initialSize, m_gl->mostRecentlyProducedSize());
 
   // Resize to 100x50.
-  m_drawingBuffer->reset(alternateSize);
+  m_drawingBuffer->resize(alternateSize);
+  VerifyStateWasRestored();
   releaseCallback->Run(gpu::SyncToken(), false /* lostResource */);
+  VerifyStateWasRestored();
 
   // Produce a mailbox at this size.
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox,
                                                      &releaseCallback));
   EXPECT_EQ(alternateSize, m_gl->mostRecentlyProducedSize());
+  VerifyStateWasRestored();
 
   // Reset to initial size.
-  m_drawingBuffer->reset(initialSize);
+  m_drawingBuffer->resize(initialSize);
+  VerifyStateWasRestored();
+  SetAndSaveRestoreState(true);
   releaseCallback->Run(gpu::SyncToken(), false /* lostResource */);
+  VerifyStateWasRestored();
 
   // Prepare another mailbox and verify that it's the correct size.
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox,
                                                      &releaseCallback));
   EXPECT_EQ(initialSize, m_gl->mostRecentlyProducedSize());
+  VerifyStateWasRestored();
 
   // Prepare one final mailbox and verify that it's the correct size.
   releaseCallback->Run(gpu::SyncToken(), false /* lostResource */);
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox,
                                                      &releaseCallback));
+  VerifyStateWasRestored();
   EXPECT_EQ(initialSize, m_gl->mostRecentlyProducedSize());
   releaseCallback->Run(gpu::SyncToken(), false /* lostResource */);
   m_drawingBuffer->beginDestruction();
@@ -125,12 +178,18 @@
 
   // Produce mailboxes.
   m_drawingBuffer->markContentsChanged();
+  m_drawingBuffer->clearFramebuffers(GL_STENCIL_BUFFER_BIT);
+  VerifyStateWasRestored();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox1,
                                                      &releaseCallback1));
   m_drawingBuffer->markContentsChanged();
+  m_drawingBuffer->clearFramebuffers(GL_DEPTH_BUFFER_BIT);
+  VerifyStateWasRestored();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox2,
                                                      &releaseCallback2));
   m_drawingBuffer->markContentsChanged();
+  m_drawingBuffer->clearFramebuffers(GL_COLOR_BUFFER_BIT);
+  VerifyStateWasRestored();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox3,
                                                      &releaseCallback3));
 
@@ -167,12 +226,15 @@
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox1,
                                                      &releaseCallback1));
+  VerifyStateWasRestored();
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox2,
                                                      &releaseCallback2));
+  VerifyStateWasRestored();
   m_drawingBuffer->markContentsChanged();
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox3,
                                                      &releaseCallback3));
+  VerifyStateWasRestored();
 
   m_drawingBuffer->markContentsChanged();
   releaseCallback1->Run(gpu::SyncToken(), true /* lostResource */);
@@ -287,13 +349,14 @@
     std::unique_ptr<GLES2InterfaceForTests> gl =
         wrapUnique(new GLES2InterfaceForTests);
     m_gl = gl.get();
+    SetAndSaveRestoreState(true);
     std::unique_ptr<WebGraphicsContext3DProviderForTests> provider =
         wrapUnique(new WebGraphicsContext3DProviderForTests(std::move(gl)));
     RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(true);
     m_imageId0 = m_gl->nextImageIdToBeCreated();
     EXPECT_CALL(*m_gl, BindTexImage2DMock(m_imageId0)).Times(1);
     m_drawingBuffer = DrawingBufferForTests::create(
-        std::move(provider), initialSize, DrawingBuffer::Preserve);
+        std::move(provider), m_gl, initialSize, DrawingBuffer::Preserve);
     CHECK(m_drawingBuffer);
     testing::Mock::VerifyAndClearExpectations(m_gl);
   }
@@ -321,6 +384,7 @@
   EXPECT_EQ(initialSize, m_gl->mostRecentlyProducedSize());
   EXPECT_TRUE(textureMailbox.is_overlay_candidate());
   testing::Mock::VerifyAndClearExpectations(m_gl);
+  VerifyStateWasRestored();
 
   GLuint m_imageId2 = m_gl->nextImageIdToBeCreated();
   EXPECT_CALL(*m_gl, BindTexImage2DMock(m_imageId2)).Times(1);
@@ -329,8 +393,10 @@
   EXPECT_CALL(*m_gl, DestroyImageMock(m_imageId1)).Times(1);
   EXPECT_CALL(*m_gl, ReleaseTexImage2DMock(m_imageId1)).Times(1);
   // Resize to 100x50.
-  m_drawingBuffer->reset(alternateSize);
+  m_drawingBuffer->resize(alternateSize);
+  VerifyStateWasRestored();
   releaseCallback->Run(gpu::SyncToken(), false /* lostResource */);
+  VerifyStateWasRestored();
   testing::Mock::VerifyAndClearExpectations(m_gl);
 
   GLuint m_imageId3 = m_gl->nextImageIdToBeCreated();
@@ -350,8 +416,10 @@
   EXPECT_CALL(*m_gl, DestroyImageMock(m_imageId3)).Times(1);
   EXPECT_CALL(*m_gl, ReleaseTexImage2DMock(m_imageId3)).Times(1);
   // Reset to initial size.
-  m_drawingBuffer->reset(initialSize);
+  m_drawingBuffer->resize(initialSize);
+  VerifyStateWasRestored();
   releaseCallback->Run(gpu::SyncToken(), false /* lostResource */);
+  VerifyStateWasRestored();
   testing::Mock::VerifyAndClearExpectations(m_gl);
 
   GLuint m_imageId5 = m_gl->nextImageIdToBeCreated();
@@ -398,6 +466,7 @@
                                                      &releaseCallback1));
   EXPECT_TRUE(textureMailbox1.is_overlay_candidate());
   testing::Mock::VerifyAndClearExpectations(m_gl);
+  VerifyStateWasRestored();
 
   // Force image CHROMIUM creation failure. Request another mailbox. It should
   // still be provided, but this time with allowOverlay = false.
@@ -406,6 +475,7 @@
   EXPECT_TRUE(m_drawingBuffer->PrepareTextureMailbox(&textureMailbox2,
                                                      &releaseCallback2));
   EXPECT_FALSE(textureMailbox2.is_overlay_candidate());
+  VerifyStateWasRestored();
 
   // Check that if image CHROMIUM starts working again, mailboxes are
   // correctly created with allowOverlay = true.
@@ -416,6 +486,7 @@
                                                      &releaseCallback3));
   EXPECT_TRUE(textureMailbox3.is_overlay_candidate());
   testing::Mock::VerifyAndClearExpectations(m_gl);
+  VerifyStateWasRestored();
 
   releaseCallback1->Run(gpu::SyncToken(), false /* lostResource */);
   releaseCallback2->Run(gpu::SyncToken(), false /* lostResource */);
@@ -532,7 +603,7 @@
     bool wantStencilBuffer = cases[i].requestStencil;
     bool wantAntialiasing = false;
     RefPtr<DrawingBuffer> drawingBuffer = DrawingBuffer::create(
-        std::move(provider), IntSize(10, 10), premultipliedAlpha,
+        std::move(provider), nullptr, IntSize(10, 10), premultipliedAlpha,
         wantAlphaChannel, wantDepthBuffer, wantStencilBuffer, wantAntialiasing,
         preserve, DrawingBuffer::WebGL1, DrawingBuffer::AllowChromiumImage);
 
@@ -553,7 +624,7 @@
       EXPECT_EQ(0u, trackingGL->stencilAttachment());
     }
 
-    drawingBuffer->reset(IntSize(10, 20));
+    drawingBuffer->resize(IntSize(10, 20));
     EXPECT_EQ(cases[i].requestDepth || cases[i].requestStencil,
               drawingBuffer->hasDepthBuffer());
     EXPECT_EQ(cases[i].requestDepth || cases[i].requestStencil,
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
index 3fb106c..87bf7c8 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
@@ -8,6 +8,7 @@
 #include "platform/graphics/gpu/Extensions3DUtil.h"
 #include "public/platform/WebGraphicsContext3DProvider.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
@@ -21,13 +22,14 @@
  public:
   static PassRefPtr<DrawingBufferForTests> create(
       std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
+      DrawingBuffer::Client* client,
       const IntSize& size,
       PreserveDrawingBuffer preserve) {
     std::unique_ptr<Extensions3DUtil> extensionsUtil =
         Extensions3DUtil::create(contextProvider->contextGL());
-    RefPtr<DrawingBufferForTests> drawingBuffer =
-        adoptRef(new DrawingBufferForTests(
-            std::move(contextProvider), std::move(extensionsUtil), preserve));
+    RefPtr<DrawingBufferForTests> drawingBuffer = adoptRef(
+        new DrawingBufferForTests(std::move(contextProvider),
+                                  std::move(extensionsUtil), client, preserve));
     bool multisampleExtensionSupported = false;
     if (!drawingBuffer->initialize(size, multisampleExtensionSupported)) {
       drawingBuffer->beginDestruction();
@@ -39,10 +41,12 @@
   DrawingBufferForTests(
       std::unique_ptr<WebGraphicsContext3DProvider> contextProvider,
       std::unique_ptr<Extensions3DUtil> extensionsUtil,
+      DrawingBuffer::Client* client,
       PreserveDrawingBuffer preserve)
       : DrawingBuffer(
             std::move(contextProvider),
             std::move(extensionsUtil),
+            client,
             false /* discardFramebufferSupported */,
             true /* wantAlphaChannel */,
             false /* premultipliedAlpha */,
@@ -102,16 +106,88 @@
   return GL_TEXTURE_2D;
 }
 
-class GLES2InterfaceForTests : public gpu::gles2::GLES2InterfaceStub {
+class GLES2InterfaceForTests : public gpu::gles2::GLES2InterfaceStub,
+                               public DrawingBuffer::Client {
  public:
+  // GLES2InterfaceStub implementation:
   void BindTexture(GLenum target, GLuint texture) override {
-    if (target != m_boundTextureTarget && texture == 0)
-      return;
+    if (target == GL_TEXTURE_2D)
+      m_state.activeTexture2DBinding = texture;
+    m_boundTextures[target] = texture;
+  }
 
-    // For simplicity, only allow one target to ever be bound.
-    ASSERT_TRUE(m_boundTextureTarget == 0 || target == m_boundTextureTarget);
-    m_boundTextureTarget = target;
-    m_boundTexture = texture;
+  void BindFramebuffer(GLenum target, GLuint framebuffer) override {
+    switch (target) {
+      case GL_FRAMEBUFFER:
+        m_state.drawFramebufferBinding = framebuffer;
+        m_state.readFramebufferBinding = framebuffer;
+        break;
+      case GL_DRAW_FRAMEBUFFER:
+        m_state.drawFramebufferBinding = framebuffer;
+        break;
+      case GL_READ_FRAMEBUFFER:
+        m_state.readFramebufferBinding = framebuffer;
+        break;
+      default:
+        break;
+    }
+  }
+
+  void BindRenderbuffer(GLenum target, GLuint renderbuffer) override {
+    m_state.renderbufferBinding = renderbuffer;
+  }
+
+  void Enable(GLenum cap) {
+    if (cap == GL_SCISSOR_TEST)
+      m_state.scissorEnabled = true;
+  }
+
+  void Disable(GLenum cap) {
+    if (cap == GL_SCISSOR_TEST)
+      m_state.scissorEnabled = false;
+  }
+
+  void ClearColor(GLfloat red,
+                  GLfloat green,
+                  GLfloat blue,
+                  GLfloat alpha) override {
+    m_state.clearColor[0] = red;
+    m_state.clearColor[1] = green;
+    m_state.clearColor[2] = blue;
+    m_state.clearColor[3] = alpha;
+  }
+
+  void ClearDepthf(GLfloat depth) override { m_state.clearDepth = depth; }
+
+  void ClearStencil(GLint s) override { m_state.clearStencil = s; }
+
+  void ColorMask(GLboolean red,
+                 GLboolean green,
+                 GLboolean blue,
+                 GLboolean alpha) override {
+    m_state.colorMask[0] = red;
+    m_state.colorMask[1] = green;
+    m_state.colorMask[2] = blue;
+    m_state.colorMask[3] = alpha;
+  }
+
+  void DepthMask(GLboolean flag) override { m_state.depthMask = flag; }
+
+  void StencilMask(GLuint mask) override { m_state.stencilMask = mask; }
+
+  void StencilMaskSeparate(GLenum face, GLuint mask) override {
+    if (face == GL_FRONT)
+      m_state.stencilMask = mask;
+  }
+
+  void PixelStorei(GLenum pname, GLint param) override {
+    if (pname == GL_PACK_ALIGNMENT)
+      m_state.packAlignment = param;
+  }
+
+  void BindBuffer(GLenum target, GLuint buffer) override {
+    if (target == GL_PIXEL_UNPACK_BUFFER)
+      m_state.pixelUnpackBufferBinding = buffer;
   }
 
   GLuint64 InsertFenceSyncCHROMIUM() override {
@@ -159,7 +235,7 @@
                   GLenum type,
                   const void* pixels) override {
     if (target == GL_TEXTURE_2D && !level) {
-      m_textureSizes.set(m_boundTexture, IntSize(width, height));
+      m_textureSizes.set(m_boundTextures[target], IntSize(width, height));
     }
   }
 
@@ -185,8 +261,9 @@
   MOCK_METHOD1(BindTexImage2DMock, void(GLint imageId));
   void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
     if (target == imageCHROMIUMTextureTarget()) {
-      m_textureSizes.set(m_boundTexture, m_imageSizes.find(imageId)->value);
-      m_imageToTextureMap.set(imageId, m_boundTexture);
+      m_textureSizes.set(m_boundTextures[target],
+                         m_imageSizes.find(imageId)->value);
+      m_imageToTextureMap.set(imageId, m_boundTextures[target]);
       BindTexImage2DMock(imageId);
     }
   }
@@ -213,8 +290,42 @@
       textures[i] = id++;
   }
 
-  GLuint boundTexture() const { return m_boundTexture; }
-  GLuint boundTextureTarget() const { return m_boundTextureTarget; }
+  // DrawingBuffer::Client implementation.
+  bool DrawingBufferClientIsBoundForDraw() override {
+    return !m_state.drawFramebufferBinding;
+  }
+  void DrawingBufferClientRestoreScissorTest() override {
+    m_state.scissorEnabled = m_savedState.scissorEnabled;
+  }
+  void DrawingBufferClientRestoreMaskAndClearValues() override {
+    memcpy(m_state.colorMask, m_savedState.colorMask,
+           sizeof(m_state.colorMask));
+    m_state.clearDepth = m_savedState.clearDepth;
+    m_state.clearStencil = m_savedState.clearStencil;
+
+    memcpy(m_state.clearColor, m_savedState.clearColor,
+           sizeof(m_state.clearColor));
+    m_state.depthMask = m_savedState.depthMask;
+    m_state.stencilMask = m_savedState.stencilMask;
+  }
+  void DrawingBufferClientRestorePixelPackAlignment() override {
+    m_state.packAlignment = m_savedState.packAlignment;
+  }
+  void DrawingBufferClientRestoreTexture2DBinding() override {
+    m_state.activeTexture2DBinding = m_savedState.activeTexture2DBinding;
+  }
+  void DrawingBufferClientRestoreRenderbufferBinding() override {
+    m_state.renderbufferBinding = m_savedState.renderbufferBinding;
+  }
+  void DrawingBufferClientRestoreFramebufferBinding() override {
+    m_state.drawFramebufferBinding = m_savedState.drawFramebufferBinding;
+    m_state.readFramebufferBinding = m_savedState.readFramebufferBinding;
+  }
+  void DrawingBufferClientRestorePixelUnpackBufferBinding() override {
+    m_state.pixelUnpackBufferBinding = m_savedState.pixelUnpackBufferBinding;
+  }
+
+  // Testing methods.
   gpu::SyncToken mostRecentlyWaitedSyncToken() const {
     return m_mostRecentlyWaitedSyncToken;
   }
@@ -227,9 +338,56 @@
     m_createImageChromiumFail = fail;
   }
 
+  // Saves current GL state for later verification.
+  void SaveState() { m_savedState = m_state; }
+  void VerifyStateHasNotChangedSinceSave() const {
+    for (size_t i = 0; i < 4; ++i) {
+      EXPECT_EQ(m_state.clearColor[0], m_savedState.clearColor[0]);
+      EXPECT_EQ(m_state.colorMask[0], m_savedState.colorMask[0]);
+    }
+    EXPECT_EQ(m_state.clearDepth, m_savedState.clearDepth);
+    EXPECT_EQ(m_state.clearStencil, m_savedState.clearStencil);
+    EXPECT_EQ(m_state.depthMask, m_savedState.depthMask);
+    EXPECT_EQ(m_state.stencilMask, m_savedState.stencilMask);
+    EXPECT_EQ(m_state.packAlignment, m_savedState.packAlignment);
+    EXPECT_EQ(m_state.activeTexture2DBinding,
+              m_savedState.activeTexture2DBinding);
+    EXPECT_EQ(m_state.renderbufferBinding, m_savedState.renderbufferBinding);
+    EXPECT_EQ(m_state.drawFramebufferBinding,
+              m_savedState.drawFramebufferBinding);
+    EXPECT_EQ(m_state.readFramebufferBinding,
+              m_savedState.readFramebufferBinding);
+    EXPECT_EQ(m_state.pixelUnpackBufferBinding,
+              m_savedState.pixelUnpackBufferBinding);
+  }
+
  private:
-  GLuint m_boundTexture = 0;
-  GLuint m_boundTextureTarget = 0;
+  std::map<GLenum, GLuint> m_boundTextures;
+
+  // State tracked to verify that it is restored correctly.
+  struct State {
+    bool scissorEnabled = false;
+
+    GLfloat clearColor[4] = {0, 0, 0, 0};
+    GLfloat clearDepth = 0;
+    GLint clearStencil = 0;
+
+    GLboolean colorMask[4] = {0, 0, 0, 0};
+    GLboolean depthMask = 0;
+    GLuint stencilMask = 0;
+
+    GLint packAlignment = 4;
+
+    // The bound 2D texture for the active texture unit.
+    GLuint activeTexture2DBinding = 0;
+    GLuint renderbufferBinding = 0;
+    GLuint drawFramebufferBinding = 0;
+    GLuint readFramebufferBinding = 0;
+    GLuint pixelUnpackBufferBinding = 0;
+  };
+  State m_state;
+  State m_savedState;
+
   gpu::SyncToken m_mostRecentlyWaitedSyncToken;
   GLbyte m_currentMailboxByte = 0;
   IntSize m_mostRecentlyProducedSize;
diff --git a/third_party/WebKit/Source/platform/mac/ThemeMac.mm b/third_party/WebKit/Source/platform/mac/ThemeMac.mm
index aedd5ba..c4eb0691 100644
--- a/third_party/WebKit/Source/platform/mac/ThemeMac.mm
+++ b/third_party/WebKit/Source/platform/mac/ThemeMac.mm
@@ -393,7 +393,7 @@
       NSFont* nsFont = [NSFont
           systemFontOfSize:[NSFont systemFontSizeForControlSize:
                                        controlSizeForFont(fontDescription)]];
-      result.firstFamily().setFamily(@"BlinkMacSystemFont");
+      result.firstFamily().setFamily(FontFamilyNames::system_ui);
       result.setComputedSize([nsFont pointSize] * zoomFactor);
       result.setSpecifiedSize([nsFont pointSize] * zoomFactor);
       return result;
diff --git a/third_party/WebKit/Source/platform/text/TextChecking.h b/third_party/WebKit/Source/platform/text/TextChecking.h
index 6e21594..2dbbccc 100644
--- a/third_party/WebKit/Source/platform/text/TextChecking.h
+++ b/third_party/WebKit/Source/platform/text/TextChecking.h
@@ -39,11 +39,6 @@
 
 namespace blink {
 
-enum TextCheckingProcessType {
-  TextCheckingProcessBatch,
-  TextCheckingProcessIncremental
-};
-
 struct GrammarDetail {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
   int location;
@@ -68,30 +63,24 @@
   DISALLOW_NEW();
   friend class SpellCheckRequest;  // For access to m_sequence.
  public:
-  TextCheckingRequestData()
-      : m_sequence(unrequestedTextCheckingSequence),
-        m_processType(TextCheckingProcessIncremental) {}
+  TextCheckingRequestData() : m_sequence(unrequestedTextCheckingSequence) {}
   TextCheckingRequestData(int sequence,
                           const String& text,
-                          TextCheckingProcessType processType,
                           const Vector<uint32_t>& markers,
                           const Vector<unsigned>& offsets)
       : m_sequence(sequence),
         m_text(text),
-        m_processType(processType),
         m_markers(markers),
         m_offsets(offsets) {}
 
   int sequence() const { return m_sequence; }
   String text() const { return m_text; }
-  TextCheckingProcessType processType() const { return m_processType; }
   const Vector<uint32_t>& markers() const { return m_markers; }
   const Vector<unsigned>& offsets() const { return m_offsets; }
 
  private:
   int m_sequence;
   String m_text;
-  TextCheckingProcessType m_processType;
   Vector<uint32_t> m_markers;
   Vector<unsigned> m_offsets;
 };
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index da892f9..3787fb6 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -2711,6 +2711,14 @@
                       ->frameView()
                       ->layoutSize()
                       .width());
+
+  webViewHelper.resize(WebSize(1200, 480));
+
+  EXPECT_EQ(1200, webViewHelper.webView()
+                      ->mainFrameImpl()
+                      ->frameView()
+                      ->layoutSize()
+                      .width());
 }
 
 TEST_P(ParameterizedWebFrameTest, AtViewportAffectingAtMediaRecalcCount) {
diff --git a/third_party/WebKit/public/platform/WebLayer.h b/third_party/WebKit/public/platform/WebLayer.h
index 56393e1..f9408b6 100644
--- a/third_party/WebKit/public/platform/WebLayer.h
+++ b/third_party/WebKit/public/platform/WebLayer.h
@@ -219,8 +219,8 @@
   virtual uint32_t compositorMutableProperties() const = 0;
 
   virtual void setHasWillChangeTransformHint(bool) = 0;
-  virtual void setPreferredRasterScale(float) = 0;
-  virtual void clearPreferredRasterScale() = 0;
+  virtual void setPreferredRasterBounds(const WebSize&) = 0;
+  virtual void clearPreferredRasterBounds() = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/modules/webmidi/WebMIDIAccessorClient.h b/third_party/WebKit/public/platform/modules/webmidi/WebMIDIAccessorClient.h
index 868c4545..780c1ab3 100644
--- a/third_party/WebKit/public/platform/modules/webmidi/WebMIDIAccessorClient.h
+++ b/third_party/WebKit/public/platform/modules/webmidi/WebMIDIAccessorClient.h
@@ -38,27 +38,24 @@
 
 class WebMIDIAccessorClient {
  public:
-  enum MIDIPortState {
-    MIDIPortStateDisconnected,
-    MIDIPortStateConnected,
-  };
-
   // didAddInputPort() and didAddOutputPort() can be called before and after
   // didStartSession() is called. But |id| should be unique in each function.
   virtual void didAddInputPort(const WebString& id,
                                const WebString& manufacturer,
                                const WebString& name,
                                const WebString& version,
-                               MIDIPortState) = 0;
+                               midi::mojom::PortState) = 0;
   virtual void didAddOutputPort(const WebString& id,
                                 const WebString& manufacturer,
                                 const WebString& name,
                                 const WebString& version,
-                                MIDIPortState) = 0;
+                                midi::mojom::PortState) = 0;
   // didSetInputPortState() and didSetOutputPortState() should not be called
   // until didStartSession() is called.
-  virtual void didSetInputPortState(unsigned portIndex, MIDIPortState) = 0;
-  virtual void didSetOutputPortState(unsigned portIndex, MIDIPortState) = 0;
+  virtual void didSetInputPortState(unsigned portIndex,
+                                    midi::mojom::PortState) = 0;
+  virtual void didSetOutputPortState(unsigned portIndex,
+                                     midi::mojom::PortState) = 0;
 
   virtual void didStartSession(midi::mojom::Result) = 0;
 
diff --git a/tools/accessibility/rebase_dump_accessibility_tree_test.py b/tools/accessibility/rebase_dump_accessibility_tree_test.py
index 2a6ccb08..5601144 100755
--- a/tools/accessibility/rebase_dump_accessibility_tree_test.py
+++ b/tools/accessibility/rebase_dump_accessibility_tree_test.py
@@ -16,7 +16,6 @@
 of the changes look reasonable, then upload the change for code review.
 """
 
-import json
 import os
 import re
 import sys
@@ -43,84 +42,65 @@
 
 def ParseFailure(name, url):
   '''Parse given the name of a failing trybot and the url of its build log.'''
-  print
-  print "Checking trybot: %s" % name
-  url = url.replace('/builders/', '/json/builders/')
-  response = urllib.urlopen(url)
-  if response.getcode() == 200:
-    jsondata = response.read()
 
-  if not jsondata:
-    print "Failed to fetch from: " + url
+  # Figure out the platform.
+  if name.find('android') >= 0:
+    platform_suffix = '-expected-android.txt'
+  elif name.find('mac') >= 0:
+    platform_suffix = '-expected-mac.txt'
+  elif name.find('win') >= 0:
+    platform_suffix = '-expected-win.txt'
+  else:
     return
 
-  try:
-    data = json.loads(jsondata)
-  except:
-    print "Failed to parse JSON from: " + url
+  # Read the content_browsertests log file.
+  data = None
+  lines = None
+  urls = []
+  for url_suffix in [
+      '/steps/content_browsertests%20(with%20patch)/logs/stdio/text',
+      '/steps/content_browsertests/logs/stdio/text']:
+    urls.append(url + url_suffix)
+  for url in urls:
+    response = urllib.urlopen(url)
+    if response.getcode() == 200:
+      data = response.read()
+      lines = data.splitlines()
+      break
+
+  if not data:
     return
 
-  for step in data["steps"]:
-    name = step["name"]
-    if name[:len("content_browsertests")] == "content_browsertests":
-      if name.find("without") >= 0:
-        continue
-      if name.find("retry") >= 0:
-        continue
-      print "Found content_browsertests logs"
-      for log in step["logs"]:
-        (log_name, log_url) = log
-        if log_name == "stdio":
-          continue
-        log_url += '/text'
-        log_response = urllib.urlopen(log_url)
-        if log_response.getcode() == 200:
-          logdata = log_response.read()
-          ParseLog(logdata)
-        else:
-          print "Failed to fetch test log data from: " + url
-
-def Fix(line):
-  if line[:3] == '@@@':
-    try:
-      line = re.search('[^@]@([^@]*)@@@', line).group(1)
-    except:
-      pass
-  return line
-
-def ParseLog(logdata):
-  '''Parse the log file for failing tests and overwrite the expected
-     result file locally with the actual results from the log.'''
-  lines = logdata.splitlines()
-  test_file = None
-  expected_file = None
+  # Parse the log file for failing tests and overwrite the expected
+  # result file locally with the actual results from the log.
+  test_name = None
   start = None
+  filename = None
   for i in range(len(lines)):
-    line = Fix(lines[i])
-    if line.find('Testing:') >= 0:
-      test_file = re.search(
-          'content.test.*accessibility.([^@]*)', line).group(1)
-      expected_file = None
-      start = None
-    if line.find('Expected output:') >= 0:
-      expected_file = re.search(
-          'content.test.*accessibility.([^@]*)', line).group(1)
-    if line == 'Actual':
+    line = lines[i]
+    if line[:12] == '[ RUN      ]':
+      test_name = line[13:]
+    if test_name and line[:8] == 'Testing:':
+      filename = re.search('content.test.*accessibility.(.*)', line).group(1)
+    if test_name and line == 'Actual':
       start = i + 2
-    if start and test_file and expected_file and line.find('End-of-file') >= 0:
-      dst_fullpath = os.path.join(TEST_DATA_PATH, expected_file)
+    if start and test_name and filename and line[:12] == '[  FAILED  ]':
+      # Get the path to the html file.
+      dst_fullpath = os.path.join(TEST_DATA_PATH, filename)
+      # Strip off .html and replace it with the platform expected suffix.
+      dst_fullpath = dst_fullpath[:-5] + platform_suffix
       if dst_fullpath in completed_files:
         continue
 
-      actual = [Fix(line) for line in lines[start : i] if line]
+      actual = [line for line in lines[start : i - 1] if line]
       fp = open(dst_fullpath, 'w')
       fp.write('\n'.join(actual))
       fp.close()
-      print "* %s" % os.path.relpath(dst_fullpath)
+      print dst_fullpath
       completed_files.add(dst_fullpath)
       start = None
-      test_file = None
-      expected_file = None
+      test_name = None
+      filename = None
 
 def ParseTrybots(data):
   '''Parse the code review page to find links to try bots.'''
@@ -146,20 +126,8 @@
   response = urllib.urlopen(url)
   if response.getcode() != 200:
     print 'Error code %d accessing url: %s' % (response.getcode(), url)
-    return
   data = response.read()
   ParseTrybots(data)
 
-  print
-  if len(completed_files) == 0:
-    print "No output from DumpAccessibilityTree test results found."
-    return
-  else:
-    print "Summary: modified the following files:"
-    all_files = list(completed_files)
-    all_files.sort()
-    for f in all_files:
-      print "* %s" % os.path.relpath(f)
-
 if __name__ == '__main__':
   sys.exit(Run())
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0acfe0c..1ae8cde 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -63275,6 +63275,22 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.SessionTabs" units="tabs">
+  <owner>zea@chromium.org</owner>
+  <summary>
+    For each Chrome window, records the number of tabs present at the time Sync
+    associates the SESSIONS datatype.
+  </summary>
+</histogram>
+
+<histogram name="Sync.SessionWindows" units="windows">
+  <owner>zea@chromium.org</owner>
+  <summary>
+    The number of windows present within Chrome at the time Sync associates the
+    SESSIONS datatype.
+  </summary>
+</histogram>
+
 <histogram name="Sync.Shutdown.BackendDestroyedTime" units="ms">
   <owner>zea@chromium.org</owner>
   <summary>
@@ -84340,6 +84356,7 @@
   <int value="1651" label="WebAudioConstantSourceNode"/>
   <int value="1652" label="LoopbackEmbeddedInSecureContext"/>
   <int value="1653" label="LoopbackEmbeddedInNonSecureContext"/>
+  <int value="1654" label="BlinkMacSystemFont"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
diff --git a/ui/ozone/OWNERS b/ui/ozone/OWNERS
index ec43a6d..68277d59 100644
--- a/ui/ozone/OWNERS
+++ b/ui/ozone/OWNERS
@@ -1,3 +1,4 @@
 rjkroege@chromium.org
 spang@chromium.org
 alexst@chromium.org
+hshi@chromium.org
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc
index a3e8166..0f39b11 100644
--- a/ui/snapshot/snapshot_aura.cc
+++ b/ui/snapshot/snapshot_aura.cc
@@ -53,8 +53,14 @@
   // Retry the copy request if the previous one failed for some reason.
   if (!tracker->windows().empty() && (retry_count < kMaxRetries) &&
       result->IsEmpty()) {
+    // Look up window before calling MakeAsyncRequest. Otherwise, due
+    // to undefined (favorably right to left) argument evaluation
+    // order, the tracker might have been passed and set to NULL
+    // before the window is looked up which results in a NULL pointer
+    // dereference.
+    gfx::NativeWindow window = tracker->windows()[0];
     MakeAsyncCopyRequest(
-        tracker->windows()[0], source_rect,
+        window, source_rect,
         base::Bind(&FinishedAsyncCopyRequest, base::Passed(&tracker),
                    source_rect, callback, retry_count + 1));
     return;
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index b321859f..565b115 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -685,8 +685,6 @@
     "test/scoped_views_test_helper.h",
     "test/slider_test_api.cc",
     "test/slider_test_api.h",
-    "test/test_layout_manager.cc",
-    "test/test_layout_manager.h",
     "test/test_slider.cc",
     "test/test_slider.h",
     "test/test_views.cc",
diff --git a/ui/views/test/test_layout_manager.cc b/ui/views/test/test_layout_manager.cc
deleted file mode 100644
index ae1f2678..0000000
--- a/ui/views/test/test_layout_manager.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/views/test/test_layout_manager.h"
-
-namespace views {
-namespace test {
-
-TestLayoutManager::TestLayoutManager() {}
-
-TestLayoutManager::~TestLayoutManager() {}
-
-void TestLayoutManager::Layout(View* host) {}
-
-gfx::Size TestLayoutManager::GetPreferredSize(const View* host) const {
-  return preferred_size_;
-}
-
-int TestLayoutManager::GetPreferredHeightForWidth(const View* host,
-                                                  int width) const {
-  return preferred_height_for_width_;
-}
-
-}  // namespace test
-}  // namespace views
diff --git a/ui/views/test/test_layout_manager.h b/ui/views/test/test_layout_manager.h
deleted file mode 100644
index b50f0190..0000000
--- a/ui/views/test/test_layout_manager.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_VIEWS_TEST_TEST_LAYOUT_MANAGER_H_
-#define UI_VIEWS_TEST_TEST_LAYOUT_MANAGER_H_
-
-#include "ui/gfx/geometry/size.h"
-#include "ui/views/layout/layout_manager.h"
-
-namespace views {
-namespace test {
-
-// A stub layout manager that returns a specific preferred size and height for
-// width.
-class TestLayoutManager : public LayoutManager {
- public:
-  TestLayoutManager();
-  ~TestLayoutManager() override;
-
-  void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; }
-
-  void set_preferred_height_for_width(int height) {
-    preferred_height_for_width_ = height;
-  }
-
-  // LayoutManager:
-  void Layout(View* host) override;
-  gfx::Size GetPreferredSize(const View* host) const override;
-  int GetPreferredHeightForWidth(const View* host, int width) const override;
-
- private:
-  // The return value of GetPreferredSize();
-  gfx::Size preferred_size_;
-
-  // The return value for GetPreferredHeightForWidth().
-  int preferred_height_for_width_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(TestLayoutManager);
-};
-
-}  // namespace test
-}  // namespace views
-
-#endif  // UI_VIEWS_TEST_TEST_LAYOUT_MANAGER_H_
diff --git a/ui/views/test/test_views.cc b/ui/views/test/test_views.cc
index 78239f3..d0ad7d5 100644
--- a/ui/views/test/test_views.cc
+++ b/ui/views/test/test_views.cc
@@ -10,16 +10,17 @@
 
 namespace views {
 
-StaticSizedView::StaticSizedView(const gfx::Size& preferred_size)
+StaticSizedView::StaticSizedView(const gfx::Size& size)
     // Default GetMinimumSize() is GetPreferredSize(). Default GetMaximumSize()
     // is 0x0.
-    : preferred_size_(preferred_size),
-      minimum_size_(preferred_size) {}
+    : size_(size),
+      minimum_size_(size) {
+}
 
 StaticSizedView::~StaticSizedView() {}
 
 gfx::Size StaticSizedView::GetPreferredSize() const {
-  return preferred_size_;
+  return size_;
 }
 
 gfx::Size StaticSizedView::GetMinimumSize() const {
diff --git a/ui/views/test/test_views.h b/ui/views/test/test_views.h
index eaabcd0..ef17c15 100644
--- a/ui/views/test/test_views.h
+++ b/ui/views/test/test_views.h
@@ -16,7 +16,7 @@
 // A view that requests a set amount of space.
 class StaticSizedView : public View {
  public:
-  explicit StaticSizedView(const gfx::Size& preferred_size = gfx::Size());
+  explicit StaticSizedView(const gfx::Size& size);
   ~StaticSizedView() override;
 
   void set_minimum_size(const gfx::Size& minimum_size) {
@@ -33,7 +33,7 @@
   gfx::Size GetMaximumSize() const override;
 
  private:
-  gfx::Size preferred_size_;
+  gfx::Size size_;
   gfx::Size minimum_size_;
   gfx::Size maximum_size_;
 
diff --git a/ui/views/view.cc b/ui/views/view.cc
index d5da6b5b..3cb42dc 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -128,10 +128,6 @@
 
   ViewStorage::GetInstance()->ViewRemoved(this);
 
-  // Some layout managers hold a reference to the host that they are installed
-  // to and may need to access this during destruction.
-  layout_manager_.reset();
-
   for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) {
     (*i)->parent_ = NULL;
     if (!(*i)->owned_by_client_)