diff --git a/DEPS b/DEPS
index 74c7d4d..810493c0 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,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': '7f3ceba5dc7f89d013f39da0b5ce14807588e121',
+  'skia_revision': '3ad86d0c8bc41007d96a8d7335bc97ba08369741',
   # 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': 'ae37766fa5f1a1c4b57e2905f28664b5f1ae67d6',
+  'v8_revision': 'd46dfc574b2090b0ffa7cd0d3cea901deddb3bd7',
   # 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.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '79207e6e11df06880ff0a9071479b2903d46d1b1',
+  'angle_revision': '5ddbdbf70c50068b9682750454d9fd339ed805c2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -165,7 +165,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': '98289bcecf60590683b9adb7dc05de31dc9dd6cf',
+  'catapult_revision': 'ac93684421fa0fb860b74e4339253378ee9066ab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -213,7 +213,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'ddc705933d3f32024ea0e320a2c9d91925b78d9c',
+  'spv_tools_revision': 'fe90a1d2dcbeaffd7cb87fa50860c6741e76eaef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1106,7 +1106,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '1ee9160a2e0bc6381caca2b8c42f7ce5507619bc',
+    Var('webrtc_git') + '/src.git' + '@' + '3ff52ffa22ae08a487482c4adc6bbf53f334f947',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1137,7 +1137,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1913722a58e2e019d88ef11e5cf8b4ba4a5db8c3',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8dfa5c869e0823cae9bd4c6cec863741fdef23c3',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
index 89e2a2e..22a7f12 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -1,4 +1,5 @@
 # speech api not enabled in webview, crbug.com/487255
+interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent
 interface SpeechSynthesisEvent : Event
 interface SpeechSynthesisUtterance : EventTarget
 interface webkitSpeechGrammar
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index 17a87572..a562c6d 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -1060,11 +1060,7 @@
   if (folder_delegate_)
     return kMaxFolderItemsPerPage;
 
-  // In new style launcher, the first row of first page is no longger suggestion
-  // apps.
-  if (page == 0 && !is_new_style_launcher_enabled_)
-    return cols_ * (rows_per_page_ - 1);
-  return cols_ * rows_per_page_;
+  return AppListConfig::instance().GetMaxNumOfItemsPerPage(page);
 }
 
 void AppsGridView::UpdatePaging() {
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index 00549d6..b581a9f 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -84,13 +84,18 @@
 // An event handler which records the event's locations.
 class EventLocationRecordingEventHandler : public ui::EventHandler {
  public:
-  explicit EventLocationRecordingEventHandler() { reset(); }
+  EventLocationRecordingEventHandler() { Reset(); }
   ~EventLocationRecordingEventHandler() override = default;
 
-  std::string GetLocationsAndReset() {
-    std::string result = location_.ToString() + " " + root_location_.ToString();
-    reset();
-    return result;
+  // |location_| is relative to the target window.
+  std::string GetLocation() const { return location_.ToString(); }
+
+  // |root_location_| is relative to the display where the event started.
+  std::string GetRootLocation() const { return root_location_.ToString(); }
+
+  void Reset() {
+    location_.SetPoint(-999, -999);
+    root_location_.SetPoint(-999, -999);
   }
 
  private:
@@ -103,11 +108,6 @@
     }
   }
 
-  void reset() {
-    location_.SetPoint(-999, -999);
-    root_location_.SetPoint(-999, -999);
-  }
-
   gfx::Point root_location_;
   gfx::Point location_;
 
@@ -866,35 +866,63 @@
   EXPECT_EQ("abcde", base::UTF16ToASCII(textfield->text()));
 }
 
+// Verifies that clicking in the primary display and dragging to the secondary
+// display correctly sets the event location (window local) and root_location
+// (in screen coordinates) for the mouse event. https://crrev.com/11691010
 TEST_F(ExtendedDesktopTest, PassiveGrab) {
   // This test deals with input events but not visuals so don't throttle input
   // on visuals.
   Shell::Get()->aura_env()->set_throttle_input_on_resize_for_testing(false);
   EventLocationRecordingEventHandler event_handler;
-  ash::Shell::Get()->AddPreTargetHandler(&event_handler);
+  Shell::Get()->AddPreTargetHandler(&event_handler);
 
-  UpdateDisplay("300x300,200x200");
+  // Create large displays so the widget won't be moved after creation.
+  // https://crbug.com/890633
+  UpdateDisplay("1000x1000,1000x1000");
 
   views::Widget* widget = CreateTestWidget(gfx::Rect(50, 50, 200, 200));
   widget->Show();
-  ASSERT_EQ("50,44 200x200", widget->GetWindowBoundsInScreen().ToString());
+  ASSERT_EQ("50,50 200x200", widget->GetWindowBoundsInScreen().ToString());
 
+  // Move the mouse to the center of the window.
   ui::test::EventGenerator* generator = GetEventGenerator();
   generator->MoveMouseTo(150, 150);
-  EXPECT_EQ("100,106 150,150", event_handler.GetLocationsAndReset());
 
+  // Location is relative to the window.
+  EXPECT_EQ("100,100", event_handler.GetLocation());
+
+  // Root location is relative to the display.
+  EXPECT_EQ("150,150", event_handler.GetRootLocation());
+  event_handler.Reset();
+
+  // Drag the mouse to the secondary display. Does not drag the window.
   generator->PressLeftButton();
-  generator->MoveMouseTo(400, 150);
+  generator->MoveMouseBy(1000, 0);
 
-  EXPECT_EQ("350,106 400,150", event_handler.GetLocationsAndReset());
+  // Location is relative to the original window.
+  EXPECT_EQ("1100,100", event_handler.GetLocation());
 
+  // Root location is relative to the original display.
+  EXPECT_EQ("1150,150", event_handler.GetRootLocation());
+  event_handler.Reset();
+
+  // End the drag.
   generator->ReleaseLeftButton();
-  EXPECT_EQ("-999,-999 -999,-999", event_handler.GetLocationsAndReset());
+  EXPECT_EQ("-999,-999", event_handler.GetRootLocation());
+  EXPECT_EQ("-999,-999", event_handler.GetLocation());
+  event_handler.Reset();
 
-  generator->MoveMouseTo(400, 150);
-  EXPECT_EQ("100,6 100,150", event_handler.GetLocationsAndReset());
+  // Move the mouse to the top-left of the secondary display.
+  generator->MoveMouseTo(1001, 1);
 
-  ash::Shell::Get()->RemovePreTargetHandler(&event_handler);
+  // Location is relative to the new display.
+  EXPECT_EQ("1,1", event_handler.GetLocation());
+
+  // Root location is relative to the new display.
+  EXPECT_EQ("1,1", event_handler.GetRootLocation());
+  event_handler.Reset();
+
+  Shell::Get()->RemovePreTargetHandler(&event_handler);
 }
 
 }  // namespace ash
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 261f9a5..f5d5f4e 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -113,24 +113,26 @@
       view));
 }
 
-// Clears the password for the given |LoginPasswordView| instance and then
-// deletes itself.
-class ClearPasswordAnimationObserver : public ui::ImplicitAnimationObserver {
+// Clears the password for the given |LoginPasswordView| instance, hides it, and
+// then deletes itself.
+class ClearPasswordAndHideAnimationObserver
+    : public ui::ImplicitAnimationObserver {
  public:
-  explicit ClearPasswordAnimationObserver(LoginPasswordView* view)
-      : view_(view) {}
-  ~ClearPasswordAnimationObserver() override = default;
+  explicit ClearPasswordAndHideAnimationObserver(LoginPasswordView* view)
+      : password_view_(view) {}
+  ~ClearPasswordAndHideAnimationObserver() override = default;
 
   // ui::ImplicitAnimationObserver:
   void OnImplicitAnimationsCompleted() override {
-    view_->Clear();
+    password_view_->Clear();
+    password_view_->SetVisible(false);
     delete this;
   }
 
  private:
-  LoginPasswordView* view_;
+  LoginPasswordView* const password_view_;
 
-  DISALLOW_COPY_AND_ASSIGN(ClearPasswordAnimationObserver);
+  DISALLOW_COPY_AND_ASSIGN(ClearPasswordAndHideAnimationObserver);
 };
 
 void DecorateOnlineSignInMessage(views::LabelButton* label_button) {
@@ -454,8 +456,13 @@
   SetPaintToLayer(ui::LayerType::LAYER_NOT_DRAWN);
 
   // Build layout.
-  auto* wrapped_password_view =
-      login_views_utils::WrapViewForPreferredSize(password_view_);
+  // Wrap the password view with a fill layout so that it always consumes space,
+  // ie, when the password view is hidden the wrapped view will still consume
+  // the same amount of space. This prevents the user view from shrinking.
+  auto* wrapped_password_view = new NonAccessibleView();
+  wrapped_password_view->SetLayoutManager(
+      std::make_unique<views::FillLayout>());
+  wrapped_password_view->AddChildView(password_view_);
   auto* wrapped_online_sign_in_message_view =
       login_views_utils::WrapViewForPreferredSize(online_sign_in_message_);
   auto* wrapped_disabled_auth_message_view =
@@ -545,7 +552,7 @@
   password_view_->SetEnabled(has_password);
   password_view_->SetEnabledOnEmptyPassword(has_tap);
   password_view_->SetFocusEnabledForChildViews(has_password);
-  password_view_->SetVisible(!hide_auth);
+  password_view_->SetVisible(!hide_auth && has_password);
   password_view_->layer()->SetOpacity(has_password ? 1 : 0);
 
   if (!had_password && has_password)
@@ -646,6 +653,9 @@
     if (!has_password)
       std::swap(opacity_start, opacity_end);
 
+    if (cached_animation_state_->had_password)
+      password_view_->SetVisible(true);
+
     password_view_->layer()->SetOpacity(opacity_start);
 
     {
@@ -656,7 +666,7 @@
       settings.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN);
       if (cached_animation_state_->had_password && !has_password) {
         settings.AddObserver(
-            new ClearPasswordAnimationObserver(password_view_));
+            new ClearPasswordAndHideAnimationObserver(password_view_));
       }
 
       password_view_->layer()->SetOpacity(opacity_end);
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index d9da3c53..b39d1ce 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -327,11 +327,10 @@
 LoginPasswordView::LoginPasswordView() {
   Shell::Get()->ime_controller()->AddObserver(this);
 
-  auto root_layout =
-      std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical);
+  auto* root_layout = SetLayoutManager(
+      std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
   root_layout->set_main_axis_alignment(
       views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
-  SetLayoutManager(std::move(root_layout));
 
   password_row_ = new NonAccessibleView();
 
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc
index 4c85280..5514872 100644
--- a/ash/public/cpp/app_list/app_list_config.cc
+++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -58,8 +58,10 @@
       // TODO(manucornet): Share the value with ShelfConstants and use
       // 48 when the new shelf UI is turned off.
       shelf_height_(56),
-      blur_radius_(30) {
-  if (app_list_features::IsNewStyleLauncherEnabled()) {
+      blur_radius_(30),
+      is_new_style_launcher_enabled_(
+          app_list_features::IsNewStyleLauncherEnabled()) {
+  if (is_new_style_launcher_enabled_) {
     grid_tile_width_ = 120;
     grid_tile_height_ = 112;
     grid_tile_spacing_ = 0;
@@ -122,4 +124,12 @@
   return 0;
 }
 
+int AppListConfig::GetMaxNumOfItemsPerPage(int page) const {
+  // In new style launcher, the first row of first page is no longger suggestion
+  // apps.
+  if (page == 0 && !is_new_style_launcher_enabled_)
+    return preferred_cols_ * (preferred_rows_ - 1);
+  return preferred_cols_ * preferred_rows_;
+}
+
 }  // namespace app_list
diff --git a/ash/public/cpp/app_list/app_list_config.h b/ash/public/cpp/app_list/app_list_config.h
index c8630b5..b78df49c 100644
--- a/ash/public/cpp/app_list/app_list_config.h
+++ b/ash/public/cpp/app_list/app_list_config.h
@@ -140,6 +140,9 @@
   int GetPreferredIconDimension(
       ash::SearchResultDisplayType display_type) const;
 
+  // Returns the maximum number of items allowed in specified page in apps grid.
+  int GetMaxNumOfItemsPerPage(int page) const;
+
  private:
   // The tile view's width and height of the item in apps grid view.
   int grid_tile_width_;
@@ -259,6 +262,9 @@
 
   // The blur radius used in the app list.
   int blur_radius_ = 30;
+
+  // True if new style launcher feature is enabled.
+  const bool is_new_style_launcher_enabled_;
 };
 
 }  // namespace app_list
diff --git a/ash/system/message_center/ash_popup_alignment_delegate.cc b/ash/system/message_center/ash_popup_alignment_delegate.cc
index 5101045..fa314ce 100644
--- a/ash/system/message_center/ash_popup_alignment_delegate.cc
+++ b/ash/system/message_center/ash_popup_alignment_delegate.cc
@@ -10,6 +10,7 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shell.h"
+#include "ash/system/tray/tray_constants.h"
 #include "base/i18n/rtl.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -24,11 +25,6 @@
 
 const int kToastMarginX = 7;
 
-// If there should be no margin for the first item, this value needs to be
-// subtracted to flush the message to the shelf (the width of the border +
-// shadow).
-const int kNoToastMarginBorderAndShadowOffset = 2;
-
 }  // namespace
 
 AshPopupAlignmentDelegate::AshPopupAlignmentDelegate(Shelf* shelf)
@@ -88,7 +84,7 @@
 }
 
 int AshPopupAlignmentDelegate::GetBaseline() const {
-  return work_area_.bottom() - kNoToastMarginBorderAndShadowOffset -
+  return work_area_.bottom() - kUnifiedMenuVerticalPadding -
          tray_bubble_height_;
 }
 
diff --git a/ash/system/unified/user_chooser_view.cc b/ash/system/unified/user_chooser_view.cc
index a86ed2a..471edfe 100644
--- a/ash/system/unified/user_chooser_view.cc
+++ b/ash/system/unified/user_chooser_view.cc
@@ -147,6 +147,9 @@
       Shell::Get()->session_controller()->GetUserSession(user_index);
   DCHECK(user_session);
 
+  if (user_session->user_info->type == user_manager::USER_TYPE_GUEST)
+    return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL);
+
   return l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_USER_INFO_ACCESSIBILITY,
       base::UTF8ToUTF16(user_session->user_info->display_name),
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 1a4c116b0..8a8f69a 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -768,6 +768,8 @@
     "task/sequence_manager/task_queue_task_runner.cc",
     "task/sequence_manager/task_queue_task_runner.h",
     "task/sequence_manager/task_time_observer.h",
+    "task/sequence_manager/tasks.cc",
+    "task/sequence_manager/tasks.h",
     "task/sequence_manager/thread_controller.h",
     "task/sequence_manager/thread_controller_impl.cc",
     "task/sequence_manager/thread_controller_impl.h",
diff --git a/base/task/sequence_manager/lazily_deallocated_deque.h b/base/task/sequence_manager/lazily_deallocated_deque.h
index 7a4d7ba..5ac0883 100644
--- a/base/task/sequence_manager/lazily_deallocated_deque.h
+++ b/base/task/sequence_manager/lazily_deallocated_deque.h
@@ -79,6 +79,7 @@
   // Assumed to be an uncommon operation.
   void push_front(T t) {
     if (!head_) {
+      DCHECK(!tail_);
       head_ = std::make_unique<Ring>(kMinimumRingSize);
       tail_ = head_.get();
     }
@@ -97,6 +98,7 @@
   // Assumed to be a common operation.
   void push_back(T t) {
     if (!head_) {
+      DCHECK(!tail_);
       head_ = std::make_unique<Ring>(kMinimumRingSize);
       tail_ = head_.get();
     }
@@ -132,6 +134,8 @@
   }
 
   void pop_front() {
+    DCHECK(head_);
+    DCHECK(!head_->empty());
     DCHECK(tail_);
     DCHECK_GT(size_, 0u);
     head_->pop_front();
@@ -174,8 +178,8 @@
     // reclaiming it next time.
     max_size_ = size_;
 
-    // Only realloc if the current capacity is sufficiently the observed maximum
-    // size for the previous period.
+    // Only realloc if the current capacity is sufficiently greater than the
+    // observed maximum size for the previous period.
     if (new_capacity + kReclaimThreshold >= capacity())
       return;
 
@@ -313,7 +317,7 @@
     Iterator& operator++() {
       if (index_ == ring_->back_index_) {
         ring_ = ring_->next_.get();
-        index_ = 0;
+        index_ = ring_ ? ring_->CircularIncrement(ring_->front_index_) : 0;
       } else {
         index_ = ring_->CircularIncrement(index_);
       }
diff --git a/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc b/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc
index 49f70289..4a85061 100644
--- a/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc
+++ b/base/task/sequence_manager/lazily_deallocated_deque_unittest.cc
@@ -254,7 +254,7 @@
   }
 }
 
-TEST_F(LazilyDeallocatedDequeTest, SetCapacity) {
+TEST_F(LazilyDeallocatedDequeTest, PushBackThenSetCapacity) {
   LazilyDeallocatedDeque<int> d;
   for (int i = 0; i < 1000; i++) {
     d.push_back(i);
@@ -265,12 +265,82 @@
   // We need 1 more spot than the size due to the way the Ring works.
   d.SetCapacity(1001);
 
+  EXPECT_EQ(1000u, d.size());
+  EXPECT_EQ(0, d.front());
+  EXPECT_EQ(999, d.back());
+
   for (int i = 0; i < 1000; i++) {
     EXPECT_EQ(d.front(), i);
     d.pop_front();
   }
 }
 
+TEST_F(LazilyDeallocatedDequeTest, PushFrontThenSetCapacity) {
+  LazilyDeallocatedDeque<int> d;
+  for (int i = 0; i < 1000; i++) {
+    d.push_front(i);
+  }
+
+  EXPECT_EQ(1336u, d.capacity());
+
+  // We need 1 more spot than the size due to the way the Ring works.
+  d.SetCapacity(1001);
+
+  EXPECT_EQ(1000u, d.size());
+  EXPECT_EQ(999, d.front());
+  EXPECT_EQ(0, d.back());
+
+  for (int i = 0; i < 1000; i++) {
+    EXPECT_EQ(d.front(), 999 - i);
+    d.pop_front();
+  }
+}
+
+TEST_F(LazilyDeallocatedDequeTest, PushFrontThenSetCapacity2) {
+  LazilyDeallocatedDeque<std::unique_ptr<int>> d;
+  for (int i = 0; i < 1000; i++) {
+    d.push_front(std::make_unique<int>(i));
+  }
+
+  EXPECT_EQ(1336u, d.capacity());
+
+  // We need 1 more spot than the size due to the way the Ring works.
+  d.SetCapacity(1001);
+
+  EXPECT_EQ(1000u, d.size());
+  EXPECT_EQ(999, *d.front());
+  EXPECT_EQ(0, *d.back());
+
+  for (int i = 0; i < 1000; i++) {
+    EXPECT_EQ(*d.front(), 999 - i);
+    d.pop_front();
+  }
+}
+
+TEST_F(LazilyDeallocatedDequeTest, PushBackAndFrontThenSetCapacity) {
+  LazilyDeallocatedDeque<int> d;
+
+  int j = 1;
+  for (int i = 0; i < 1000; i++) {
+    d.push_back(j++);
+    d.push_back(j++);
+    d.push_back(j++);
+    d.push_back(j++);
+    d.push_front(-i);
+  }
+
+  d.SetCapacity(5001);
+
+  EXPECT_EQ(5000u, d.size());
+  EXPECT_EQ(-999, d.front());
+  EXPECT_EQ(4000, d.back());
+
+  for (int i = -999; i < 4000; i++) {
+    EXPECT_EQ(d.front(), i);
+    d.pop_front();
+  }
+}
+
 TEST_F(LazilyDeallocatedDequeTest, RingPushFront) {
   LazilyDeallocatedDeque<int>::Ring r(4);
 
@@ -354,6 +424,86 @@
   EXPECT_FALSE(r.CanPop());
 }
 
+TEST_F(LazilyDeallocatedDequeTest, PushAndIterate) {
+  LazilyDeallocatedDeque<int> d;
+
+  for (int i = 0; i < 1000; i++) {
+    d.push_front(i);
+  }
+
+  int expected = 999;
+  for (int value : d) {
+    EXPECT_EQ(expected, value);
+    expected--;
+  }
+}
+
+TEST_F(LazilyDeallocatedDequeTest, Swap) {
+  LazilyDeallocatedDeque<int> a;
+  LazilyDeallocatedDeque<int> b;
+
+  a.push_back(1);
+  a.push_back(2);
+
+  for (int i = 0; i < 1000; i++) {
+    b.push_back(i);
+  }
+
+  EXPECT_EQ(2u, a.size());
+  EXPECT_EQ(1, a.front());
+  EXPECT_EQ(2, a.back());
+  EXPECT_EQ(1000u, b.size());
+  EXPECT_EQ(0, b.front());
+  EXPECT_EQ(999, b.back());
+
+  a.swap(b);
+
+  EXPECT_EQ(1000u, a.size());
+  EXPECT_EQ(0, a.front());
+  EXPECT_EQ(999, a.back());
+  EXPECT_EQ(2u, b.size());
+  EXPECT_EQ(1, b.front());
+  EXPECT_EQ(2, b.back());
+}
+
+class DestructorTestItem {
+ public:
+  DestructorTestItem() : v_(-1) {}
+
+  DestructorTestItem(int v) : v_(v) {}
+
+  ~DestructorTestItem() { destructor_count_++; }
+
+  int v_;
+  static int destructor_count_;
+};
+
+int DestructorTestItem::destructor_count_ = 0;
+
+TEST_F(LazilyDeallocatedDequeTest, PopFrontCallsDestructor) {
+  LazilyDeallocatedDeque<DestructorTestItem> a;
+
+  a.push_front(DestructorTestItem(123));
+
+  DestructorTestItem::destructor_count_ = 0;
+  a.pop_front();
+  EXPECT_EQ(1, DestructorTestItem::destructor_count_);
+}
+
+TEST_F(LazilyDeallocatedDequeTest, ExpectedNumberOfDestructorsCalled) {
+  {
+    LazilyDeallocatedDeque<DestructorTestItem> a;
+
+    for (int i = 0; i < 100; i++) {
+      a.push_front(DestructorTestItem(i));
+    }
+
+    DestructorTestItem::destructor_count_ = 0;
+  }
+
+  EXPECT_EQ(100, DestructorTestItem::destructor_count_);
+}
+
 }  // namespace internal
 }  // namespace sequence_manager
 }  // namespace base
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc
index 8dab9cd0..62cb6585 100644
--- a/base/task/sequence_manager/task_queue.cc
+++ b/base/task/sequence_manager/task_queue.cc
@@ -20,8 +20,6 @@
 
 namespace {
 
-constexpr int kTaskTypeNone = 0;
-
 // TODO(kraynov): Move NullTaskRunner from //base/test to //base.
 scoped_refptr<SingleThreadTaskRunner> CreateNullTaskRunner() {
   return MakeRefCounted<internal::TaskQueueTaskRunner>(
@@ -54,12 +52,13 @@
       TakeTaskQueueImpl());
 }
 
-TaskQueue::Task::Task(TaskQueue::PostedTask task, TimeTicks desired_run_time)
-    : PendingTask(task.posted_from,
-                  std::move(task.callback),
+TaskQueue::Task::Task(internal::PostedTask posted_task,
+                      TimeTicks desired_run_time)
+    : PendingTask(posted_task.location,
+                  std::move(posted_task.callback),
                   desired_run_time,
-                  task.nestable),
-      task_type_(task.task_type) {}
+                  posted_task.nestable),
+      task_type_(posted_task.task_type) {}
 
 TaskQueue::TaskTiming::TaskTiming(bool has_wall_time, bool has_thread_time)
     : has_wall_time_(has_wall_time), has_thread_time_(has_thread_time) {}
@@ -78,26 +77,6 @@
     end_thread_time_ = base::ThreadTicks::Now();
 }
 
-TaskQueue::PostedTask::PostedTask(OnceClosure callback,
-                                  Location posted_from,
-                                  TimeDelta delay,
-                                  Nestable nestable,
-                                  int task_type)
-    : callback(std::move(callback)),
-      posted_from(posted_from),
-      delay(delay),
-      nestable(nestable),
-      task_type(task_type) {}
-
-TaskQueue::PostedTask::PostedTask(PostedTask&& move_from)
-    : callback(std::move(move_from.callback)),
-      posted_from(move_from.posted_from),
-      delay(move_from.delay),
-      nestable(move_from.nestable),
-      task_type(move_from.task_type) {}
-
-TaskQueue::PostedTask::~PostedTask() = default;
-
 void TaskQueue::ShutdownTaskQueue() {
   DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   AutoLock lock(impl_lock_);
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h
index da49983..4b747a8 100644
--- a/base/task/sequence_manager/task_queue.h
+++ b/base/task/sequence_manager/task_queue.h
@@ -15,6 +15,7 @@
 #include "base/synchronization/lock.h"
 #include "base/task/sequence_manager/lazy_now.h"
 #include "base/task/sequence_manager/moveable_auto_lock.h"
+#include "base/task/sequence_manager/tasks.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 
@@ -62,26 +63,6 @@
                                           TimeTicks next_wake_up) = 0;
   };
 
-  // A wrapper around OnceClosure with additional metadata to be passed
-  // to PostTask and plumbed until PendingTask is created.
-  // TODO(kraynov): Move to TaskQueueTaskRunner.
-  struct BASE_EXPORT PostedTask {
-    PostedTask(OnceClosure callback,
-               Location posted_from,
-               TimeDelta delay = TimeDelta(),
-               Nestable nestable = Nestable::kNestable,
-               int task_type = 0);
-    PostedTask(PostedTask&& move_from);
-    PostedTask(const PostedTask& copy_from) = delete;
-    ~PostedTask();
-
-    OnceClosure callback;
-    Location posted_from;
-    TimeDelta delay;
-    Nestable nestable;
-    int task_type;
-  };
-
   // Prepare the task queue to get released.
   // All tasks posted after this call will be discarded.
   virtual void ShutdownTaskQueue();
@@ -147,10 +128,12 @@
     bool should_notify_observers;
   };
 
-  // Interface to pass per-task metadata to RendererScheduler.
+  // Interface to inspect task type by a scheduler controlling SequenceManager.
+  // TODO(kraynov): Merge with TaskQueueImpl::Task (keeping enqueue order
+  // private with friend classes) and move to tasks.(h|cc).
   class BASE_EXPORT Task : public PendingTask {
    public:
-    Task(PostedTask posted_task, TimeTicks desired_run_time);
+    Task(internal::PostedTask posted_task, TimeTicks desired_run_time);
 
     int task_type() const { return task_type_; }
 
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
index d3c5878d..bc361dda 100644
--- a/base/task/sequence_manager/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -73,7 +73,7 @@
 #endif
 }
 
-TaskQueueImpl::Task::Task(TaskQueue::PostedTask task,
+TaskQueueImpl::Task::Task(PostedTask task,
                           TimeTicks desired_run_time,
                           EnqueueOrder sequence_number)
     : TaskQueue::Task(std::move(task), desired_run_time) {
@@ -81,7 +81,7 @@
   sequence_num = static_cast<int>(sequence_number);
 }
 
-TaskQueueImpl::Task::Task(TaskQueue::PostedTask task,
+TaskQueueImpl::Task::Task(PostedTask task,
                           TimeTicks desired_run_time,
                           EnqueueOrder sequence_number,
                           EnqueueOrder enqueue_order)
@@ -180,7 +180,7 @@
   return PlatformThread::CurrentId() == associated_thread_->thread_id;
 }
 
-void TaskQueueImpl::PostTask(TaskQueue::PostedTask task) {
+void TaskQueueImpl::PostTask(PostedTask task) {
   // This method can only be called if task queue is able to accept tasks,
   // i.e. has a sequence manager and not being unregistered. This is enforced
   // by |proxy_| which is detached if this condition not met.
@@ -191,7 +191,7 @@
   }
 }
 
-void TaskQueueImpl::PostImmediateTaskImpl(TaskQueue::PostedTask task) {
+void TaskQueueImpl::PostImmediateTaskImpl(PostedTask task) {
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
   // for details.
   CHECK(task.callback);
@@ -206,7 +206,7 @@
                                             sequence_number, sequence_number));
 }
 
-void TaskQueueImpl::PostDelayedTaskImpl(TaskQueue::PostedTask task) {
+void TaskQueueImpl::PostDelayedTaskImpl(PostedTask task) {
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
   // for details.
   CHECK(task.callback);
@@ -259,13 +259,13 @@
   EnqueueOrder thread_hop_task_sequence_number =
       any_thread().sequence_manager->GetNextSequenceNumber();
   // TODO(altimin): Add a copy method to Task to capture metadata here.
-  PushOntoImmediateIncomingQueueLocked(Task(
-      TaskQueue::PostedTask(BindOnce(&TaskQueueImpl::ScheduleDelayedWorkTask,
-                                     Unretained(this), std::move(pending_task)),
-                            FROM_HERE, TimeDelta(), Nestable::kNonNestable,
-                            pending_task.task_type()),
-      TimeTicks(), thread_hop_task_sequence_number,
-      thread_hop_task_sequence_number));
+  PushOntoImmediateIncomingQueueLocked(
+      Task(PostedTask(BindOnce(&TaskQueueImpl::ScheduleDelayedWorkTask,
+                               Unretained(this), std::move(pending_task)),
+                      FROM_HERE, TimeDelta(), Nestable::kNonNestable,
+                      pending_task.task_type()),
+           TimeTicks(), thread_hop_task_sequence_number,
+           thread_hop_task_sequence_number));
 }
 
 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) {
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index 27229b3..5fb05b84 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -98,7 +98,7 @@
       if (time == other.time) {
         // Debug gcc builds can compare an element against itself.
         DCHECK(sequence_num != other.sequence_num || this == &other);
-        // |PostedTask::sequence_num| is int and might wrap around to
+        // |PendingTask::sequence_num| is int and might wrap around to
         // a negative number when casted from EnqueueOrder.
         // This way of comparison handles that properly.
         return (sequence_num - other.sequence_num) <= 0;
@@ -109,11 +109,11 @@
 
   class BASE_EXPORT Task : public TaskQueue::Task {
    public:
-    Task(TaskQueue::PostedTask task,
+    Task(PostedTask task,
          TimeTicks desired_run_time,
          EnqueueOrder sequence_number);
 
-    Task(TaskQueue::PostedTask task,
+    Task(PostedTask task,
          TimeTicks desired_run_time,
          EnqueueOrder sequence_number,
          EnqueueOrder enqueue_order);
@@ -172,7 +172,7 @@
   // TaskQueue implementation.
   const char* GetName() const;
   bool RunsTasksInCurrentSequence() const;
-  void PostTask(TaskQueue::PostedTask task);
+  void PostTask(PostedTask task);
   // Require a reference to enclosing task queue for lifetime control.
   std::unique_ptr<TaskQueue::QueueEnabledVoter> CreateQueueEnabledVoter(
       scoped_refptr<TaskQueue> owning_task_queue);
@@ -360,8 +360,8 @@
     bool is_enabled_for_test;
   };
 
-  void PostImmediateTaskImpl(TaskQueue::PostedTask task);
-  void PostDelayedTaskImpl(TaskQueue::PostedTask task);
+  void PostImmediateTaskImpl(PostedTask task);
+  void PostDelayedTaskImpl(PostedTask task);
 
   // Push the task onto the |delayed_incoming_queue|. Lock-free main thread
   // only fast path.
diff --git a/base/task/sequence_manager/task_queue_proxy.cc b/base/task/sequence_manager/task_queue_proxy.cc
index 4da4d1b..3a2abf0a 100644
--- a/base/task/sequence_manager/task_queue_proxy.cc
+++ b/base/task/sequence_manager/task_queue_proxy.cc
@@ -20,7 +20,7 @@
 
 TaskQueueProxy::~TaskQueueProxy() = default;
 
-bool TaskQueueProxy::PostTask(TaskQueue::PostedTask task) const {
+bool TaskQueueProxy::PostTask(PostedTask task) const {
   // NOTE: Task's destructor might attempt to post another task,
   // so ensure it never happens inside this lock.
   Optional<MoveableAutoLock> lock(AcquireLockIfNeeded());
diff --git a/base/task/sequence_manager/task_queue_proxy.h b/base/task/sequence_manager/task_queue_proxy.h
index ccdc7536..3c68eec 100644
--- a/base/task/sequence_manager/task_queue_proxy.h
+++ b/base/task/sequence_manager/task_queue_proxy.h
@@ -10,6 +10,7 @@
 #include "base/synchronization/lock.h"
 #include "base/task/sequence_manager/moveable_auto_lock.h"
 #include "base/task/sequence_manager/task_queue.h"
+#include "base/task/sequence_manager/tasks.h"
 
 namespace base {
 namespace sequence_manager {
@@ -30,7 +31,7 @@
                  scoped_refptr<AssociatedThreadId> associated_thread);
 
   // May be called on any thread.
-  bool PostTask(TaskQueue::PostedTask task) const;
+  bool PostTask(PostedTask task) const;
   bool RunsTasksInCurrentSequence() const;
 
   // PostTask will reject any task after this call.
diff --git a/base/task/sequence_manager/task_queue_selector_unittest.cc b/base/task/sequence_manager/task_queue_selector_unittest.cc
index bf88408..0a41733 100644
--- a/base/task/sequence_manager/task_queue_selector_unittest.cc
+++ b/base/task/sequence_manager/task_queue_selector_unittest.cc
@@ -116,8 +116,8 @@
     for (size_t i = 0; i < num_tasks; i++) {
       changed_queue_set.insert(queue_indices[i]);
       task_queues_[queue_indices[i]]->immediate_work_queue()->Push(
-          TaskQueueImpl::Task(TaskQueue::PostedTask(test_closure_, FROM_HERE),
-                              TimeTicks(), EnqueueOrder(),
+          TaskQueueImpl::Task(PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+                              EnqueueOrder(),
                               enqueue_order_generator.GenerateNext()));
     }
   }
@@ -130,8 +130,7 @@
       changed_queue_set.insert(queue_indices[i]);
       task_queues_[queue_indices[i]]->immediate_work_queue()->Push(
           TaskQueueImpl::Task(
-              TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
-              EnqueueOrder(),
+              PostedTask(test_closure_, FROM_HERE), TimeTicks(), EnqueueOrder(),
               EnqueueOrder::FromIntForTesting(enqueue_orders[i])));
     }
   }
@@ -738,9 +737,9 @@
 }
 
 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) {
-  task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task(
-      TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
-      EnqueueOrder(), EnqueueOrder::FromIntForTesting(2)));
+  task_queues_[0]->delayed_work_queue()->Push(
+      TaskQueueImpl::Task(PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+                          EnqueueOrder(), EnqueueOrder::FromIntForTesting(2)));
 
   WorkQueue* chosen_work_queue = nullptr;
   bool chose_delayed_over_immediate = false;
@@ -752,9 +751,9 @@
 }
 
 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) {
-  task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task(
-      TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
-      EnqueueOrder(), EnqueueOrder::FromIntForTesting(2)));
+  task_queues_[0]->immediate_work_queue()->Push(
+      TaskQueueImpl::Task(PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+                          EnqueueOrder(), EnqueueOrder::FromIntForTesting(2)));
 
   WorkQueue* chosen_work_queue = nullptr;
   bool chose_delayed_over_immediate = false;
@@ -778,9 +777,8 @@
   task_queue->SetQueueEnabledForTest(false);
   selector.DisableQueue(task_queue.get());
 
-  TaskQueueImpl::Task task(TaskQueue::PostedTask(test_closure_, FROM_HERE),
-                           TimeTicks(), EnqueueOrder(),
-                           EnqueueOrder::FromIntForTesting(2));
+  TaskQueueImpl::Task task(PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+                           EnqueueOrder(), EnqueueOrder::FromIntForTesting(2));
   task_queue->immediate_work_queue()->Push(std::move(task));
 
   WorkQueue* chosen_work_queue;
@@ -809,11 +807,11 @@
 
   selector.SetQueuePriority(task_queue2.get(), TaskQueue::kControlPriority);
 
-  TaskQueueImpl::Task task1(TaskQueue::PostedTask(test_closure_, FROM_HERE),
-                            TimeTicks(), EnqueueOrder::FromIntForTesting(2),
+  TaskQueueImpl::Task task1(PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+                            EnqueueOrder::FromIntForTesting(2),
                             EnqueueOrder::FromIntForTesting(2));
-  TaskQueueImpl::Task task2(TaskQueue::PostedTask(test_closure_, FROM_HERE),
-                            TimeTicks(), EnqueueOrder::FromIntForTesting(3),
+  TaskQueueImpl::Task task2(PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+                            EnqueueOrder::FromIntForTesting(3),
                             EnqueueOrder::FromIntForTesting(3));
   task_queue->immediate_work_queue()->Push(std::move(task1));
   task_queue2->immediate_work_queue()->Push(std::move(task2));
@@ -859,13 +857,13 @@
 
 TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) {
   task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task(
-      TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+      PostedTask(test_closure_, FROM_HERE), TimeTicks(),
       EnqueueOrder::FromIntForTesting(GetParam().immediate_task_enqueue_order),
       EnqueueOrder::FromIntForTesting(
           GetParam().immediate_task_enqueue_order)));
 
   task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task(
-      TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
+      PostedTask(test_closure_, FROM_HERE), TimeTicks(),
       EnqueueOrder::FromIntForTesting(GetParam().delayed_task_enqueue_order),
       EnqueueOrder::FromIntForTesting(GetParam().delayed_task_enqueue_order)));
 
diff --git a/base/task/sequence_manager/task_queue_task_runner.cc b/base/task/sequence_manager/task_queue_task_runner.cc
index b1b7975..a82b1476 100644
--- a/base/task/sequence_manager/task_queue_task_runner.cc
+++ b/base/task/sequence_manager/task_queue_task_runner.cc
@@ -21,16 +21,16 @@
 bool TaskQueueTaskRunner::PostDelayedTask(const Location& location,
                                           OnceClosure callback,
                                           TimeDelta delay) {
-  return task_queue_proxy_->PostTask(TaskQueue::PostedTask(
+  return task_queue_proxy_->PostTask(PostedTask(
       std::move(callback), location, delay, Nestable::kNestable, task_type_));
 }
 
 bool TaskQueueTaskRunner::PostNonNestableDelayedTask(const Location& location,
                                                      OnceClosure callback,
                                                      TimeDelta delay) {
-  return task_queue_proxy_->PostTask(
-      TaskQueue::PostedTask(std::move(callback), location, delay,
-                            Nestable::kNonNestable, task_type_));
+  return task_queue_proxy_->PostTask(PostedTask(std::move(callback), location,
+                                                delay, Nestable::kNonNestable,
+                                                task_type_));
 }
 
 bool TaskQueueTaskRunner::RunsTasksInCurrentSequence() const {
diff --git a/base/task/sequence_manager/tasks.cc b/base/task/sequence_manager/tasks.cc
new file mode 100644
index 0000000..6ff7a18
--- /dev/null
+++ b/base/task/sequence_manager/tasks.cc
@@ -0,0 +1,33 @@
+// Copyright 2018 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/task/sequence_manager/tasks.h"
+
+namespace base {
+namespace sequence_manager {
+namespace internal {
+
+PostedTask::PostedTask(OnceClosure callback,
+                       Location location,
+                       TimeDelta delay,
+                       Nestable nestable,
+                       int task_type)
+    : callback(std::move(callback)),
+      location(location),
+      delay(delay),
+      nestable(nestable),
+      task_type(task_type) {}
+
+PostedTask::PostedTask(PostedTask&& move_from) noexcept
+    : callback(std::move(move_from.callback)),
+      location(move_from.location),
+      delay(move_from.delay),
+      nestable(move_from.nestable),
+      task_type(move_from.task_type) {}
+
+PostedTask::~PostedTask() = default;
+
+}  // namespace internal
+}  // namespace sequence_manager
+}  // namespace base
diff --git a/base/task/sequence_manager/tasks.h b/base/task/sequence_manager/tasks.h
new file mode 100644
index 0000000..b227028e
--- /dev/null
+++ b/base/task/sequence_manager/tasks.h
@@ -0,0 +1,43 @@
+// Copyright 2018 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 BASE_TASK_SEQUENCE_MANAGER_TASKS_H_
+#define BASE_TASK_SEQUENCE_MANAGER_TASKS_H_
+
+#include "base/pending_task.h"
+
+namespace base {
+namespace sequence_manager {
+
+constexpr int kTaskTypeNone = 0;
+
+// TODO(kraynov): Move TaskQueue::Task here.
+
+namespace internal {
+
+// Wrapper around PostTask method arguments and the assigned task type.
+// Eventually it becomes a PendingTask once accepted by a TaskQueueImpl.
+struct BASE_EXPORT PostedTask {
+  explicit PostedTask(OnceClosure callback = OnceClosure(),
+                      Location location = Location(),
+                      TimeDelta delay = TimeDelta(),
+                      Nestable nestable = Nestable::kNestable,
+                      int task_type = kTaskTypeNone);
+  PostedTask(PostedTask&& move_from) noexcept;
+  ~PostedTask();
+
+  OnceClosure callback;
+  Location location;
+  TimeDelta delay;
+  Nestable nestable;
+  int task_type;
+
+  DISALLOW_COPY_AND_ASSIGN(PostedTask);
+};
+
+}  // namespace internal
+}  // namespace sequence_manager
+}  // namespace base
+
+#endif  // BASE_TASK_SEQUENCE_MANAGER_TASKS_H_
diff --git a/base/task/sequence_manager/test/fake_task.cc b/base/task/sequence_manager/test/fake_task.cc
index 5f67474..e87cb4b 100644
--- a/base/task/sequence_manager/test/fake_task.cc
+++ b/base/task/sequence_manager/test/fake_task.cc
@@ -10,11 +10,11 @@
 FakeTask::FakeTask() : FakeTask(0 /* task_type */) {}
 
 FakeTask::FakeTask(int task_type)
-    : TaskQueue::Task(TaskQueue::PostedTask(OnceClosure(),
-                                            FROM_HERE,
-                                            TimeDelta(),
-                                            Nestable::kNestable,
-                                            task_type),
+    : TaskQueue::Task(internal::PostedTask(OnceClosure(),
+                                           FROM_HERE,
+                                           TimeDelta(),
+                                           Nestable::kNestable,
+                                           task_type),
                       TimeTicks()) {}
 
 FakeTaskTiming::FakeTaskTiming()
diff --git a/base/task/sequence_manager/work_queue_sets_unittest.cc b/base/task/sequence_manager/work_queue_sets_unittest.cc
index b849eec..cc33de4 100644
--- a/base/task/sequence_manager/work_queue_sets_unittest.cc
+++ b/base/task/sequence_manager/work_queue_sets_unittest.cc
@@ -45,15 +45,15 @@
 
   TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) {
     TaskQueueImpl::Task fake_task(
-        TaskQueue::PostedTask(BindOnce([] {}), FROM_HERE), TimeTicks(),
-        EnqueueOrder(), EnqueueOrder::FromIntForTesting(enqueue_order));
+        PostedTask(BindOnce([] {}), FROM_HERE), TimeTicks(), EnqueueOrder(),
+        EnqueueOrder::FromIntForTesting(enqueue_order));
     return fake_task;
   }
 
   TaskQueueImpl::Task FakeNonNestableTaskWithEnqueueOrder(int enqueue_order) {
     TaskQueueImpl::Task fake_task(
-        TaskQueue::PostedTask(BindOnce([] {}), FROM_HERE), TimeTicks(),
-        EnqueueOrder(), EnqueueOrder::FromIntForTesting(enqueue_order));
+        PostedTask(BindOnce([] {}), FROM_HERE), TimeTicks(), EnqueueOrder(),
+        EnqueueOrder::FromIntForTesting(enqueue_order));
     fake_task.nestable = Nestable::kNonNestable;
     return fake_task;
   }
diff --git a/base/task/sequence_manager/work_queue_unittest.cc b/base/task/sequence_manager/work_queue_unittest.cc
index a71cebca..9aec1a5 100644
--- a/base/task/sequence_manager/work_queue_unittest.cc
+++ b/base/task/sequence_manager/work_queue_unittest.cc
@@ -51,8 +51,7 @@
       int enqueue_order,
       WeakPtr<Cancelable> weak_ptr) {
     TaskQueueImpl::Task fake_task(
-        TaskQueue::PostedTask(BindOnce(&Cancelable::NopTask, weak_ptr),
-                              FROM_HERE),
+        PostedTask(BindOnce(&Cancelable::NopTask, weak_ptr), FROM_HERE),
         TimeTicks(), EnqueueOrder(),
         EnqueueOrder::FromIntForTesting(enqueue_order));
     return fake_task;
@@ -60,15 +59,15 @@
 
   TaskQueueImpl::Task FakeTaskWithEnqueueOrder(int enqueue_order) {
     TaskQueueImpl::Task fake_task(
-        TaskQueue::PostedTask(BindOnce(&NopTask), FROM_HERE), TimeTicks(),
-        EnqueueOrder(), EnqueueOrder::FromIntForTesting(enqueue_order));
+        PostedTask(BindOnce(&NopTask), FROM_HERE), TimeTicks(), EnqueueOrder(),
+        EnqueueOrder::FromIntForTesting(enqueue_order));
     return fake_task;
   }
 
   TaskQueueImpl::Task FakeNonNestableTaskWithEnqueueOrder(int enqueue_order) {
     TaskQueueImpl::Task fake_task(
-        TaskQueue::PostedTask(BindOnce(&NopTask), FROM_HERE), TimeTicks(),
-        EnqueueOrder(), EnqueueOrder::FromIntForTesting(enqueue_order));
+        PostedTask(BindOnce(&NopTask), FROM_HERE), TimeTicks(), EnqueueOrder(),
+        EnqueueOrder::FromIntForTesting(enqueue_order));
     fake_task.nestable = Nestable::kNonNestable;
     return fake_task;
   }
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index d9a4f86..fb12cf6 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -8917,5 +8917,40 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNewLocalSurfaceIdForcesDraw);
 
+// Verifies that DidReceiveCompositorFrameAck does not get sent with PostTask
+// when not needed.
+class DidReceiveCompositorFrameAckNotSentWhenNotNeeded
+    : public LayerTreeHostTest {
+ public:
+  DidReceiveCompositorFrameAckNotSentWhenNotNeeded() {}
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->send_compositor_frame_ack = false;
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DidReceiveCompositorFrameAck() override { ADD_FAILURE(); }
+
+  // DrawLayersOnThread gets called after the conditional call to
+  // DidReceiveCompositorFrameAck, so we wait for it to end the test.
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    if (!received_first_frame_) {
+      received_first_frame_ = true;
+      PostSetNeedsCommitToMainThread();
+    } else {
+      EndTest();
+    }
+  }
+
+  void AfterTest() override {}
+
+ private:
+  bool received_first_frame_ = false;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    DidReceiveCompositorFrameAckNotSentWhenNotNeeded);
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index e1240350..389e25b 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -160,6 +160,11 @@
   // When false, sync tokens are expected to be present, and are verified,
   // before transfering gpu resources to the display compositor.
   bool delegated_sync_points_required = true;
+
+  // When true, LayerTreeHostImplClient will be posting a task to call
+  // DidReceiveCompositorFrameAck, used by the Compositor but not the
+  // LayerTreeView.
+  bool send_compositor_frame_ack = true;
 };
 
 }  // namespace cc
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 966124c..6aff668 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -69,6 +69,7 @@
 
   host_impl_ = layer_tree_host->CreateLayerTreeHostImpl(this);
   const LayerTreeSettings& settings = layer_tree_host->GetSettings();
+  send_compositor_frame_ack_ = settings.send_compositor_frame_ack;
 
   SchedulerSettings scheduler_settings(settings.ToSchedulerSettings());
 
@@ -291,9 +292,11 @@
                "ProxyImpl::DidReceiveCompositorFrameAckOnImplThread");
   DCHECK(IsImplThread());
   scheduler_->DidReceiveCompositorFrameAck();
-  MainThreadTaskRunner()->PostTask(
-      FROM_HERE, base::BindOnce(&ProxyMain::DidReceiveCompositorFrameAck,
-                                proxy_main_frame_sink_bound_weak_ptr_));
+  if (send_compositor_frame_ack_) {
+    MainThreadTaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(&ProxyMain::DidReceiveCompositorFrameAck,
+                                  proxy_main_frame_sink_bound_weak_ptr_));
+  }
 }
 
 void ProxyImpl::OnCanDrawStateChanged(bool can_draw) {
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index a6b9fa2..4bfbf73 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -153,6 +153,8 @@
   bool inside_draw_;
   bool input_throttled_until_commit_;
 
+  bool send_compositor_frame_ack_;
+
   TaskRunnerProvider* task_runner_provider_;
 
   DelayedUniqueNotifier smoothness_priority_expiration_notifier_;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 38e774a2..8e79bbb 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -442,12 +442,14 @@
                "SingleThreadProxy::DidReceiveCompositorFrameAckOnImplThread");
   if (scheduler_on_impl_thread_)
     scheduler_on_impl_thread_->DidReceiveCompositorFrameAck();
-  // We do a PostTask here because freeing resources in some cases (such as in
-  // TextureLayer) is PostTasked and we want to make sure ack is received after
-  // resources are returned.
-  task_runner_provider_->MainThreadTaskRunner()->PostTask(
-      FROM_HERE, base::Bind(&SingleThreadProxy::DidReceiveCompositorFrameAck,
-                            frame_sink_bound_weak_ptr_));
+  if (layer_tree_host_->GetSettings().send_compositor_frame_ack) {
+    // We do a PostTask here because freeing resources in some cases (such as in
+    // TextureLayer) is PostTasked and we want to make sure ack is received
+    // after resources are returned.
+    task_runner_provider_->MainThreadTaskRunner()->PostTask(
+        FROM_HERE, base::Bind(&SingleThreadProxy::DidReceiveCompositorFrameAck,
+                              frame_sink_bound_weak_ptr_));
+  }
 }
 
 void SingleThreadProxy::OnDrawForLayerTreeFrameSink(
diff --git a/chrome/android/java/res/layout-sw600dp/location_bar.xml b/chrome/android/java/res/layout-sw600dp/location_bar.xml
index 5c2a4b7..47d81308 100644
--- a/chrome/android/java/res/layout-sw600dp/location_bar.xml
+++ b/chrome/android/java/res/layout-sw600dp/location_bar.xml
@@ -20,7 +20,7 @@
             android:src="@drawable/ic_omnibox_page"
             android:scaleType="center"
             android:contentDescription="@string/accessibility_toolbar_btn_site_info"/>
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/security_button"
             style="@style/LocationBarButton"
             android:layout_width="match_parent"
@@ -29,7 +29,7 @@
             android:layout_gravity="center"
             android:alpha="0"
             android:visibility="invisible"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
     </FrameLayout>
 
     <include layout="@layout/location_bar_status" />
diff --git a/chrome/android/java/res/layout/accept_languages_item.xml b/chrome/android/java/res/layout/accept_languages_item.xml
index dd9fd20a..48c794e 100644
--- a/chrome/android/java/res/layout/accept_languages_item.xml
+++ b/chrome/android/java/res/layout/accept_languages_item.xml
@@ -13,10 +13,10 @@
     android:paddingEnd="@dimen/pref_languages_padding"
     style="@style/ListItemContainer">
 
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/icon_view"
         style="@style/ListItemStartIcon"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 
     <LinearLayout
         android:layout_width="0dp"
@@ -48,6 +48,6 @@
         android:background="@null"
         android:src="@drawable/ic_more_vert_black_24dp"
         app:menuWidth="@dimen/pref_languages_item_popup_width"
-        app:chrometint="@color/dark_mode_tint"
+        app:tint="@color/dark_mode_tint"
         tools:ignore="ContentDescription" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/accessibility_tab_switcher.xml b/chrome/android/java/res/layout/accessibility_tab_switcher.xml
index a8ba536d..7b2057b 100644
--- a/chrome/android/java/res/layout/accessibility_tab_switcher.xml
+++ b/chrome/android/java/res/layout/accessibility_tab_switcher.xml
@@ -54,14 +54,14 @@
         android:id="@+id/button_wrapper"
         android:visibility="gone">
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/standard_tabs_button"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:background="@drawable/btn_bg_holo_active"
             android:src="@drawable/btn_normal_tabs"
-            app:chrometint="@color/light_mode_tint"
+            app:tint="@color/light_mode_tint"
             android:contentDescription="@string/accessibility_tab_switcher_standard_stack"
             style="?android:attr/borderlessButtonStyle" />
 
@@ -71,13 +71,13 @@
             android:layout_gravity="center_vertical"
             android:background="#292929" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/incognito_tabs_button"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:src="@drawable/btn_incognito_tabs"
-            app:chrometint="@color/light_mode_tint"
+            app:tint="@color/light_mode_tint"
             android:background="@drawable/btn_bg_holo"
             android:contentDescription="@string/accessibility_tab_switcher_incognito_stack"
             style="?android:attr/borderlessButtonStyle" />
diff --git a/chrome/android/java/res/layout/accessibility_tab_switcher_list_item.xml b/chrome/android/java/res/layout/accessibility_tab_switcher_list_item.xml
index cf23a9b..62e6b35 100644
--- a/chrome/android/java/res/layout/accessibility_tab_switcher_list_item.xml
+++ b/chrome/android/java/res/layout/accessibility_tab_switcher_list_item.xml
@@ -9,7 +9,6 @@
 <org.chromium.chrome.browser.widget.accessibility.AccessibilityTabModelListItem
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/list_item_frame"
     android:layout_width="match_parent"
     android:layout_height="@dimen/accessibility_tab_height">
@@ -20,13 +19,13 @@
         <include layout="@layout/modern_list_item_view" />
 
         <!-- TODO(huayinz): Remove custom padding after https://crbug.com/746712 is fixed. -->
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/close_btn_modern"
             style="@style/ListItemEndIconSmall"
             android:paddingStart="23dp"
             android:paddingEnd="13dp"
             android:src="@drawable/btn_delete_24dp"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
     </LinearLayout>
 
     <LinearLayout
diff --git a/chrome/android/java/res/layout/bottom_toolbar.xml b/chrome/android/java/res/layout/bottom_toolbar.xml
index c84fd09..f69fdcfa 100644
--- a/chrome/android/java/res/layout/bottom_toolbar.xml
+++ b/chrome/android/java/res/layout/bottom_toolbar.xml
@@ -5,12 +5,11 @@
 
 <org.chromium.chrome.browser.toolbar.ScrollingBottomViewResourceFrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/bottom_toolbar_control_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="@dimen/bottom_toolbar_height" >
+    android:minHeight="@dimen/bottom_toolbar_height">
 
     <ImageView
         android:id="@+id/bottom_toolbar_top_shadow"
@@ -40,7 +39,7 @@
                 android:layout_height="1dp"
                 android:layout_weight="1" />
 
-            <org.chromium.chrome.browser.widget.TintedImageButton
+            <android.support.v7.widget.AppCompatImageButton
                 android:id="@+id/first_button"
                 style="@style/ToolbarButton"
                 android:layout_gravity="center" />
@@ -50,7 +49,7 @@
                 android:layout_height="1dp"
                 android:layout_weight="1" />
 
-            <org.chromium.chrome.browser.widget.TintedImageButton
+            <android.support.v7.widget.AppCompatImageButton
                 android:id="@+id/second_button"
                 style="@style/ToolbarButton"
                 android:layout_gravity="center" />
diff --git a/chrome/android/java/res/layout/chip.xml b/chrome/android/java/res/layout/chip.xml
index 2bcb5390..d158383 100644
--- a/chrome/android/java/res/layout/chip.xml
+++ b/chrome/android/java/res/layout/chip.xml
@@ -13,14 +13,14 @@
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:background="@drawable/chip_bg">
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/icon"
         android:layout_width="20dp"
         android:layout_height="20dp"
         android:layout_marginStart="8dp"
         android:gravity="center"
         android:scaleType="fitCenter"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
     <TextView
         android:id="@+id/text"
         android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/layout/clear_storage.xml b/chrome/android/java/res/layout/clear_storage.xml
index de067072..671db1d9 100644
--- a/chrome/android/java/res/layout/clear_storage.xml
+++ b/chrome/android/java/res/layout/clear_storage.xml
@@ -3,11 +3,11 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<org.chromium.chrome.browser.widget.TintedImageView
+<android.support.v7.widget.AppCompatImageView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:contentDescription="@string/webstorage_clear_data_dialog_title"
     android:src="@drawable/ic_delete_white_24dp"
-    app:chrometint="@color/blue_mode_tint"/>
+    app:tint="@color/blue_mode_tint"/>
diff --git a/chrome/android/java/res/layout/content_suggestions_card_modern_reversed.xml b/chrome/android/java/res/layout/content_suggestions_card_modern_reversed.xml
index 7d81b4b..a330626 100644
--- a/chrome/android/java/res/layout/content_suggestions_card_modern_reversed.xml
+++ b/chrome/android/java/res/layout/content_suggestions_card_modern_reversed.xml
@@ -100,7 +100,7 @@
             </LinearLayout>
         </LinearLayout>
 
-        <org.chromium.chrome.browser.widget.TintedImageView
+        <android.support.v7.widget.AppCompatImageView
             android:id="@+id/article_thumbnail"
             android:layout_width="@dimen/snippets_thumbnail_size"
             android:layout_height="@dimen/snippets_thumbnail_size"
diff --git a/chrome/android/java/res/layout/contextual_suggestions_card_modern.xml b/chrome/android/java/res/layout/contextual_suggestions_card_modern.xml
index e8baf25..a5f55d9 100644
--- a/chrome/android/java/res/layout/contextual_suggestions_card_modern.xml
+++ b/chrome/android/java/res/layout/contextual_suggestions_card_modern.xml
@@ -99,7 +99,6 @@
                 android:layout_marginStart="6dp"
                 android:contentDescription="@string/accessibility_ntp_offline_badge"
                 android:visibility="gone"
-                android:src="@drawable/offline_pin_round"
-                app:chrometint="@color/default_icon_color" />
+                android:src="@drawable/offline_pin_round" />
         </LinearLayout>
 </RelativeLayout>
diff --git a/chrome/android/java/res/layout/contextual_suggestions_card_modern_alternate.xml b/chrome/android/java/res/layout/contextual_suggestions_card_modern_alternate.xml
index 3dbfc54..22d1da9 100644
--- a/chrome/android/java/res/layout/contextual_suggestions_card_modern_alternate.xml
+++ b/chrome/android/java/res/layout/contextual_suggestions_card_modern_alternate.xml
@@ -67,8 +67,7 @@
             android:layout_marginStart="6dp"
             android:contentDescription="@string/accessibility_ntp_offline_badge"
             android:visibility="gone"
-            android:src="@drawable/offline_pin_round"
-            app:chrometint="@color/default_icon_color" />
+            android:src="@drawable/offline_pin_round" />
     </LinearLayout>
 
     <LinearLayout
diff --git a/chrome/android/java/res/layout/contextual_suggestions_toolbar.xml b/chrome/android/java/res/layout/contextual_suggestions_toolbar.xml
index 928d7c4..797e7def 100644
--- a/chrome/android/java/res/layout/contextual_suggestions_toolbar.xml
+++ b/chrome/android/java/res/layout/contextual_suggestions_toolbar.xml
@@ -45,10 +45,10 @@
             android:layout_height="match_parent"
             android:background="?attr/selectableItemBackground"
             android:src="@drawable/ic_more_vert_black_24dp"
-            app:chrometint="@color/dark_mode_tint"
+            app:tint="@color/dark_mode_tint"
             tools:ignore="ContentDescription" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/close_button"
             android:layout_height="match_parent"
             android:layout_width="@dimen/contextual_suggestions_toolbar_icon_size"
@@ -56,7 +56,7 @@
             android:src="@drawable/btn_close"
             android:scaleType="center"
             android:contentDescription="@string/contextual_suggestions_close_button_description"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
    </LinearLayout>
 
    <ImageView
diff --git a/chrome/android/java/res/layout/custom_tabs_toolbar.xml b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
index 981f544..efae5b1 100644
--- a/chrome/android/java/res/layout/custom_tabs_toolbar.xml
+++ b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
@@ -19,7 +19,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical" >
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/security_button"
             style="@style/LocationBarButton"
             android:layout_width="@dimen/location_bar_icon_width"
@@ -27,7 +27,7 @@
             android:layout_gravity="center_vertical"
             android:scaleType="center"
             android:visibility="invisible"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
         <view
             class="org.chromium.chrome.browser.toolbar.CustomTabToolbar$InterceptTouchLayout"
             android:id="@+id/title_url_container"
@@ -96,7 +96,7 @@
         android:layout_gravity="center_vertical|end"
         android:gravity="center_vertical"
         android:orientation="horizontal" />
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/menu_button"
         style="@style/ToolbarButton"
         android:layout_gravity="center_vertical|end"
@@ -105,5 +105,5 @@
         android:src="@drawable/ic_more_vert_black_24dp"
         android:contentDescription="@string/accessibility_toolbar_btn_menu"
         android:background="@null"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 </org.chromium.chrome.browser.toolbar.CustomTabToolbar>
diff --git a/chrome/android/java/res/layout/empty_background_view_tablet.xml b/chrome/android/java/res/layout/empty_background_view_tablet.xml
index 212b92a..dd8806e6 100644
--- a/chrome/android/java/res/layout/empty_background_view_tablet.xml
+++ b/chrome/android/java/res/layout/empty_background_view_tablet.xml
@@ -43,7 +43,7 @@
             android:background="?attr/selectableItemBackground"
             android:contentDescription="@string/accessibility_tabstrip_btn_incognito_toggle_standard"
             />
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/empty_menu_button"
             style="@style/ToolbarButton"
             android:layout_width="48dp"
@@ -52,7 +52,7 @@
             android:scaleType="center"
             android:contentDescription="@string/accessibility_toolbar_btn_menu"
             android:paddingStart="2dp"
-            app:chrometint="@color/light_mode_tint"
+            app:tint="@color/light_mode_tint"
             />
     </LinearLayout>
 </org.chromium.chrome.browser.widget.emptybackground.EmptyBackgroundViewTablet>
diff --git a/chrome/android/java/res/layout/experimental_toolbar_button.xml b/chrome/android/java/res/layout/experimental_toolbar_button.xml
index 1dbeb1f..8c7f19b 100644
--- a/chrome/android/java/res/layout/experimental_toolbar_button.xml
+++ b/chrome/android/java/res/layout/experimental_toolbar_button.xml
@@ -3,11 +3,10 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<org.chromium.chrome.browser.widget.TintedImageButton
+<android.support.v7.widget.AppCompatImageButton
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     style="@style/ToolbarButton"
     android:layout_gravity="top"
     android:paddingStart="8dp"
-    tools:ignore="ContentDescription" />
\ No newline at end of file
+    tools:ignore="ContentDescription"/>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/find_in_page.xml b/chrome/android/java/res/layout/find_in_page.xml
index acde96ff..caa4296 100644
--- a/chrome/android/java/res/layout/find_in_page.xml
+++ b/chrome/android/java/res/layout/find_in_page.xml
@@ -41,25 +41,25 @@
         android:layout_marginBottom="8dp"
         android:background="#000000"
         android:alpha="0.1" />
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/find_prev_button"
         style="@style/ToolbarButton"
         android:layout_height="match_parent"
         android:src="@drawable/ic_expand_less_black_24dp"
         android:contentDescription="@string/accessibility_find_toolbar_btn_prev"
-        app:chrometint="@color/dark_mode_tint" />
-    <org.chromium.chrome.browser.widget.TintedImageButton
+        app:tint="@color/dark_mode_tint" />
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/find_next_button"
         style="@style/ToolbarButton"
         android:layout_height="match_parent"
         android:src="@drawable/ic_expand_more_black_24dp"
         android:contentDescription="@string/accessibility_find_toolbar_btn_next"
-        app:chrometint="@color/dark_mode_tint" />
-    <org.chromium.chrome.browser.widget.TintedImageButton
+        app:tint="@color/dark_mode_tint" />
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/close_find_button"
         style="@style/ToolbarButton"
         android:layout_height="match_parent"
         android:src="@drawable/btn_close"
         android:contentDescription="@string/close"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/history_item_view.xml b/chrome/android/java/res/layout/history_item_view.xml
index c2bd348..b4b1c99 100644
--- a/chrome/android/java/res/layout/history_item_view.xml
+++ b/chrome/android/java/res/layout/history_item_view.xml
@@ -15,12 +15,12 @@
 
         <include layout="@layout/modern_list_item_view" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/remove"
             style="@style/ListItemEndIconSmall"
             android:contentDescription="@string/remove"
             android:src="@drawable/btn_delete_24dp"
-            app:chrometint="@color/light_icon_color" />
+            app:tint="@color/light_icon_color" />
     </LinearLayout>
 
 </org.chromium.chrome.browser.history.HistoryItemView>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/icon_row_menu_footer.xml b/chrome/android/java/res/layout/icon_row_menu_footer.xml
index 02571a7..9b18e375 100644
--- a/chrome/android/java/res/layout/icon_row_menu_footer.xml
+++ b/chrome/android/java/res/layout/icon_row_menu_footer.xml
@@ -18,31 +18,31 @@
         android:orientation="horizontal"
         android:id="@+id/menu_items" >
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/forward_menu_id"
             style="@style/OverflowMenuButton"
             android:src="@drawable/btn_forward"
             android:contentDescription="@string/accessibility_menu_forward" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/bookmark_this_page_id"
             style="@style/OverflowMenuButton"
             android:src="@drawable/btn_star"
             android:contentDescription="@string/accessibility_menu_bookmark" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/offline_page_id"
             style="@style/OverflowMenuButton"
             android:src="@drawable/ic_file_download_white_24dp"
             android:contentDescription="@string/download_page" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/info_menu_id"
             style="@style/OverflowMenuButton"
             android:src="@drawable/btn_info"
             android:contentDescription="@string/accessibility_menu_info" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/reload_menu_id"
             style="@style/OverflowMenuButton"
             android:src="@drawable/btn_reload_stop"
diff --git a/chrome/android/java/res/layout/icon_row_menu_item.xml b/chrome/android/java/res/layout/icon_row_menu_item.xml
index 43442e6..7da9b78 100644
--- a/chrome/android/java/res/layout/icon_row_menu_item.xml
+++ b/chrome/android/java/res/layout/icon_row_menu_item.xml
@@ -6,29 +6,28 @@
 -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="?android:attr/listPreferredItemHeightSmall"
     android:layout_gravity="top|start"
     android:orientation="horizontal">
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/button_one"
         style="@style/OverflowMenuButton" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/button_two"
         style="@style/OverflowMenuButton" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/button_three"
         style="@style/OverflowMenuButton" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/button_four"
         style="@style/OverflowMenuButton" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/button_five"
         style="@style/OverflowMenuButton" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/infobar_translate_compact_content.xml b/chrome/android/java/res/layout/infobar_translate_compact_content.xml
index 30967f37..41f8e9bf 100644
--- a/chrome/android/java/res/layout/infobar_translate_compact_content.xml
+++ b/chrome/android/java/res/layout/infobar_translate_compact_content.xml
@@ -23,7 +23,7 @@
         app:tabGravity="fill"
         app:tabMode="scrollable" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/translate_infobar_menu_button"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
@@ -33,5 +33,5 @@
         android:background="?attr/selectableItemBackground"
         android:contentDescription="@string/accessibility_toolbar_btn_menu"
         android:src="@drawable/ic_more_vert_black_24dp"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/language_ask_prompt_row.xml b/chrome/android/java/res/layout/language_ask_prompt_row.xml
index e965687..a66aadc1 100644
--- a/chrome/android/java/res/layout/language_ask_prompt_row.xml
+++ b/chrome/android/java/res/layout/language_ask_prompt_row.xml
@@ -16,6 +16,7 @@
     <CheckBox
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingEnd="@dimen/explicit_ask_checkbox_end_padding"
         android:id="@+id/language_ask_checkbox"
         android:layout_alignBaseline="@+id/ui_language_representation" />
 
diff --git a/chrome/android/java/res/layout/list_menu_button.xml b/chrome/android/java/res/layout/list_menu_button.xml
index 5672e8ca..8e6de6e 100644
--- a/chrome/android/java/res/layout/list_menu_button.xml
+++ b/chrome/android/java/res/layout/list_menu_button.xml
@@ -16,5 +16,5 @@
     android:paddingEnd="@dimen/selectable_list_layout_row_padding"
     android:background="@null"
     android:src="@drawable/ic_more_vert_black_24dp"
-    app:chrometint="@color/dark_mode_tint"
+    app:tint="@color/dark_mode_tint"
     tools:ignore="ContentDescription" />
diff --git a/chrome/android/java/res/layout/list_selection_handle_view.xml b/chrome/android/java/res/layout/list_selection_handle_view.xml
index 3367d7e8..a3360a1 100644
--- a/chrome/android/java/res/layout/list_selection_handle_view.xml
+++ b/chrome/android/java/res/layout/list_selection_handle_view.xml
@@ -9,18 +9,18 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools">
 
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/check"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:scaleType="center"
         android:background="@drawable/list_item_icon_modern_bg"
         android:visibility="gone"
-        app:chrometint="@color/white_mode_tint"
+        app:tint="@color/white_mode_tint"
         app:layout_gravity="center"
         tools:ignore="ContentDescription" />
 
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/circle"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -28,7 +28,7 @@
         android:background="@null"
         android:src="@drawable/download_circular_selector_transparent"
         android:visibility="gone"
-        app:chrometint="@null"
+        app:tint="@null"
         tools:ignore="ContentDescription"/>
 
 </merge>
diff --git a/chrome/android/java/res/layout/location_bar_base.xml b/chrome/android/java/res/layout/location_bar_base.xml
index 7d9bc9f..4970595 100644
--- a/chrome/android/java/res/layout/location_bar_base.xml
+++ b/chrome/android/java/res/layout/location_bar_base.xml
@@ -24,7 +24,7 @@
             android:scaleType="center"
             android:contentDescription="@string/accessibility_toolbar_btn_site_info" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/security_button"
             style="@style/LocationBarButton"
             android:layout_width="match_parent"
@@ -33,7 +33,7 @@
             android:layout_gravity="center"
             android:alpha="0"
             android:visibility="invisible"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
     </FrameLayout>
 
diff --git a/chrome/android/java/res/layout/menu_button.xml b/chrome/android/java/res/layout/menu_button.xml
index 442f408..f4808b1 100644
--- a/chrome/android/java/res/layout/menu_button.xml
+++ b/chrome/android/java/res/layout/menu_button.xml
@@ -12,13 +12,13 @@
        android:layout_height="wrap_content"
        android:id="@+id/menu_button_wrapper">
 
-       <org.chromium.chrome.browser.widget.TintedImageButton
+       <android.support.v7.widget.AppCompatImageButton
            android:id="@+id/menu_button"
            style="@style/ToolbarMenuButtonPhone"
            android:src="@drawable/ic_more_vert_black_24dp"
            android:contentDescription="@string/accessibility_toolbar_btn_menu"
            android:layout_gravity="center"
-           app:chrometint="@color/dark_mode_tint" />
+           app:tint="@color/dark_mode_tint" />
 
        <ImageView
            android:id="@+id/menu_badge"
diff --git a/chrome/android/java/res/layout/modern_list_item_view.xml b/chrome/android/java/res/layout/modern_list_item_view.xml
index 3616a79..0180c25 100644
--- a/chrome/android/java/res/layout/modern_list_item_view.xml
+++ b/chrome/android/java/res/layout/modern_list_item_view.xml
@@ -6,7 +6,7 @@
 <merge
     xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/icon_view"
         style="@style/ListItemStartIcon" />
 
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index 7c0158c..722604e4 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -54,13 +54,13 @@
             android:gravity="center_vertical"
             android:inputType="text"
             android:singleLine="true" />
-        <org.chromium.chrome.browser.widget.TintedImageView
+        <android.support.v7.widget.AppCompatImageView
             android:id="@+id/voice_search_button"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:contentDescription="@string/accessibility_toolbar_btn_mic"
             android:src="@drawable/btn_mic"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
     </view>
 
     <ViewStub
diff --git a/chrome/android/java/res/layout/password_entry_editor_copyable_row.xml b/chrome/android/java/res/layout/password_entry_editor_copyable_row.xml
index 73cea57..5f6180b 100644
--- a/chrome/android/java/res/layout/password_entry_editor_copyable_row.xml
+++ b/chrome/android/java/res/layout/password_entry_editor_copyable_row.xml
@@ -17,7 +17,7 @@
         android:layout_weight="1"
         android:textAppearance="@style/TextAppearance.PreferenceMediumText" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/password_entry_editor_copy"
         android:background="?attr/selectableItemBackground"
         android:layout_width="wrap_content"
@@ -25,7 +25,7 @@
         android:layout_gravity="end"
         android:layout_marginTop="15dp"
         android:layout_marginEnd="15dp"
-        app:chrometint="@color/dark_mode_tint"
+        app:tint="@color/dark_mode_tint"
         android:contentDescription="@string/password_entry_editor_copy_stored_username"
         style="?android:attr/buttonStyleSmall" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/password_entry_editor_interactive.xml b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
index 97f3535c..efa7efb 100644
--- a/chrome/android/java/res/layout/password_entry_editor_interactive.xml
+++ b/chrome/android/java/res/layout/password_entry_editor_interactive.xml
@@ -59,7 +59,7 @@
                     android:layout_weight="1"
                     android:textAppearance="@style/TextAppearance.PreferenceMediumText" />
 
-                <org.chromium.chrome.browser.widget.TintedImageButton
+                <android.support.v7.widget.AppCompatImageButton
                     android:id="@+id/password_entry_editor_view_password"
                     android:background="?attr/selectableItemBackground"
                     android:layout_width="wrap_content"
@@ -68,11 +68,11 @@
                     android:layout_marginTop="15dp"
                     android:layout_marginEnd="15dp"
                     app:srcCompat="@drawable/ic_visibility_black"
-                    app:chrometint="@color/dark_mode_tint"
+                    app:tint="@color/dark_mode_tint"
                     android:contentDescription="@string/password_entry_editor_view_stored_password"
                     style="?android:attr/buttonStyleSmall" />
 
-                <org.chromium.chrome.browser.widget.TintedImageButton
+                <android.support.v7.widget.AppCompatImageButton
                     android:id="@+id/password_entry_editor_copy_password"
                     android:background="?attr/selectableItemBackground"
                     android:layout_width="wrap_content"
@@ -80,7 +80,7 @@
                     android:layout_gravity="end"
                     android:layout_marginTop="15dp"
                     android:layout_marginEnd="15dp"
-                    app:chrometint="@color/dark_mode_tint"
+                    app:tint="@color/dark_mode_tint"
                     android:contentDescription="@string/password_entry_editor_copy_stored_password"
                     style="?android:attr/buttonStyleSmall" />
             </LinearLayout>
diff --git a/chrome/android/java/res/layout/search_toolbar.xml b/chrome/android/java/res/layout/search_toolbar.xml
index 92ab49a..c2088a4a 100644
--- a/chrome/android/java/res/layout/search_toolbar.xml
+++ b/chrome/android/java/res/layout/search_toolbar.xml
@@ -24,7 +24,7 @@
         android:textAppearance="@style/BlackTitle1"
         android:textColorHint="@color/search_box_hint"/>
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/clear_text_button"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
@@ -35,5 +35,5 @@
         android:scaleType="center"
         android:contentDescription="@string/accessibility_toolbar_btn_delete_url"
         android:visibility="invisible"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/textbubble_text_with_image.xml b/chrome/android/java/res/layout/textbubble_text_with_image.xml
index 2f12ec6..24332f9 100644
--- a/chrome/android/java/res/layout/textbubble_text_with_image.xml
+++ b/chrome/android/java/res/layout/textbubble_text_with_image.xml
@@ -16,14 +16,14 @@
     android:padding="16dp"
     android:gravity="center" >
 
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/image"
         android:layout_width="20sp"
         android:layout_height="20sp"
         android:layout_marginEnd="12dp"
         tools:ignore="ContentDescription"
         android:scaleType="centerInside"
-        app:chrometint="@color/white_mode_tint" />
+        app:tint="@color/white_mode_tint" />
 
     <TextView
         android:id="@+id/message"
diff --git a/chrome/android/java/res/layout/title_button_menu_item.xml b/chrome/android/java/res/layout/title_button_menu_item.xml
index 423c0ba2..7f91b77 100644
--- a/chrome/android/java/res/layout/title_button_menu_item.xml
+++ b/chrome/android/java/res/layout/title_button_menu_item.xml
@@ -11,9 +11,8 @@
      * A text label with an icon
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeightSmall">
+              android:layout_width="match_parent"
+              android:layout_height="?android:attr/listPreferredItemHeightSmall">
     <TextView
         android:id="@+id/title"
         android:layout_width="0dp"
@@ -41,7 +40,7 @@
         android:src="?android:attr/listChoiceIndicatorMultiple" />
 
     <!-- Displays an icon. -->
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/button"
         android:layout_width="56dp"
         android:layout_height="match_parent"
diff --git a/chrome/android/java/res/layout/toolbar_phone.xml b/chrome/android/java/res/layout/toolbar_phone.xml
index 47f6ec5..30a5dce 100644
--- a/chrome/android/java/res/layout/toolbar_phone.xml
+++ b/chrome/android/java/res/layout/toolbar_phone.xml
@@ -30,7 +30,7 @@
         android:src="@drawable/btn_toolbar_home"
         android:contentDescription="@string/accessibility_toolbar_btn_home"
         android:visibility="gone"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 
     <org.chromium.chrome.browser.omnibox.LocationBarPhone
         android:id="@+id/location_bar"
@@ -38,14 +38,6 @@
         android:layout_height="match_parent"
         android:layout_gravity="top" />
 
-    <ViewStub
-        android:id="@+id/incognito_tabs_stub"
-        android:inflatedId="@+id/incognito_toggle_tabs"
-        android:layout="@layout/incognito_toggle_tabs"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_gravity="center" />
-
     <LinearLayout android:id="@+id/toolbar_buttons"
         android:orientation="horizontal"
         android:layout_width="wrap_content"
@@ -63,6 +55,14 @@
                 style="@style/ToolbarButton"
                 android:paddingStart="8dp"
                 android:visibility="gone" />
+
+            <ViewStub
+                android:id="@+id/incognito_button_stub"
+                android:inflatedId="@+id/incognito_button"
+                android:layout="@layout/toolbar_phone_incognito_button"
+                style="@style/ToolbarButton"
+                android:contentDescription="@string/accessibility_tabstrip_btn_incognito_toggle_standard"
+                android:visibility="gone" />
         </FrameLayout>
 
         <ImageButton android:id="@+id/tab_switcher_button"
diff --git a/chrome/android/java/res/layout/incognito_toggle_tabs.xml b/chrome/android/java/res/layout/toolbar_phone_incognito_button.xml
similarity index 79%
rename from chrome/android/java/res/layout/incognito_toggle_tabs.xml
rename to chrome/android/java/res/layout/toolbar_phone_incognito_button.xml
index eb61a6e5..4c86eb3c 100644
--- a/chrome/android/java/res/layout/incognito_toggle_tabs.xml
+++ b/chrome/android/java/res/layout/toolbar_phone_incognito_button.xml
@@ -4,5 +4,5 @@
      found in the LICENSE file. -->
 
 <!-- The incognito toggle toolbar button. -->
-<org.chromium.chrome.browser.toolbar.IncognitoToggleTabLayout
+<org.chromium.chrome.browser.widget.incognitotoggle.IncognitoToggleButton
     style="@style/ToolbarButton" />
diff --git a/chrome/android/java/res/layout/toolbar_tablet.xml b/chrome/android/java/res/layout/toolbar_tablet.xml
index 42b2376..d9fbd76 100644
--- a/chrome/android/java/res/layout/toolbar_tablet.xml
+++ b/chrome/android/java/res/layout/toolbar_tablet.xml
@@ -28,28 +28,28 @@
             android:src="@drawable/btn_toolbar_home"
             android:contentDescription="@string/accessibility_toolbar_btn_home"
             android:visibility="gone"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/back_button"
             style="@style/ToolbarButton"
             android:src="@drawable/btn_back"
             android:contentDescription="@string/accessibility_toolbar_btn_back"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/forward_button"
             style="@style/ToolbarButton"
             android:src="@drawable/btn_forward"
             android:contentDescription="@string/accessibility_toolbar_btn_forward"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/refresh_button"
             style="@style/ToolbarButton"
             android:src="@drawable/btn_reload_stop"
             android:contentDescription="@string/accessibility_btn_refresh"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
         <org.chromium.chrome.browser.omnibox.LocationBarTablet
             android:id="@+id/location_bar"
@@ -72,12 +72,12 @@
             android:layout_height="wrap_content"
             android:id="@+id/menu_button_wrapper" >
 
-            <org.chromium.chrome.browser.widget.TintedImageButton
+            <android.support.v7.widget.AppCompatImageButton
                 android:id="@+id/menu_button"
                 style="@style/ToolbarMenuButtonTablet"
                 android:src="@drawable/ic_more_vert_black_24dp"
                 android:contentDescription="@string/accessibility_toolbar_btn_menu"
-                app:chrometint="@color/dark_mode_tint" />
+                app:tint="@color/dark_mode_tint" />
 
             <ImageView
                 android:id="@+id/menu_badge"
diff --git a/chrome/android/java/res/layout/translate_menu_item_checked.xml b/chrome/android/java/res/layout/translate_menu_item_checked.xml
index c5b1ea62..3115270 100644
--- a/chrome/android/java/res/layout/translate_menu_item_checked.xml
+++ b/chrome/android/java/res/layout/translate_menu_item_checked.xml
@@ -26,14 +26,14 @@
             android:paddingTop="13dp"
             android:paddingBottom="13dp"
             android:paddingEnd="16dp" />
-        <org.chromium.chrome.browser.widget.TintedImageView
+        <android.support.v7.widget.AppCompatImageView
             android:id="@+id/menu_item_icon"
             android:src="@drawable/ic_check_googblue_24dp"
             android:layout_width="24dp"
             android:layout_height="match_parent"
             android:layout_gravity="end"
             android:gravity="center_vertical"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
     </LinearLayout>
 
diff --git a/chrome/android/java/res/layout/update_menu_item.xml b/chrome/android/java/res/layout/update_menu_item.xml
index f2f8a1b..98b05087 100644
--- a/chrome/android/java/res/layout/update_menu_item.xml
+++ b/chrome/android/java/res/layout/update_menu_item.xml
@@ -41,6 +41,6 @@
         android:layout_height="match_parent"
         android:layout_gravity="end"
         android:gravity="center_vertical"
-        app:chrometint="@null" />
+        app:tint="@null" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/url_action_container.xml b/chrome/android/java/res/layout/url_action_container.xml
index 53dbc0e4..5756cf2a 100644
--- a/chrome/android/java/res/layout/url_action_container.xml
+++ b/chrome/android/java/res/layout/url_action_container.xml
@@ -4,8 +4,7 @@
      found in the LICENSE file. -->
 
 <merge
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
+    xmlns:android="http://schemas.android.com/apk/res/android">
 
     <LinearLayout android:id="@+id/url_action_container"
         android:layout_width="wrap_content"
@@ -13,27 +12,27 @@
         android:layout_gravity="end|center_vertical"
         android:orientation="horizontal" >
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/delete_button"
             style="@style/LocationBarActionButton"
             android:src="@drawable/btn_delete_24dp"
             android:visibility="invisible"
             android:contentDescription="@string/accessibility_toolbar_btn_delete_url" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/mic_button"
             style="@style/LocationBarActionButton"
             android:src="@drawable/btn_mic"
             android:visibility="invisible"
             android:contentDescription="@string/accessibility_toolbar_btn_mic" />
 
-        <org.chromium.chrome.browser.widget.TintedImageButton
+        <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/bookmark_button"
             style="@style/LocationBarActionButton"
             android:visibility="gone"
             android:contentDescription="@string/accessibility_menu_bookmark" />
 
-       <org.chromium.chrome.browser.widget.TintedImageButton
+       <android.support.v7.widget.AppCompatImageButton
             android:id="@+id/save_offline_button"
             style="@style/LocationBarActionButton"
             android:nextFocusForward="@+id/menu_button"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 3d946cde..54ebed0a 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -298,7 +298,7 @@
         <item name="android:layout_weight">1</item>
         <item name="android:background">?attr/listChoiceBackgroundIndicator</item>
         <item name="android:scaleType">center</item>
-        <item name="chrometint">@color/dark_mode_tint</item>
+        <item name="tint">@color/dark_mode_tint</item>
     </style>
     <style name="OverflowMenuAnim">
         <item name="android:windowEnterAnimation">@anim/menu_enter</item>
@@ -560,7 +560,7 @@
         <item name="android:paddingStart">4dp</item>
         <item name="android:scaleType">center</item>
         <item name="android:layout_gravity">end</item>
-        <item name="chrometint">@color/dark_mode_tint</item>
+        <item name="tint">@color/dark_mode_tint</item>
     </style>
     <style name="ModernToolbar" parent="Widget.AppCompat.Toolbar">
         <item name="titleTextAppearance">@style/BlackHeadline1</item>
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml
index fc71116..e0f3c30 100644
--- a/chrome/android/java/res/values/attrs.xml
+++ b/chrome/android/java/res/values/attrs.xml
@@ -4,10 +4,6 @@
      found in the LICENSE file. -->
 
 <resources>
-    <declare-styleable name="TintedImage">
-        <attr name="chrometint" format="color" />
-    </declare-styleable>
-
     <declare-styleable name="HyperlinkPreference">
         <!-- The URL to load when the preference is clicked -->
         <attr name="url" format="string" />
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 7a21711c..991aaa7 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -550,4 +550,7 @@
     <dimen name="navigation_popup_default_padding">16dp</dimen>
     <dimen name="navigation_popup_top_padding">8dp</dimen>
     <dimen name="navigation_popup_favicon_bg_size">36dp</dimen>
+
+    <!-- Explicit Language Ask Prompt dimensions -->
+    <dimen name="explicit_ask_checkbox_end_padding">4dp</dimen>
 </resources>
diff --git a/chrome/android/java/res_download/layout/download_item_view.xml b/chrome/android/java/res_download/layout/download_item_view.xml
index e396f2c..e36dd3f 100644
--- a/chrome/android/java/res_download/layout/download_item_view.xml
+++ b/chrome/android/java/res_download/layout/download_item_view.xml
@@ -15,10 +15,10 @@
             android:id="@+id/layout_container"
             style="@style/ListItemContainer" >
 
-        <org.chromium.chrome.browser.widget.TintedImageView
+        <android.support.v7.widget.AppCompatImageView
             android:id="@+id/icon_view"
             style="@style/DownloadIconView"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
         <!-- Shown for completed downloads. -->
         <RelativeLayout
@@ -91,7 +91,7 @@
                     android:layout_below="@+id/download_progress_view"
                     android:textAlignment="viewEnd" />
 
-            <org.chromium.chrome.browser.widget.TintedImageButton
+            <android.support.v7.widget.AppCompatImageButton
                     android:id="@+id/pause_button"
                     android:layout_width="48dp"
                     android:layout_height="48dp"
@@ -102,9 +102,9 @@
                     android:background="?attr/selectableItemBackground"
                     android:contentDescription="@string/download_notification_pause_button"
                     android:src="@drawable/ic_pause_white_24dp"
-                    app:chrometint="@color/default_icon_color" />
+                    app:tint="@color/default_icon_color" />
 
-            <org.chromium.chrome.browser.widget.TintedImageButton
+            <android.support.v7.widget.AppCompatImageButton
                     android:id="@+id/cancel_button"
                     android:layout_width="48dp"
                     android:layout_height="48dp"
@@ -116,7 +116,7 @@
                     android:background="?attr/selectableItemBackground"
                     android:contentDescription="@string/download_notification_cancel_button"
                     android:src="@drawable/btn_close"
-                    app:chrometint="@color/default_icon_color" />
+                    app:tint="@color/default_icon_color" />
         </RelativeLayout>
     </LinearLayout>
 </view>
diff --git a/chrome/android/java/res_download/layout/download_location_dialog.xml b/chrome/android/java/res_download/layout/download_location_dialog.xml
index cb75a04..4061a078 100644
--- a/chrome/android/java/res_download/layout/download_location_dialog.xml
+++ b/chrome/android/java/res_download/layout/download_location_dialog.xml
@@ -28,11 +28,11 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal">
 
-            <org.chromium.chrome.browser.widget.TintedImageView
+            <android.support.v7.widget.AppCompatImageView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 app:srcCompat="@drawable/ic_drive_file_24dp"
-                app:chrometint="@color/default_icon_color"
+                app:tint="@color/default_icon_color"
                 style="@style/ListItemStartIcon" />
 
             <org.chromium.chrome.browser.widget.AlertDialogEditText
@@ -49,11 +49,11 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal">
 
-            <org.chromium.chrome.browser.widget.TintedImageView
+            <android.support.v7.widget.AppCompatImageView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:src="@drawable/ic_folder_blue_24dp"
-                app:chrometint="@color/default_icon_color"
+                app:tint="@color/default_icon_color"
                 style="@style/ListItemStartIcon" />
 
             <Spinner
diff --git a/chrome/android/java/res_download/layout/download_manager_generic_item.xml b/chrome/android/java/res_download/layout/download_manager_generic_item.xml
index ceaa410..581a439 100644
--- a/chrome/android/java/res_download/layout/download_manager_generic_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_generic_item.xml
@@ -16,7 +16,7 @@
     app:columnCount="3"
     app:rowCount="2">
 
-    <org.chromium.chrome.browser.widget.TintedImageView
+    <android.support.v7.widget.AppCompatImageView
         android:id="@+id/thumbnail"
         android:layout_width="@dimen/download_manager_generic_thumbnail_size"
         android:layout_height="@dimen/download_manager_generic_thumbnail_size"
@@ -27,7 +27,7 @@
         app:layout_row="0"
         app:layout_rowSpan="2"
         app:layout_gravity="center_vertical"
-        app:chrometint="@color/dark_mode_tint" />
+        app:tint="@color/dark_mode_tint" />
 
     <org.chromium.chrome.browser.download.home.view.SelectionView
         android:id="@+id/selection"
diff --git a/chrome/android/java/res_download/layout/download_manager_in_progress_item.xml b/chrome/android/java/res_download/layout/download_manager_in_progress_item.xml
index b5304d6..4762920e 100644
--- a/chrome/android/java/res_download/layout/download_manager_in_progress_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_in_progress_item.xml
@@ -43,7 +43,7 @@
         app:layout_row="1"
         app:layout_gravity="fill_horizontal" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/cancel_button"
         android:layout_width="48dp"
         android:layout_height="48dp"
@@ -54,6 +54,6 @@
         android:background="?attr/selectableItemBackground"
         android:contentDescription="@string/download_notification_cancel_button"
         android:src="@drawable/btn_close"
-        app:chrometint="@color/default_icon_color" />
+        app:tint="@color/default_icon_color" />
 
 </android.support.v7.widget.GridLayout>
\ No newline at end of file
diff --git a/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml b/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml
index 8557e4a..116f9e8 100644
--- a/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml
@@ -60,7 +60,7 @@
         android:layout_marginStart="16dp"
         app:layout_gravity="fill_horizontal" />
 
-    <org.chromium.chrome.browser.widget.TintedImageButton
+    <android.support.v7.widget.AppCompatImageButton
         android:id="@+id/cancel_button"
         android:layout_width="48dp"
         android:layout_height="48dp"
@@ -71,6 +71,6 @@
         android:background="?attr/selectableItemBackground"
         android:contentDescription="@string/download_notification_cancel_button"
         android:src="@drawable/btn_close"
-        app:chrometint="@color/default_icon_color" />
+        app:tint="@color/default_icon_color" />
 
 </android.support.v7.widget.GridLayout>
diff --git a/chrome/android/java/res_download/layout/offline_download_header.xml b/chrome/android/java/res_download/layout/offline_download_header.xml
index 74d9b36..60cfc07d 100644
--- a/chrome/android/java/res_download/layout/offline_download_header.xml
+++ b/chrome/android/java/res_download/layout/offline_download_header.xml
@@ -16,11 +16,11 @@
         android:id="@+id/layout_container"
         style="@style/ListItemContainer" >
 
-        <org.chromium.chrome.browser.widget.TintedImageView
+        <android.support.v7.widget.AppCompatImageView
             android:id="@+id/icon_view"
             style="@style/DownloadIconView"
             android:src="@drawable/ic_chrome"
-            app:chrometint="@color/dark_mode_tint" />
+            app:tint="@color/dark_mode_tint" />
 
         <RelativeLayout
             android:id="@+id/completed_layout"
@@ -47,7 +47,7 @@
                     android:layout_weight="0"
                     android:visibility="gone" />
 
-                <org.chromium.chrome.browser.widget.TintedImageView
+                <android.support.v7.widget.AppCompatImageView
                     android:id="@+id/expand_icon"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
@@ -56,7 +56,7 @@
                     android:paddingEnd="16dp"
                     tools:ignore="ContentDescription"
                     android:src="@drawable/ic_expand_more_black_24dp"
-                    app:chrometint="@color/dark_mode_tint" />
+                    app:tint="@color/dark_mode_tint" />
             </LinearLayout>
 
             <TextView
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuAdapter.java
index 6732fdd4..e6d2716 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuAdapter.java
@@ -10,7 +10,9 @@
 import android.animation.ObjectAnimator;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.IntDef;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
@@ -23,7 +25,6 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.ViewHighlighter;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
@@ -227,7 +228,7 @@
                     holder = new TitleButtonMenuItemViewHolder();
                     holder.title = (TextView) convertView.findViewById(R.id.title);
                     holder.checkbox = (AppMenuItemIcon) convertView.findViewById(R.id.checkbox);
-                    holder.button = (TintedImageButton) convertView.findViewById(R.id.button);
+                    holder.button = (AppCompatImageButton) convertView.findViewById(R.id.button);
                     holder.button.setTag(
                             R.id.menu_item_original_background, holder.button.getBackground());
 
@@ -288,13 +289,13 @@
 
         // The checkbox must be tinted to make Android consistently style it across OS versions.
         // http://crbug.com/571445
-        button.setTint(
+        ImageViewCompat.setImageTintList(button,
                 AppCompatResources.getColorStateList(button.getContext(), R.color.checkbox_tint));
 
         setupMenuButton(button, item);
     }
 
-    private void setupImageButton(TintedImageButton button, final MenuItem item) {
+    private void setupImageButton(AppCompatImageButton button, final MenuItem item) {
         // Store and recover the level of image as button.setimageDrawable
         // resets drawable to default level.
         int currentLevel = item.getIcon().getLevel();
@@ -302,8 +303,9 @@
         item.getIcon().setLevel(currentLevel);
 
         if (item.isChecked()) {
-            button.setTint(AppCompatResources.getColorStateList(
-                    button.getContext(), R.color.blue_mode_tint));
+            ImageViewCompat.setImageTintList(button,
+                    AppCompatResources.getColorStateList(
+                            button.getContext(), R.color.blue_mode_tint));
         }
 
         setupMenuButton(button, item);
@@ -438,8 +440,8 @@
 
             // Save references to all the buttons.
             for (int i = 0; i < numItems; i++) {
-                TintedImageButton view =
-                        (TintedImageButton) convertView.findViewById(BUTTON_IDS[i]);
+                AppCompatImageButton view =
+                        (AppCompatImageButton) convertView.findViewById(BUTTON_IDS[i]);
                 holder.buttons[i] = view;
                 holder.buttons[i].setTag(
                         R.id.menu_item_original_background, holder.buttons[i].getBackground());
@@ -475,16 +477,16 @@
     }
 
     private static class RowItemViewHolder {
-        public TintedImageButton[] buttons;
+        public AppCompatImageButton[] buttons;
 
         RowItemViewHolder(int numButtons) {
-            buttons = new TintedImageButton[numButtons];
+            buttons = new AppCompatImageButton[numButtons];
         }
     }
 
     static class TitleButtonMenuItemViewHolder {
         public TextView title;
         public AppMenuItemIcon checkbox;
-        public TintedImageButton button;
+        public AppCompatImageButton button;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
index 72be6c58..3a681f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuIconRowFooter.java
@@ -5,7 +5,9 @@
 package org.chromium.chrome.browser.appmenu;
 
 import android.content.Context;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -15,7 +17,6 @@
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge;
 import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 
 /**
  * A {@link LinearLayout} that displays a horizontal row of icons for page actions.
@@ -24,11 +25,11 @@
     private ChromeActivity mActivity;
     private AppMenu mAppMenu;
 
-    private TintedImageButton mForwardButton;
-    private TintedImageButton mBookmarkButton;
-    private TintedImageButton mDownloadButton;
-    private TintedImageButton mPageInfoButton;
-    private TintedImageButton mReloadButton;
+    private AppCompatImageButton mForwardButton;
+    private AppCompatImageButton mBookmarkButton;
+    private AppCompatImageButton mDownloadButton;
+    private AppCompatImageButton mPageInfoButton;
+    private AppCompatImageButton mReloadButton;
 
     public AppMenuIconRowFooter(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -38,19 +39,19 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mForwardButton = (TintedImageButton) findViewById(R.id.forward_menu_id);
+        mForwardButton = (AppCompatImageButton) findViewById(R.id.forward_menu_id);
         mForwardButton.setOnClickListener(this);
 
-        mBookmarkButton = (TintedImageButton) findViewById(R.id.bookmark_this_page_id);
+        mBookmarkButton = (AppCompatImageButton) findViewById(R.id.bookmark_this_page_id);
         mBookmarkButton.setOnClickListener(this);
 
-        mDownloadButton = (TintedImageButton) findViewById(R.id.offline_page_id);
+        mDownloadButton = (AppCompatImageButton) findViewById(R.id.offline_page_id);
         mDownloadButton.setOnClickListener(this);
 
-        mPageInfoButton = (TintedImageButton) findViewById(R.id.info_menu_id);
+        mPageInfoButton = (AppCompatImageButton) findViewById(R.id.info_menu_id);
         mPageInfoButton.setOnClickListener(this);
 
-        mReloadButton = (TintedImageButton) findViewById(R.id.reload_menu_id);
+        mReloadButton = (AppCompatImageButton) findViewById(R.id.reload_menu_id);
         mReloadButton.setOnClickListener(this);
     }
 
@@ -102,7 +103,7 @@
         if (currentTab.getBookmarkId() != Tab.INVALID_BOOKMARK_ID) {
             mBookmarkButton.setImageResource(R.drawable.btn_star_filled);
             mBookmarkButton.setContentDescription(mActivity.getString(R.string.edit_bookmark));
-            mBookmarkButton.setTint(
+            ImageViewCompat.setImageTintList(mBookmarkButton,
                     AppCompatResources.getColorStateList(getContext(), R.color.blue_mode_tint));
         } else {
             mBookmarkButton.setImageResource(R.drawable.btn_star);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuItemIcon.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuItemIcon.java
index 47b3980..87113f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuItemIcon.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuItemIcon.java
@@ -5,15 +5,14 @@
 package org.chromium.chrome.browser.appmenu;
 
 import android.content.Context;
+import android.support.v7.widget.AppCompatImageView;
 import android.util.AttributeSet;
 import android.widget.Checkable;
 
-import org.chromium.chrome.browser.widget.TintedImageView;
-
 /**
- * A TintedImageView that supports the checkable state.
+ * An AppCompatImageView that supports the checkable state.
  */
-public class AppMenuItemIcon extends TintedImageView implements Checkable {
+public class AppMenuItemIcon extends AppCompatImageView implements Checkable {
     private static final int[] CHECKED_STATE_SET = new int[] {android.R.attr.state_checked};
     private boolean mCheckedState;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index 27cb28a..5337520 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -14,6 +14,7 @@
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
+import org.chromium.components.variations.VariationsAssociatedData;
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
@@ -30,11 +31,25 @@
     /** Prefix for Intent extras relevant to this feature. */
     private static final String INTENT_EXTRA_PREFIX =
             "org.chromium.chrome.browser.autofill_assistant.";
+    /** Autofill Assistant Study name. */
+    private static final String STUDY_NAME = "AutofillAssistant";
+    /** Variation url parameter name. */
+    private static final String URL_PARAMETER_NAME = "url";
 
     private final long mUiControllerAndroid;
     private final AutofillAssistantUiDelegate mUiDelegate;
 
     /**
+     * Returns true if all conditions are satisfied to construct an AutofillAssistantUiController.
+     *
+     * @return True if a controller can be constructed.
+     */
+    public static boolean isConfigured() {
+        return !VariationsAssociatedData.getVariationParamValue(STUDY_NAME, URL_PARAMETER_NAME)
+                        .isEmpty();
+    }
+
+    /**
      * Construct Autofill Assistant UI controller.
      *
      * @param activity The CustomTabActivity of the controller associated with.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderSelectActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderSelectActivity.java
index 116dbf49..289f6f3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderSelectActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderSelectActivity.java
@@ -11,6 +11,7 @@
 import android.support.graphics.drawable.VectorDrawableCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageView;
 import android.support.v7.widget.Toolbar;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
@@ -26,7 +27,6 @@
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver;
 import org.chromium.chrome.browser.util.IntentUtils;
-import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 import org.chromium.components.bookmarks.BookmarkId;
 
@@ -359,7 +359,7 @@
          * i.e. New Folder, Normal and Selected.
          */
         private void setUpIcons(FolderListEntry entry, View view) {
-            TintedImageView startIcon = view.findViewById(R.id.icon_view);
+            AppCompatImageView startIcon = view.findViewById(R.id.icon_view);
 
             Drawable iconDrawable;
             if (entry.mType == FolderListEntry.TYPE_NORMAL) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index f3bee68..149d1adf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -683,7 +683,8 @@
         // TODO(crbug.com/806868): Only enable Autofill Assistant when the flag is enabled in the
         // intent.
         if (mAutofillAssistantUiController == null
-                && ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ASSISTANT)) {
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.AUTOFILL_ASSISTANT)
+                && AutofillAssistantUiController.isConfigured()) {
             mAutofillAssistantUiController = new AutofillAssistantUiController(this);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/chips/ChipsViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/chips/ChipsViewHolder.java
index 66d3dd04..029bcd6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/chips/ChipsViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/chips/ChipsViewHolder.java
@@ -5,31 +5,31 @@
 
 import android.content.res.ColorStateList;
 import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ImageViewCompat;
+import android.support.v7.widget.AppCompatImageView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
-import org.chromium.chrome.browser.widget.TintedImageView;
-
 /** The {@link ViewHolder} responsible for reflecting a {@link Chip} to a {@link View}. */
 public class ChipsViewHolder extends ViewHolder {
     private final int mTextStartPaddingWithIconPx;
     private final int mTextStartPaddingWithNoIconPx;
 
     private final TextView mText;
-    private final TintedImageView mImage;
+    private final AppCompatImageView mImage;
 
     /** Builds a ChipsViewHolder around a specific {@link View}. */
     private ChipsViewHolder(View itemView) {
         super(itemView);
 
         mText = itemView.findViewById(org.chromium.chrome.R.id.text);
-        mImage = (TintedImageView) itemView.findViewById(org.chromium.chrome.R.id.icon);
+        mImage = (AppCompatImageView) itemView.findViewById(org.chromium.chrome.R.id.icon);
 
         ColorStateList textColors = mText.getTextColors();
-        if (textColors != null) mImage.setTint(textColors);
+        if (textColors != null) ImageViewCompat.setImageTintList(mImage, textColors);
 
         mTextStartPaddingWithIconPx = mText.getResources().getDimensionPixelSize(
                 org.chromium.chrome.R.dimen.chip_icon_padding);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java
index 25ee4a60..4c752178 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java
@@ -9,7 +9,9 @@
 import android.support.annotation.DrawableRes;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageView;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -20,7 +22,6 @@
 import org.chromium.chrome.browser.download.home.list.UiUtils;
 import org.chromium.chrome.browser.download.home.view.SelectionView;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
-import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.download.R;
 import org.chromium.components.offline_items_collection.OfflineItemVisuals;
 
@@ -31,7 +32,7 @@
 
     private final TextView mTitle;
     private final TextView mCaption;
-    private final TintedImageView mThumbnailView;
+    private final AppCompatImageView mThumbnailView;
 
     private Bitmap mThumbnailBitmap;
 
@@ -52,7 +53,7 @@
 
         mTitle = (TextView) itemView.findViewById(R.id.title);
         mCaption = (TextView) itemView.findViewById(R.id.caption);
-        mThumbnailView = (TintedImageView) itemView.findViewById(R.id.thumbnail);
+        mThumbnailView = (AppCompatImageView) itemView.findViewById(R.id.thumbnail);
     }
 
     // ListItemViewHolder implementation.
@@ -83,7 +84,7 @@
             assert !mThumbnailBitmap.isRecycled();
 
             mThumbnailView.setBackground(null);
-            mThumbnailView.setTint(null);
+            ImageViewCompat.setImageTintList(mThumbnailView, null);
 
             RoundedBitmapDrawable drawable =
                     RoundedBitmapDrawableFactory.create(resources, mThumbnailBitmap);
@@ -94,8 +95,9 @@
             mThumbnailView.getBackground().setLevel(
                     resources.getInteger(R.integer.list_item_level_default));
             mThumbnailView.setImageResource(mIconId);
-            mThumbnailView.setTint(AppCompatResources.getColorStateList(
-                    mThumbnailView.getContext(), R.color.dark_mode_tint));
+            ImageViewCompat.setImageTintList(mThumbnailView,
+                    AppCompatResources.getColorStateList(
+                            mThumbnailView.getContext(), R.color.dark_mode_tint));
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressVideoViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressVideoViewHolder.java
index 5a12ed80..6d214b0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressVideoViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressVideoViewHolder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.download.home.list.holder;
 
+import android.support.v7.widget.AppCompatImageButton;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -15,7 +16,6 @@
 import org.chromium.chrome.browser.download.home.list.UiUtils;
 import org.chromium.chrome.browser.download.home.list.view.CircularProgressView;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.download.R;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemState;
@@ -28,7 +28,7 @@
     private final TextView mTitle;
     private final TextView mCaption;
     private final CircularProgressView mActionButton;
-    private final TintedImageButton mCancelButton;
+    private final AppCompatImageButton mCancelButton;
 
     /**
      * Creates a new {@link InProgressViewHolder} instance.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java
index 186e8df..ee2f125 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.download.home.list.holder;
 
+import android.support.v7.widget.AppCompatImageButton;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -15,7 +16,6 @@
 import org.chromium.chrome.browser.download.home.list.UiUtils;
 import org.chromium.chrome.browser.download.home.list.view.CircularProgressView;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.download.R;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemState;
@@ -28,7 +28,7 @@
     private final TextView mTitle;
     private final TextView mCaption;
     private final CircularProgressView mActionButton;
-    private final TintedImageButton mCancelButton;
+    private final AppCompatImageButton mCancelButton;
 
     /**
      * Creates a new {@link InProgressViewHolder} instance.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/view/SelectionView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/view/SelectionView.java
index de4bfff..75cc8fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/view/SelectionView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/view/SelectionView.java
@@ -6,12 +6,12 @@
 
 import android.content.Context;
 import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
+import android.support.v7.widget.AppCompatImageView;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.widget.FrameLayout;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.TintedImageView;
 
 /**
  * A helper UI widget that provides visual feedback when the selection state of the underlying view
@@ -19,8 +19,8 @@
  * selected. The caller can define the UI behavior at each of these states by subclassing this view.
  */
 public class SelectionView extends FrameLayout {
-    private final TintedImageView mCheck;
-    private final TintedImageView mCircle;
+    private final AppCompatImageView mCheck;
+    private final AppCompatImageView mCircle;
     private final AnimatedVectorDrawableCompat mCheckDrawable;
 
     private boolean mIsSelected;
@@ -31,8 +31,8 @@
     public SelectionView(Context context, AttributeSet attrs) {
         super(context, attrs);
         LayoutInflater.from(context).inflate(R.layout.list_selection_handle_view, this, true);
-        mCheck = (TintedImageView) findViewById(R.id.check);
-        mCircle = (TintedImageView) findViewById(R.id.circle);
+        mCheck = (AppCompatImageView) findViewById(R.id.check);
+        mCircle = (AppCompatImageView) findViewById(R.id.circle);
         mCheckDrawable = AnimatedVectorDrawableCompat.create(
                 context, R.drawable.ic_check_googblue_24dp_animated);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
index c60d8ad..f898fab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -11,7 +11,9 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.view.MarginLayoutParamsCompat;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.util.AttributeSet;
@@ -30,7 +32,6 @@
 import org.chromium.chrome.browser.widget.ListMenuButton.Item;
 import org.chromium.chrome.browser.widget.MaterialProgressBar;
 import org.chromium.chrome.browser.widget.ThumbnailProvider;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 import org.chromium.chrome.download.R;
 import org.chromium.components.offline_items_collection.OfflineItem;
@@ -100,7 +101,7 @@
     private TextView mDownloadStatusView;
     private TextView mDownloadPercentageView;
     private MaterialProgressBar mProgressView;
-    private TintedImageButton mPauseResumeButton;
+    private AppCompatImageButton mPauseResumeButton;
     private View mCancelButton;
 
     /**
@@ -154,7 +155,7 @@
         mDownloadStatusView = (TextView) findViewById(R.id.status_view);
         mDownloadPercentageView = (TextView) findViewById(R.id.percentage_view);
 
-        mPauseResumeButton = (TintedImageButton) findViewById(R.id.pause_button);
+        mPauseResumeButton = (AppCompatImageButton) findViewById(R.id.pause_button);
         mCancelButton = findViewById(R.id.cancel_button);
 
         mMoreButton.setDelegate(this);
@@ -343,7 +344,7 @@
             mIconView.getBackground().setLevel(
                     getResources().getInteger(R.integer.list_item_level_selected));
             mIconView.setImageDrawable(mCheckDrawable);
-            mIconView.setTint(mCheckedIconForegroundColorList);
+            ImageViewCompat.setImageTintList(mIconView, mCheckedIconForegroundColorList);
             mCheckDrawable.start();
         } else if (mThumbnailBitmap != null) {
             assert !mThumbnailBitmap.isRecycled();
@@ -352,13 +353,13 @@
                     Bitmap.createScaledBitmap(mThumbnailBitmap, mIconSize, mIconSize, false),
                     getResources().getDimensionPixelSize(
                             R.dimen.list_item_start_icon_corner_radius)));
-            mIconView.setTint(null);
+            ImageViewCompat.setImageTintList(mIconView, null);
         } else {
             mIconView.setBackgroundResource(mIconBackgroundResId);
             mIconView.getBackground().setLevel(
                     getResources().getInteger(R.integer.list_item_level_default));
             mIconView.setImageResource(mIconResId);
-            mIconView.setTint(mIconForegroundColorList);
+            ImageViewCompat.setImageTintList(mIconView, mIconForegroundColorList);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java
index c6ce60b..0ae7e87 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java
@@ -7,7 +7,9 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageView;
 import android.text.format.DateUtils;
 import android.text.format.Formatter;
 import android.util.AttributeSet;
@@ -18,7 +20,6 @@
 import org.chromium.chrome.browser.download.ui.DownloadHistoryAdapter.SubsectionHeader;
 import org.chromium.chrome.browser.download.ui.DownloadItemSelectionDelegate.SubsectionHeaderSelectionObserver;
 import org.chromium.chrome.browser.widget.DateDividedAdapter.TimedItem;
-import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 import org.chromium.chrome.download.R;
 
@@ -39,7 +40,7 @@
 
     private TextView mDescriptionTextView;
     private ImageView mExpandImage;
-    private TintedImageView mIconImageView;
+    private AppCompatImageView mIconImageView;
 
     public OfflineGroupHeaderView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -54,7 +55,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mIconImageView = (TintedImageView) findViewById(R.id.icon_view);
+        mIconImageView = (AppCompatImageView) findViewById(R.id.icon_view);
         mDescriptionTextView = (TextView) findViewById(R.id.description);
         mExpandImage = (ImageView) findViewById(R.id.expand_icon);
     }
@@ -116,7 +117,7 @@
                     getResources().getInteger(R.integer.list_item_level_selected));
 
             mIconImageView.setImageDrawable(mCheckDrawable);
-            mIconImageView.setTint(mCheckedIconForegroundColorList);
+            ImageViewCompat.setImageTintList(mIconImageView, mCheckedIconForegroundColorList);
             mCheckDrawable.start();
         } else {
             mIconImageView.setBackgroundResource(mIconBackgroundResId);
@@ -124,7 +125,7 @@
                     getResources().getInteger(R.integer.list_item_level_default));
 
             mIconImageView.setImageResource(R.drawable.ic_chrome);
-            mIconImageView.setTint(mIconForegroundColorList);
+            ImageViewCompat.setImageTintList(mIconImageView, mIconForegroundColorList);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
index b610b826..bbd4697 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
@@ -11,6 +11,7 @@
 import android.support.graphics.drawable.VectorDrawableCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.View;
 
@@ -23,14 +24,13 @@
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 
 /**
  * The SelectableItemView for items displayed in the browsing history UI.
  */
 public class HistoryItemView extends SelectableItemView<HistoryItem> implements LargeIconCallback {
-    private TintedImageButton mRemoveButton;
+    private AppCompatImageButton mRemoveButton;
     private VectorDrawableCompat mBlockedVisitDrawable;
     private View mContentView;
 
@@ -62,7 +62,7 @@
         super.onFinishInflate();
         mIconView.setImageResource(R.drawable.default_favicon);
         mContentView = findViewById(R.id.content);
-        mRemoveButton = (TintedImageButton) findViewById(R.id.remove);
+        mRemoveButton = (AppCompatImageButton) findViewById(R.id.remove);
         mRemoveButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
index 9b1ecff..a66105b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateCompactInfoBar.java
@@ -6,6 +6,7 @@
 
 import android.support.design.widget.TabLayout;
 import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.AppCompatImageButton;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -20,7 +21,6 @@
 import org.chromium.chrome.browser.infobar.translate.TranslateTabLayout;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.ui.widget.Toast;
 
 /**
@@ -104,7 +104,7 @@
     private TranslateMenuHelper mOverflowMenuHelper;
     private TranslateMenuHelper mLanguageMenuHelper;
 
-    private TintedImageButton mMenuButton;
+    private AppCompatImageButton mMenuButton;
     private InfoBarCompactLayout mParent;
 
     private TranslateSnackbarController mSnackbarController;
@@ -239,7 +239,8 @@
             }
         });
 
-        mMenuButton = (TintedImageButton) content.findViewById(R.id.translate_infobar_menu_button);
+        mMenuButton =
+                (AppCompatImageButton) content.findViewById(R.id.translate_infobar_menu_button);
         mMenuButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java
index ca104d9..a3173a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/translate/TranslateMenuHelper.java
@@ -8,6 +8,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.AppCompatImageView;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -22,7 +23,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.infobar.TranslateOptions;
-import org.chromium.chrome.browser.widget.TintedImageView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -287,8 +287,8 @@
                     menuItemView = getItemView(
                             menuItemView, position, parent, R.layout.translate_menu_item_checked);
 
-                    TintedImageView checkboxIcon =
-                            (TintedImageView) menuItemView.findViewById(R.id.menu_item_icon);
+                    AppCompatImageView checkboxIcon =
+                            (AppCompatImageView) menuItemView.findViewById(R.id.menu_item_icon);
                     if (getItem(position).mId == TranslateMenu.ID_OVERFLOW_ALWAYS_TRANSLATE
                             && mOptions.getTranslateState(TranslateOptions.Type.ALWAYS_LANGUAGE)) {
                         checkboxIcon.setVisibility(View.VISIBLE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
index e788ce0..25a5dfe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
@@ -43,7 +43,8 @@
         }
     }
 
-    private class LanguageAskPromptRowViewHolder extends ViewHolder {
+    private class LanguageAskPromptRowViewHolder
+            extends ViewHolder implements View.OnClickListener {
         private TextView mLanguageNameTextView;
         private TextView mNativeNameTextView;
         private CheckBox mCheckbox;
@@ -52,6 +53,7 @@
 
         LanguageAskPromptRowViewHolder(View view) {
             super(view);
+            view.setOnClickListener(this);
             mLanguageNameTextView =
                     ((TextView) itemView.findViewById(R.id.ui_language_representation));
             mNativeNameTextView =
@@ -69,6 +71,11 @@
             });
         }
 
+        @Override
+        public void onClick(View v) {
+            mCheckbox.setChecked(!mCheckbox.isChecked());
+        }
+
         /**
          * Sets the text in the TextView children of this row to |languageName| and |nativeName|
          * respectively.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index bf78c48..b43056d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -22,7 +22,9 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.MarginLayoutParamsCompat;
 import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.SparseArray;
@@ -77,7 +79,6 @@
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.ScrimView.ScrimParams;
 import org.chromium.chrome.browser.widget.TintedDrawable;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -110,10 +111,10 @@
     private ScrimParams mScrimParams;
 
     protected ImageView mNavigationButton;
-    protected TintedImageButton mSecurityButton;
+    protected AppCompatImageButton mSecurityButton;
     protected TextView mVerboseStatusTextView;
-    protected TintedImageButton mDeleteButton;
-    protected TintedImageButton mMicButton;
+    protected AppCompatImageButton mDeleteButton;
+    protected AppCompatImageButton mMicButton;
     protected View mUrlBar;
     private final boolean mIsTablet;
 
@@ -395,12 +396,12 @@
         mIsTablet = DeviceFormFactor.isNonMultiDisplayContextOnTablet(context);
         mNavigationButtonType = mIsTablet ? NavigationButtonType.PAGE : NavigationButtonType.EMPTY;
 
-        mSecurityButton = (TintedImageButton) findViewById(R.id.security_button);
+        mSecurityButton = (AppCompatImageButton) findViewById(R.id.security_button);
         mSecurityIconResource = 0;
 
         mVerboseStatusTextView = (TextView) findViewById(R.id.location_bar_verbose_status);
 
-        mDeleteButton = (TintedImageButton) findViewById(R.id.delete_button);
+        mDeleteButton = (AppCompatImageButton) findViewById(R.id.delete_button);
 
         mUrlBar = findViewById(R.id.url_bar);
         mUrlCoordinator = new UrlBarCoordinator((UrlBar) mUrlBar);
@@ -409,7 +410,7 @@
         mSuggestionItems = new ArrayList<OmniboxResultItem>();
         mSuggestionListAdapter = new OmniboxResultsAdapter(getContext(), mSuggestionItems);
 
-        mMicButton = (TintedImageButton) findViewById(R.id.mic_button);
+        mMicButton = (AppCompatImageButton) findViewById(R.id.mic_button);
 
         mUrlActionContainer = (LinearLayout) findViewById(R.id.url_action_container);
 
@@ -1016,7 +1017,8 @@
         } else {
             // ImageView#setImageResource is no-op if given resource is the current one.
             mSecurityButton.setImageResource(id);
-            mSecurityButton.setTint(mToolbarDataProvider.getSecurityIconColorStateList());
+            ImageViewCompat.setImageTintList(
+                    mSecurityButton, mToolbarDataProvider.getSecurityIconColorStateList());
         }
 
         int contentDescriptionId = getToolbarDataProvider().getSecurityIconContentDescription();
@@ -2123,8 +2125,8 @@
         if (updateUseDarkColors()) updateSecurityIcon();
         int id = mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint;
         ColorStateList colorStateList = AppCompatResources.getColorStateList(getContext(), id);
-        mMicButton.setTint(colorStateList);
-        mDeleteButton.setTint(colorStateList);
+        ImageViewCompat.setImageTintList(mMicButton, colorStateList);
+        ImageViewCompat.setImageTintList(mDeleteButton, colorStateList);
 
         setNavigationButtonType(mNavigationButtonType);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java
index 2f42e70..4ae1304 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java
@@ -8,6 +8,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.widget.TextViewCompat;
+import android.support.v7.widget.AppCompatImageView;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -19,7 +20,6 @@
 import org.chromium.chrome.browser.download.DownloadDirectoryProvider;
 import org.chromium.chrome.browser.download.DownloadUtils;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
-import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.download.R;
 
 import java.util.ArrayList;
@@ -146,7 +146,7 @@
             }
         }
 
-        TintedImageView imageView = (TintedImageView) view.findViewById(R.id.icon_view);
+        AppCompatImageView imageView = (AppCompatImageView) view.findViewById(R.id.icon_view);
         imageView.setVisibility(View.GONE);
 
         return view;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/LanguageListBaseAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/LanguageListBaseAdapter.java
index ed7fa35..3cd386ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/LanguageListBaseAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/LanguageListBaseAdapter.java
@@ -11,6 +11,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.AppCompatImageView;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.support.v7.widget.helper.ItemTouchHelper;
@@ -25,7 +26,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.widget.ListMenuButton;
-import org.chromium.chrome.browser.widget.TintedImageView;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -52,7 +52,7 @@
         private TextView mTitle;
         private TextView mDescription;
 
-        private TintedImageView mStartIcon;
+        private AppCompatImageView mStartIcon;
         private ListMenuButton mMoreButton;
 
         LanguageRowViewHolder(View view) {
@@ -61,7 +61,7 @@
             mTitle = (TextView) view.findViewById(R.id.title);
             mDescription = (TextView) view.findViewById(R.id.description);
 
-            mStartIcon = (TintedImageView) view.findViewById(R.id.icon_view);
+            mStartIcon = (AppCompatImageView) view.findViewById(R.id.icon_view);
             mMoreButton = (ListMenuButton) view.findViewById(R.id.more);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index 021fbe6..695b294 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -13,6 +13,7 @@
 import android.os.Bundle;
 import android.support.annotation.StringRes;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.text.InputType;
 import android.text.SpannableString;
 import android.text.Spanned;
@@ -35,7 +36,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.PreferenceUtils;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.widget.Toast;
@@ -266,7 +266,7 @@
     }
 
     private void hookupCopyUsernameButton(View usernameView) {
-        final TintedImageButton copyUsernameButton =
+        final AppCompatImageButton copyUsernameButton =
                 usernameView.findViewById(R.id.password_entry_editor_copy);
         copyUsernameButton.setImageDrawable(
                 AppCompatResources.getDrawable(getActivity(), R.drawable.ic_content_copy_black));
@@ -288,7 +288,7 @@
     }
 
     private void hookupCopySiteButton(View siteView) {
-        final TintedImageButton copySiteButton =
+        final AppCompatImageButton copySiteButton =
                 siteView.findViewById(R.id.password_entry_editor_copy);
         copySiteButton.setContentDescription(
                 getActivity().getString(R.string.password_entry_editor_copy_stored_site));
@@ -362,7 +362,7 @@
     }
 
     private void hookupPasswordButtons() {
-        final TintedImageButton copyPasswordButton =
+        final AppCompatImageButton copyPasswordButton =
                 mView.findViewById(R.id.password_entry_editor_copy_password);
         final ImageButton viewPasswordButton =
                 mView.findViewById(R.id.password_entry_editor_view_password);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
index e1cf6e9..03e48c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBinder.java
@@ -16,6 +16,7 @@
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
 import android.support.v4.text.BidiFormatter;
+import android.support.v4.widget.ImageViewCompat;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.view.View;
@@ -36,7 +37,6 @@
 import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.util.ViewUtils;
-import org.chromium.chrome.browser.widget.TintedImageView;
 
 /**
  * This class is directly connected to suggestions view holders. It takes over the responsibility
@@ -252,7 +252,7 @@
         } else {
             mThumbnailView.setImageResource(R.drawable.ic_snippet_thumbnail_placeholder);
         }
-        if (!mIsContextual) ((TintedImageView) mThumbnailView).setTint(null);
+        if (!mIsContextual) ImageViewCompat.setImageTintList(mThumbnailView, null);
 
         // Fetch thumbnail for the current article.
         mImageFetcher.makeArticleThumbnailRequest(
@@ -301,7 +301,7 @@
         mThumbnailView.setScaleType(ImageView.ScaleType.CENTER_CROP);
         mThumbnailView.setBackground(null);
         mThumbnailView.setImageDrawable(thumbnail);
-        if (!mIsContextual) ((TintedImageView) mThumbnailView).setTint(null);
+        if (!mIsContextual) ImageViewCompat.setImageTintList(mThumbnailView, null);
     }
 
     private void setThumbnailFromFileType(@DownloadFilter.Type int fileType) {
@@ -313,7 +313,9 @@
         mThumbnailView.setBackgroundColor(iconBackgroundColor);
         mThumbnailView.setImageResource(
                 DownloadUtils.getIconResId(fileType, DownloadUtils.IconSize.DP_36));
-        if (!mIsContextual) ((TintedImageView) mThumbnailView).setTint(iconForegroundColorList);
+        if (!mIsContextual) {
+            ImageViewCompat.setImageTintList(mThumbnailView, iconForegroundColorList);
+        }
     }
 
     private void setDefaultFaviconOnView(int faviconSizePx) {
@@ -342,7 +344,7 @@
 
         mThumbnailView.setScaleType(ImageView.ScaleType.CENTER_CROP);
         mThumbnailView.setBackground(null);
-        if (!mIsContextual) ((TintedImageView) mThumbnailView).setTint(null);
+        if (!mIsContextual) ImageViewCompat.setImageTintList(mThumbnailView, null);
         int duration = (int) (FADE_IN_ANIMATION_TIME_MS
                 * ChromeAnimation.Animation.getAnimationMultiplier());
         if (duration == 0) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
index bdceb17..44106cdcb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.toolbar;
 
+import android.support.v7.widget.AppCompatImageButton;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -13,7 +14,6 @@
 import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
 import org.chromium.chrome.browser.toolbar.ToolbarButtonSlotData.ToolbarButtonData;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 
 /**
  * This class is responsible for pushing updates to both the Android view and the compositor
@@ -34,19 +34,19 @@
         /** A handle to the composited bottom toolbar layer. */
         public ScrollingBottomViewSceneLayer sceneLayer;
 
-        /** Cached {@link TintedImageButton} of the first button. */
-        public final TintedImageButton firstTintedImageButton;
+        /** Cached {@link android.support.v7.widget.AppCompatImageButton} of the first button. */
+        public final AppCompatImageButton firstImageButton;
 
-        /** Cached {@link TintedImageButton} of the second button. */
-        public final TintedImageButton secondTintedImageButton;
+        /** Cached {@link android.support.v7.widget.AppCompatImageButton} of the second button. */
+        public final AppCompatImageButton secondImageButton;
 
         /**
          * @param toolbarRootView The Android View based toolbar.
          */
         public ViewHolder(ScrollingBottomViewResourceFrameLayout toolbarRootView) {
             toolbarRoot = toolbarRootView;
-            firstTintedImageButton = toolbarRoot.findViewById(R.id.first_button);
-            secondTintedImageButton = toolbarRoot.findViewById(R.id.second_button);
+            firstImageButton = toolbarRoot.findViewById(R.id.first_button);
+            secondImageButton = toolbarRoot.findViewById(R.id.second_button);
         }
     }
 
@@ -86,18 +86,18 @@
         } else if (BottomToolbarModel.TOOLBAR_SWIPE_HANDLER == propertyKey) {
             view.toolbarRoot.setSwipeDetector(model.get(BottomToolbarModel.TOOLBAR_SWIPE_HANDLER));
         } else if (BottomToolbarModel.FIRST_BUTTON_DATA == propertyKey) {
-            updateButton(view.firstTintedImageButton,
-                    model.get(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons(model));
+            updateButton(view.firstImageButton, model.get(BottomToolbarModel.FIRST_BUTTON_DATA),
+                    useLightIcons(model));
         } else if (BottomToolbarModel.SECOND_BUTTON_DATA == propertyKey) {
-            updateButton(view.secondTintedImageButton,
-                    model.get(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons(model));
+            updateButton(view.secondImageButton, model.get(BottomToolbarModel.SECOND_BUTTON_DATA),
+                    useLightIcons(model));
         } else if (BottomToolbarModel.PRIMARY_COLOR == propertyKey) {
             final boolean useLightIcons = useLightIcons(model);
             view.toolbarRoot.findViewById(R.id.bottom_sheet_toolbar)
                     .setBackgroundColor(model.get(BottomToolbarModel.PRIMARY_COLOR));
-            updateButtonDrawable(view.firstTintedImageButton,
+            updateButtonDrawable(view.firstImageButton,
                     model.get(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons);
-            updateButtonDrawable(view.secondTintedImageButton,
+            updateButtonDrawable(view.secondImageButton,
                     model.get(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons);
         } else {
             assert false : "Unhandled property detected in BottomToolbarViewBinder!";
@@ -110,7 +110,7 @@
     }
 
     private static void updateButton(
-            TintedImageButton button, ToolbarButtonData buttonData, boolean useLightIcons) {
+            AppCompatImageButton button, ToolbarButtonData buttonData, boolean useLightIcons) {
         if (buttonData == null) {
             ToolbarButtonData.clearButton(button);
         } else {
@@ -119,7 +119,7 @@
     }
 
     private static void updateButtonDrawable(
-            TintedImageButton button, ToolbarButtonData buttonData, boolean useLightIcons) {
+            AppCompatImageButton button, ToolbarButtonData buttonData, boolean useLightIcons) {
         if (buttonData != null) buttonData.updateButtonDrawable(button, useLightIcons);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index 5d82548..799c412d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -23,6 +23,8 @@
 import android.support.annotation.Nullable;
 import android.support.v4.text.BidiFormatter;
 import android.support.v4.view.MarginLayoutParamsCompat;
+import android.support.v4.widget.ImageViewCompat;
+import android.support.v7.widget.AppCompatImageButton;
 import android.text.SpannableString;
 import android.text.TextUtils;
 import android.text.style.ForegroundColorSpan;
@@ -60,7 +62,6 @@
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.TintedDrawable;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.components.url_formatter.UrlFormatter;
 import org.chromium.content_public.common.ContentUrlConstants;
 import org.chromium.net.GURLUtils;
@@ -131,7 +132,7 @@
     private View mLiteStatusSeparatorView;
     private UrlBarCoordinator mUrlCoordinator;
     private TextView mTitleBar;
-    private TintedImageButton mSecurityButton;
+    private AppCompatImageButton mSecurityButton;
     private LinearLayout mCustomActionButtons;
     private ImageButton mCloseButton;
 
@@ -503,7 +504,8 @@
 
     private void updateButtonsTint() {
         if (getMenuButton() != null) {
-            getMenuButton().setTint(mUseDarkColors ? mDarkModeTint : mLightModeTint);
+            ImageViewCompat.setImageTintList(
+                    getMenuButton(), mUseDarkColors ? mDarkModeTint : mLightModeTint);
         }
         updateButtonTint(mCloseButton);
         int numCustomActionButtons = mCustomActionButtons.getChildCount();
@@ -549,7 +551,8 @@
         } else {
             // ImageView#setImageResource is no-op if given resource is the current one.
             mSecurityButton.setImageResource(securityIconResource);
-            mSecurityButton.setTint(getToolbarDataProvider().getSecurityIconColorStateList());
+            ImageViewCompat.setImageTintList(
+                    mSecurityButton, getToolbarDataProvider().getSecurityIconColorStateList());
             mAnimDelegate.showSecurityButton();
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java
index 29eba6c..7f13edf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.toolbar;
 
 import android.content.Context;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -16,14 +17,12 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.util.FeatureUtilities;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 
 /**
  * View that displays the home page button.
  */
-public class HomePageButton extends TintedImageButton
+public class HomePageButton extends AppCompatImageButton
         implements OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener {
-
     private static final int ID_REMOVE = 0;
 
     /** Constructor inflating from XML. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IncognitoToggleTabLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IncognitoToggleTabLayout.java
deleted file mode 100644
index 99a9d5a..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IncognitoToggleTabLayout.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2018 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.toolbar;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.support.design.widget.TabLayout;
-import android.support.v7.content.res.AppCompatResources;
-import android.util.AttributeSet;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
-import org.chromium.chrome.browser.tabmodel.TabModel;
-import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.widget.TintedImageView;
-
-/**
- * TabLayout shown in the Horizontal Tab Switcher.
- */
-public class IncognitoToggleTabLayout extends TabLayout {
-    private TabLayout.Tab mStandardButton;
-    private TabLayout.Tab mIncognitoButton;
-    private TintedImageView mStandardButtonIcon;
-    private TintedImageView mIncognitoButtonIcon;
-    private TabSwitcherDrawable mTabSwitcherDrawable;
-
-    private ColorStateList mTabIconDarkColor;
-    private ColorStateList mTabIconLightColor;
-    private ColorStateList mTabIconSelectedDarkColor;
-    private ColorStateList mTabIconSelectedLightColor;
-
-    private TabModelSelector mTabModelSelector;
-
-    /**
-     * Constructor for inflating from XML.
-     */
-    public IncognitoToggleTabLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        mTabIconDarkColor =
-                AppCompatResources.getColorStateList(getContext(), R.color.dark_mode_tint);
-        mTabIconSelectedDarkColor =
-                AppCompatResources.getColorStateList(getContext(), R.color.light_active_color);
-        mTabIconLightColor =
-                AppCompatResources.getColorStateList(getContext(), R.color.white_alpha_70);
-        mTabIconSelectedLightColor =
-                AppCompatResources.getColorStateList(getContext(), R.color.white_mode_tint);
-
-        mStandardButtonIcon = new TintedImageView(getContext());
-        mTabSwitcherDrawable = TabSwitcherDrawable.createTabSwitcherDrawable(getContext(), false);
-        mStandardButtonIcon.setImageDrawable(mTabSwitcherDrawable);
-        mIncognitoButtonIcon = new TintedImageView(getContext());
-        mIncognitoButtonIcon.setImageResource(R.drawable.incognito_simple);
-
-        mStandardButton =
-                newTab().setCustomView(mStandardButtonIcon)
-                        .setContentDescription(R.string.accessibility_tab_switcher_standard_stack);
-        addTab(mStandardButton);
-        mIncognitoButton =
-                newTab().setCustomView(mIncognitoButtonIcon)
-                        .setContentDescription(
-                                ChromeFeatureList.isEnabled(ChromeFeatureList.INCOGNITO_STRINGS)
-                                        ? R.string.accessibility_tab_switcher_private_stack
-                                        : R.string.accessibility_tab_switcher_incognito_stack);
-        addTab(mIncognitoButton);
-
-        addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
-            @Override
-            public void onTabSelected(TabLayout.Tab tab) {
-                setSelectedModel(mIncognitoButton.isSelected());
-            }
-
-            @Override
-            public void onTabUnselected(TabLayout.Tab tab) {}
-
-            @Override
-            public void onTabReselected(TabLayout.Tab tab) {}
-        });
-    }
-
-    /**
-     * @param selector A {@link TabModelSelector} to provide information about open tabs.
-     */
-    public void setTabModelSelector(TabModelSelector selector) {
-        mTabModelSelector = selector;
-        if (mTabModelSelector == null) return;
-        mTabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
-            @Override
-            public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
-                setStateBasedOnModel();
-            }
-        });
-        setStateBasedOnModel();
-    }
-
-    /**
-     * Update the visual state based on number of normal (non-incognito) tabs present.
-     * @param tabCount The number of normal tabs.
-     */
-    public void updateTabCount(int tabCount) {
-        mTabSwitcherDrawable.updateForTabCount(tabCount, false);
-    }
-
-    private void setStateBasedOnModel() {
-        if (mTabModelSelector == null) return;
-        final boolean isIncognitoSelected = mTabModelSelector.isIncognitoSelected();
-        if (isIncognitoSelected) {
-            setSelectedTabIndicatorColor(mTabIconSelectedLightColor.getDefaultColor());
-            mStandardButtonIcon.setTint(mTabIconLightColor);
-            mTabSwitcherDrawable.setTint(mTabIconLightColor);
-            mIncognitoButtonIcon.setTint(mTabIconSelectedLightColor);
-        } else {
-            setSelectedTabIndicatorColor(mTabIconSelectedDarkColor.getDefaultColor());
-            mStandardButtonIcon.setTint(mTabIconSelectedDarkColor);
-            mTabSwitcherDrawable.setTint(mTabIconSelectedDarkColor);
-            mIncognitoButtonIcon.setTint(mTabIconDarkColor);
-        }
-        // Ensure the tab in tab layout is correctly selected when tab switcher is
-        // first opened.
-        if (isIncognitoSelected && !mIncognitoButton.isSelected()) {
-            mIncognitoButton.select();
-        } else if (!isIncognitoSelected && !mStandardButton.isSelected()) {
-            mStandardButton.select();
-        }
-    }
-
-    private void setSelectedModel(boolean incognitoSelected) {
-        if (mTabModelSelector == null
-                || incognitoSelected == mTabModelSelector.isIncognitoSelected()) {
-            return;
-        }
-
-        mTabModelSelector.commitAllTabClosures();
-        mTabModelSelector.selectModel(incognitoSelected);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
index b48b03161..b93bafd39 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
@@ -6,21 +6,20 @@
 
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.support.v4.widget.ImageViewCompat;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.View.OnTouchListener;
 import android.widget.FrameLayout;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 
 /**
  * The overflow menu button.
  */
 class MenuButton extends FrameLayout {
-    /** The {@link TintedImageButton} for the menu button. */
-    private TintedImageButton mMenuTintedImageButton;
+    /** The {@link android.support.v7.widget.AppCompatImageButton} for the menu button. */
+    private AppCompatImageButton mMenuImageButton;
 
     /** The view for the update badge. */
     private View mUpdateBadgeView;
@@ -32,7 +31,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mMenuTintedImageButton = findViewById(R.id.menu_button);
+        mMenuImageButton = findViewById(R.id.menu_button);
         mUpdateBadgeView = findViewById(R.id.menu_badge);
     }
 
@@ -41,12 +40,12 @@
      *                        clicked.
      */
     void setTouchListener(OnTouchListener onTouchListener) {
-        mMenuTintedImageButton.setOnTouchListener(onTouchListener);
+        mMenuImageButton.setOnTouchListener(onTouchListener);
     }
 
     @Override
     public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
-        mMenuTintedImageButton.setAccessibilityDelegate(delegate);
+        mMenuImageButton.setAccessibilityDelegate(delegate);
     }
 
     /**
@@ -64,7 +63,7 @@
     }
 
     View getMenuButton() {
-        return mMenuTintedImageButton;
+        return mMenuImageButton;
     }
 
     /**
@@ -72,6 +71,6 @@
      *                 tinted).
      */
     void setTint(ColorStateList tintList) {
-        mMenuTintedImageButton.setTint(tintList);
+        ImageViewCompat.setImageTintList(mMenuImageButton, tintList);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java
index 8599e1f..c5089fef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java
@@ -13,11 +13,11 @@
 import android.graphics.drawable.Drawable;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.view.View;
 import android.view.View.OnClickListener;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
 /**
@@ -75,19 +75,19 @@
         }
 
         /**
-         * @param imageButton The {@link TintedImageButton} this button data will fill.
+         * @param imageButton The {@link AppCompatImageButton} this button data will fill.
          * @param isLight Whether or not to use light mode.
          */
-        void updateButton(TintedImageButton imageButton, boolean isLight) {
+        void updateButton(AppCompatImageButton imageButton, boolean isLight) {
             imageButton.setOnClickListener(mOnClickListener);
             updateButtonDrawable(imageButton, isLight);
         }
 
         /**
-         * @param imageButton The {@link TintedImageButton} this button data will fill.
+         * @param imageButton The {@link AppCompatImageButton} this button data will fill.
          * @param isLight Whether or not to use light mode.
          */
-        void updateButtonDrawable(TintedImageButton imageButton, boolean isLight) {
+        void updateButtonDrawable(AppCompatImageButton imageButton, boolean isLight) {
             ObjectAnimator fadeOutAnim =
                     ObjectAnimator.ofFloat(imageButton, View.ALPHA, 1.0f, 0.0f);
             fadeOutAnim.setDuration(FADE_DURATION / 2);
@@ -124,7 +124,7 @@
             animatorSet.start();
         }
 
-        static void clearButton(TintedImageButton button) {
+        static void clearButton(AppCompatImageButton button) {
             ToolbarButtonData emptyButtonData =
                     new ToolbarButtonData(null, "", "", null, button.getContext());
             emptyButtonData.updateButton(button, false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index 125178c0..f8cd899 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -18,6 +18,7 @@
 import android.support.annotation.StringRes;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -44,7 +45,6 @@
 import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.PulseDrawable;
 import org.chromium.chrome.browser.widget.ScrimView;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.ToolbarProgressBar;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
@@ -63,7 +63,7 @@
     /**
      * The ImageButton view that represents the menu button.
      */
-    protected TintedImageButton mMenuButton;
+    protected AppCompatImageButton mMenuButton;
     private ImageView mMenuBadge;
     private View mMenuButtonWrapper;
     private AppMenuButtonHelper mAppMenuButtonHelper;
@@ -156,7 +156,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mMenuButton = (TintedImageButton) findViewById(R.id.menu_button);
+        mMenuButton = (AppCompatImageButton) findViewById(R.id.menu_button);
         mMenuBadge = (ImageView) findViewById(R.id.menu_badge);
         mMenuButtonWrapper = findViewById(R.id.menu_button_wrapper);
 
@@ -306,9 +306,9 @@
     }
 
     /**
-     * @return The {@link TintedImageButton} containing the menu button.
+     * @return The {@link AppCompatImageButton} containing the menu button.
      */
-    protected TintedImageButton getMenuButton() {
+    protected AppCompatImageButton getMenuButton() {
         return mMenuButton;
     }
 
@@ -986,7 +986,7 @@
      * #onNativeLibraryReady() & once in #onFinishInflate() (see https://crbug.com/862887).
      * @param ntpButton The button that needs to be changed.
      */
-    protected void changeIconToNTPIcon(TintedImageButton ntpButton) {
+    protected void changeIconToNTPIcon(AppCompatImageButton ntpButton) {
         if (FeatureUtilities.isNewTabPageButtonEnabled())
             ntpButton.setImageResource(R.drawable.ic_home);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 789ce1d7..04a7af1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -30,7 +30,9 @@
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.view.animation.FastOutSlowInInterpolator;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.graphics.drawable.DrawableWrapper;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.util.TypedValue;
@@ -76,8 +78,8 @@
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.util.ViewUtils;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.animation.CancelAwareAnimatorListener;
+import org.chromium.chrome.browser.widget.incognitotoggle.IncognitoToggleButton;
 import org.chromium.chrome.browser.widget.newtab.NewTabButton;
 import org.chromium.chrome.browser.widget.textbubble.TextBubble;
 import org.chromium.components.feature_engagement.EventConstants;
@@ -144,14 +146,14 @@
     protected LocationBarPhone mLocationBar;
 
     protected ViewGroup mToolbarButtonsContainer;
-    private IncognitoToggleTabLayout mIncognitoToggleTabLayout;
+    private IncognitoToggleButton mIncognitoToggleButton;
     protected ImageView mToggleTabStackButton;
     protected NewTabButton mNewTabButton;
-    protected @Nullable TintedImageButton mHomeButton;
+    protected @Nullable AppCompatImageButton mHomeButton;
     private TextView mUrlBar;
     protected View mUrlActionContainer;
     protected ImageView mToolbarShadow;
-    private @Nullable TintedImageButton mExperimentalButton;
+    private @Nullable AppCompatImageButton mExperimentalButton;
 
     private final int mProgressBackBackgroundColorWhite;
 
@@ -194,6 +196,7 @@
 
     private OnClickListener mTabSwitcherListener;
     private OnClickListener mNewTabListener;
+    private OnClickListener mIncognitoListener;
 
     @ViewDebug.ExportedProperty(category = "chrome")
     protected boolean mUrlFocusChangeInProgress;
@@ -393,7 +396,7 @@
 
             mToolbarButtonsContainer = (ViewGroup) findViewById(R.id.toolbar_buttons);
 
-            mHomeButton = (TintedImageButton) findViewById(R.id.home_button);
+            mHomeButton = (AppCompatImageButton) findViewById(R.id.home_button);
             changeIconToNTPIcon(mHomeButton);
             if (FeatureUtilities.isBottomToolbarEnabled()) {
                 disableMenuButton();
@@ -493,7 +496,7 @@
         mToggleTabStackButton.setOnKeyListener(new KeyboardNavigationListener() {
             @Override
             public View getNextFocusForward() {
-                final TintedImageButton menuButton = getMenuButton();
+                final AppCompatImageButton menuButton = getMenuButton();
                 if (menuButton != null && menuButton.isShown()) {
                     return menuButton;
                 } else {
@@ -607,6 +610,8 @@
                 RecordUserAction.record("MobileNewTabOpened");
                 // TODO(kkimlabs): Record UMA action for homepage button.
             }
+        } else if (mIncognitoToggleButton == v) {
+            if (mIncognitoListener != null) mIncognitoListener.onClick(v);
         } else if (mHomeButton != null && mHomeButton == v) {
             openHomepage();
             if (isNativeLibraryReady()
@@ -807,7 +812,19 @@
      * @return The right bounds of the location bar after accounting for any visible left buttons.
      */
     protected int getBoundsAfterAccountingForRightButtons() {
-        return Math.max(mToolbarSidePadding, mToolbarButtonsContainer.getMeasuredWidth());
+        // We set the incognito toggle button's visibility from GONE to VISIBLE when the tab
+        // switcher starts to open, but we don't want this to affect the Omnibox's size during the
+        // animation, so we have to make an adjustment here.
+        // However, if the experimental button is showing it sits in a FrameLayout with the
+        // incognito button and the omnibox will be appropriately sized without an explicit
+        // adjustment.
+        int incognitoButtonWidth = 0;
+        if (mIncognitoToggleButton != null && mIncognitoToggleButton.getVisibility() == VISIBLE
+                && (mExperimentalButton == null || mExperimentalButton.getVisibility() == GONE)) {
+            incognitoButtonWidth += mIncognitoToggleButton.getMeasuredWidth();
+        }
+        return Math.max(mToolbarSidePadding,
+                mToolbarButtonsContainer.getMeasuredWidth() - incognitoButtonWidth);
     }
 
     protected void updateToolbarBackground(int color) {
@@ -1380,7 +1397,7 @@
         }
 
         // Draw the menu button if necessary.
-        final TintedImageButton menuButton = getMenuButton();
+        final AppCompatImageButton menuButton = getMenuButton();
         if (menuButton != null && !mShowMenuBadge && mTabSwitcherAnimationMenuDrawable != null
                 && mUrlExpansionPercent != 1f) {
             mTabSwitcherAnimationMenuDrawable.setBounds(menuButton.getPaddingLeft(),
@@ -1720,7 +1737,8 @@
     private void addHomeButton() {
         mHomeButton.setVisibility(
                 urlHasFocus() || isTabSwitcherAnimationRunning() ? INVISIBLE : VISIBLE);
-        mHomeButton.setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+        ColorStateList tintList = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
+        ImageViewCompat.setImageTintList(mHomeButton, tintList);
         mBrowsingModeViews.add(mHomeButton);
     }
 
@@ -1818,21 +1836,24 @@
 
         // Don't inflate the incognito toggle button unless the horizontal tab switcher experiment
         // is enabled and the user actually enters the tab switcher.
-        if (!FeatureUtilities.isBottomToolbarEnabled() && mIncognitoToggleTabLayout == null
+        if (!FeatureUtilities.isBottomToolbarEnabled() && mIncognitoToggleButton == null
                 && mTabSwitcherState != STATIC_TAB && usingHorizontalTabSwitcher()
                 && PrefServiceBridge.getInstance().isIncognitoModeEnabled()) {
-            ViewStub incognitoToggleTabsStub = findViewById(R.id.incognito_tabs_stub);
-            mIncognitoToggleTabLayout =
-                    (IncognitoToggleTabLayout) incognitoToggleTabsStub.inflate();
-            mIncognitoToggleTabLayout.setTabModelSelector(mTabModelSelector);
-            mTabSwitcherModeViews.add(mIncognitoToggleTabLayout);
-            mIncognitoToggleTabLayout.updateTabCount(mTabModelSelector.getModel(false).getCount());
-
-            mBrowsingModeViews.add(mToggleTabStackButton);
+            ViewStub incognitoToggleButtonStub = findViewById(R.id.incognito_button_stub);
+            mIncognitoToggleButton = (IncognitoToggleButton) incognitoToggleButtonStub.inflate();
+            mIncognitoToggleButton.setOnClickListener(this);
+            mIncognitoToggleButton.setTabModelSelector(mTabModelSelector);
+            mTabSwitcherModeViews.add(mIncognitoToggleButton);
         }
 
         for (View view : mTabSwitcherModeViews) {
-            view.setVisibility(tabSwitcherViewsVisibility);
+            // The incognito toggle button needs to be set to GONE rather than INVISIBLE so it
+            // doesn't reduce the space available for the Omnibox.
+            if (view == mIncognitoToggleButton && tabSwitcherViewsVisibility == INVISIBLE) {
+                view.setVisibility(GONE);
+            } else {
+                view.setVisibility(tabSwitcherViewsVisibility);
+            }
         }
         for (View view : mBrowsingModeViews) {
             view.setVisibility(browsingViewsVisibility);
@@ -1902,8 +1923,7 @@
         } else {
             if (!mDelayingTabSwitcherAnimation) {
                 mTabSwitcherModeAnimation = createExitTabSwitcherAnimation(showToolbar);
-                if (mIncognitoToggleTabLayout != null)
-                    mIncognitoToggleTabLayout.setClickable(false);
+                if (mIncognitoToggleButton != null) mIncognitoToggleButton.setClickable(false);
             }
         }
 
@@ -1936,7 +1956,7 @@
 
     @Override
     protected void onTabSwitcherTransitionFinished() {
-        if (mIncognitoToggleTabLayout != null) mIncognitoToggleTabLayout.setClickable(true);
+        if (mIncognitoToggleButton != null) mIncognitoToggleButton.setClickable(true);
 
         setAlpha(1.f);
         mClipRect = null;
@@ -1981,6 +2001,11 @@
     }
 
     @Override
+    public void setIncognitoClickHandler(OnClickListener listener) {
+        mIncognitoListener = listener;
+    }
+
+    @Override
     protected void onAccessibilityStatusChanged(boolean enabled) {
         super.onAccessibilityStatusChanged(enabled);
         if (mNewTabButton != null) mNewTabButton.onAccessibilityStatusChanged();
@@ -2235,10 +2260,6 @@
         mTabSwitcherButtonDrawableLight.updateForTabCount(numberOfTabs, isIncognito());
         mTabSwitcherButtonDrawable.updateForTabCount(numberOfTabs, isIncognito());
 
-        if (!isIncognito() && mIncognitoToggleTabLayout != null) {
-            mIncognitoToggleTabLayout.updateTabCount(numberOfTabs);
-        }
-
         boolean useTabStackDrawableLight = isIncognito()
                 || ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor());
         if (mTabSwitcherAnimationTabStackDrawable == null
@@ -2574,12 +2595,14 @@
         }
 
         if (getMenuButton() != null) {
-            getMenuButton().setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+            ColorStateList tintList = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
+            ImageViewCompat.setImageTintList(getMenuButton(), tintList);
         }
 
         updateModernLocationBarColor(getLocationBarColorForToolbarColor(currentPrimaryColor));
         if (mExperimentalButton != null) {
-            mExperimentalButton.setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+            ColorStateList tintList = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
+            ImageViewCompat.setImageTintList(mExperimentalButton, tintList);
         }
 
         setMenuButtonHighlightDrawable(mHighlightingMenu);
@@ -2587,7 +2610,9 @@
             setAppMenuUpdateBadgeDrawable(mUseLightToolbarDrawables);
         }
         ColorStateList tint = mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint;
-        if (mIsHomeButtonEnabled && mHomeButton != null) mHomeButton.setTint(tint);
+        if (mIsHomeButtonEnabled && mHomeButton != null) {
+            ImageViewCompat.setImageTintList(mHomeButton, tint);
+        }
 
         mLocationBar.updateVisualsForState();
 
@@ -2644,8 +2669,8 @@
     @Override
     public void setTabModelSelector(TabModelSelector selector) {
         mTabModelSelector = selector;
-        if (mIncognitoToggleTabLayout != null) {
-            mIncognitoToggleTabLayout.setTabModelSelector(mTabModelSelector);
+        if (mIncognitoToggleButton != null) {
+            mIncognitoToggleButton.setTabModelSelector(mTabModelSelector);
         }
     }
 
@@ -2689,7 +2714,7 @@
             OnClickListener onClickListener, int drawableResId, int contentDescriptionResId) {
         if (mExperimentalButton == null) {
             ViewStub viewStub = findViewById(R.id.experimental_button_stub);
-            mExperimentalButton = (TintedImageButton) viewStub.inflate();
+            mExperimentalButton = (AppCompatImageButton) viewStub.inflate();
 
             if (!isMenuButtonPresent()) mExperimentalButton.setPadding(0, 0, 0, 0);
             mExperimentalButtonTranslation = getResources().getDimensionPixelSize(
@@ -2708,7 +2733,8 @@
         mExperimentalButton.setImageResource(drawableResId);
         mExperimentalButton.setContentDescription(
                 getContext().getResources().getString(contentDescriptionResId));
-        mExperimentalButton.setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+        ImageViewCompat.setImageTintList(
+                mExperimentalButton, mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
 
         if (mTabSwitcherState == STATIC_TAB) {
             if (!mUrlFocusChangeInProgress && !urlHasFocus()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
index 9e034ac5..4626f83 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
@@ -11,7 +11,9 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.support.v4.view.ViewCompat;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -32,7 +34,6 @@
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.ArrayList;
@@ -47,13 +48,13 @@
     // The number of toolbar buttons that can be hidden at small widths (reload, back, forward).
     public static final int HIDEABLE_BUTTON_COUNT = 3;
 
-    private TintedImageButton mHomeButton;
-    private TintedImageButton mBackButton;
-    private TintedImageButton mForwardButton;
-    private TintedImageButton mReloadButton;
-    private TintedImageButton mBookmarkButton;
-    private TintedImageButton mSaveOfflineButton;
-    private TintedImageButton mSecurityButton;
+    private AppCompatImageButton mHomeButton;
+    private AppCompatImageButton mBackButton;
+    private AppCompatImageButton mForwardButton;
+    private AppCompatImageButton mReloadButton;
+    private AppCompatImageButton mBookmarkButton;
+    private AppCompatImageButton mSaveOfflineButton;
+    private AppCompatImageButton mSecurityButton;
     private ImageButton mAccessibilitySwitcherButton;
 
     private OnClickListener mBookmarkListener;
@@ -63,7 +64,7 @@
 
     private boolean mShowTabStack;
     private boolean mToolbarButtonsVisible;
-    private TintedImageButton[] mToolbarButtons;
+    private AppCompatImageButton[] mToolbarButtons;
 
     private NavigationPopup mNavigationPopup;
 
@@ -98,12 +99,12 @@
         super.onFinishInflate();
         mLocationBar = (LocationBarTablet) findViewById(R.id.location_bar);
 
-        mHomeButton = (TintedImageButton) findViewById(R.id.home_button);
+        mHomeButton = (AppCompatImageButton) findViewById(R.id.home_button);
         changeIconToNTPIcon(mHomeButton);
-        mBackButton = (TintedImageButton) findViewById(R.id.back_button);
-        mForwardButton = (TintedImageButton) findViewById(R.id.forward_button);
-        mReloadButton = (TintedImageButton) findViewById(R.id.refresh_button);
-        mSecurityButton = (TintedImageButton) findViewById(R.id.security_button);
+        mBackButton = (AppCompatImageButton) findViewById(R.id.back_button);
+        mForwardButton = (AppCompatImageButton) findViewById(R.id.forward_button);
+        mReloadButton = (AppCompatImageButton) findViewById(R.id.refresh_button);
+        mSecurityButton = (AppCompatImageButton) findViewById(R.id.security_button);
         mShowTabStack = AccessibilityUtil.isAccessibilityEnabled()
                 && isAccessibilityTabSwitcherPreferenceEnabled();
 
@@ -116,7 +117,7 @@
         mAccessibilitySwitcherButton.setImageDrawable(mTabSwitcherButtonDrawable);
         updateSwitcherButtonVisibility(mShowTabStack);
 
-        mBookmarkButton = (TintedImageButton) findViewById(R.id.bookmark_button);
+        mBookmarkButton = (AppCompatImageButton) findViewById(R.id.bookmark_button);
 
         final View menuButtonWrapper = getMenuButtonWrapper();
         menuButtonWrapper.setVisibility(View.VISIBLE);
@@ -127,13 +128,13 @@
                     getResources().getDimensionPixelSize(R.dimen.tablet_toolbar_end_padding), 0);
         }
 
-        mSaveOfflineButton = (TintedImageButton) findViewById(R.id.save_offline_button);
+        mSaveOfflineButton = (AppCompatImageButton) findViewById(R.id.save_offline_button);
 
         // Initialize values needed for showing/hiding toolbar buttons when the activity size
         // changes.
         mShouldAnimateButtonVisibilityChange = false;
         mToolbarButtonsVisible = true;
-        mToolbarButtons = new TintedImageButton[] {mBackButton, mForwardButton, mReloadButton};
+        mToolbarButtons = new AppCompatImageButton[] {mBackButton, mForwardButton, mReloadButton};
     }
 
     @Override
@@ -382,11 +383,16 @@
             setBackgroundColor(color);
             getProgressBar().setThemeColor(color, isIncognito());
 
-            getMenuButton().setTint(incognito ? mLightModeTint : mDarkModeTint);
-            mHomeButton.setTint(incognito ? mLightModeTint : mDarkModeTint);
-            mBackButton.setTint(incognito ? mLightModeTint : mDarkModeTint);
-            mForwardButton.setTint(incognito ? mLightModeTint : mDarkModeTint);
-            mSaveOfflineButton.setTint(incognito ? mLightModeTint : mDarkModeTint);
+            ImageViewCompat.setImageTintList(
+                    getMenuButton(), incognito ? mLightModeTint : mDarkModeTint);
+            ImageViewCompat.setImageTintList(
+                    mHomeButton, incognito ? mLightModeTint : mDarkModeTint);
+            ImageViewCompat.setImageTintList(
+                    mBackButton, incognito ? mLightModeTint : mDarkModeTint);
+            ImageViewCompat.setImageTintList(
+                    mForwardButton, incognito ? mLightModeTint : mDarkModeTint);
+            ImageViewCompat.setImageTintList(
+                    mSaveOfflineButton, incognito ? mLightModeTint : mDarkModeTint);
             if (incognito) {
                 mLocationBar.getContainerView().getBackground().setAlpha(
                         ToolbarPhone.LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA);
@@ -471,7 +477,8 @@
             mReloadButton.setContentDescription(getContext().getString(
                     R.string.accessibility_btn_refresh));
         }
-        mReloadButton.setTint(isIncognito() ? mLightModeTint : mDarkModeTint);
+        ImageViewCompat.setImageTintList(
+                mReloadButton, isIncognito() ? mLightModeTint : mDarkModeTint);
         mReloadButton.setEnabled(!mIsInTabSwitcherMode);
     }
 
@@ -480,14 +487,16 @@
         if (isBookmarked) {
             mBookmarkButton.setImageResource(R.drawable.btn_star_filled);
             // Non-incognito mode shows a blue filled star.
-            mBookmarkButton.setTint(isIncognito() ? mLightModeTint
-                                                  : AppCompatResources.getColorStateList(
-                                                            getContext(), R.color.blue_mode_tint));
+            ImageViewCompat.setImageTintList(mBookmarkButton,
+                    isIncognito() ? mLightModeTint
+                                  : AppCompatResources.getColorStateList(
+                                            getContext(), R.color.blue_mode_tint));
             mBookmarkButton.setContentDescription(getContext().getString(
                     R.string.edit_bookmark));
         } else {
             mBookmarkButton.setImageResource(R.drawable.btn_star);
-            mBookmarkButton.setTint(isIncognito() ? mLightModeTint : mDarkModeTint);
+            ImageViewCompat.setImageTintList(
+                    mBookmarkButton, isIncognito() ? mLightModeTint : mDarkModeTint);
             mBookmarkButton.setContentDescription(getContext().getString(
                     R.string.accessibility_menu_bookmark));
         }
@@ -604,7 +613,7 @@
         if (mShouldAnimateButtonVisibilityChange) {
             runToolbarButtonsVisibilityAnimation(visible);
         } else {
-            for (TintedImageButton button : mToolbarButtons) {
+            for (AppCompatImageButton button : mToolbarButtons) {
                 button.setVisibility(visible ? View.VISIBLE : View.GONE);
             }
             mLocationBar.setShouldShowButtonsWhenUnfocused(visible);
@@ -646,7 +655,7 @@
         Collection<Animator> animators = new ArrayList<>();
 
         // Create animators for all of the toolbar buttons.
-        for (TintedImageButton button : mToolbarButtons) {
+        for (AppCompatImageButton button : mToolbarButtons) {
             animators.add(mLocationBar.createShowButtonAnimator(button));
         }
 
@@ -660,7 +669,7 @@
         set.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                for (TintedImageButton button : mToolbarButtons) {
+                for (AppCompatImageButton button : mToolbarButtons) {
                     button.setVisibility(View.VISIBLE);
                 }
                 // Set the padding at the start of the animation so the toolbar buttons don't jump
@@ -681,7 +690,7 @@
         Collection<Animator> animators = new ArrayList<>();
 
         // Create animators for all of the toolbar buttons.
-        for (TintedImageButton button : mToolbarButtons) {
+        for (AppCompatImageButton button : mToolbarButtons) {
             animators.add(mLocationBar.createHideButtonAnimator(button));
         }
 
@@ -698,7 +707,7 @@
                 // Only set end visibility and alpha if the animation is ending because it's
                 // completely finished and not because it was canceled.
                 if (mToolbarButtons[0].getAlpha() == 0.f) {
-                    for (TintedImageButton button : mToolbarButtons) {
+                    for (AppCompatImageButton button : mToolbarButtons) {
                         button.setVisibility(View.GONE);
                         button.setAlpha(1.f);
                     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java
deleted file mode 100644
index ceca4af..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.widget;
-
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import org.chromium.chrome.R;
-
-/**
- * Utility for tinting an ImageView and its Drawable.
- *
- * Example usage in XML:
- * <ImageViewTinterInstanceOwner
- *     xmlns:android="http://schemas.android.com/apk/res/android"
- *     xmlns:app="http://schemas.android.com/apk/res-auto"
- *     app:chrometint="@color/default_icon_color_blue" />
- */
-public class ImageViewTinter {
-    /** Classes that own an ImageViewTinter must implement these functions. */
-    public static interface ImageViewTinterOwner {
-        /** See {@link ImageViewTinter#drawableStateChanged}. */
-        void drawableStateChanged();
-
-        /** See {@link ImageViewTinter#setTint}. */
-        void setTint(ColorStateList tintList);
-
-        /** See {@link ImageView#onDraw}. */
-        void onDraw(Canvas canvas);
-    }
-
-    private ImageView mImageView;
-    private ColorStateList mTintList;
-
-    /**
-     * Constructor.  Should be called with the AttributeSet and style of the ImageView so that XML
-     * attributes for it can be parsed.
-     * @param view     ImageView being tinted.
-     * @param attrs    AttributeSet that is pulled in from an XML layout.  May be null.
-     * @param defStyle Style that is pulled in from an XML layout.
-     */
-    public ImageViewTinter(ImageViewTinterOwner view, @Nullable AttributeSet attrs, int defStyle) {
-        mImageView = (ImageView) view;
-
-        // Parse out the attributes from the XML.
-        if (attrs != null) {
-            TypedArray a = mImageView.getContext().obtainStyledAttributes(
-                    attrs, R.styleable.TintedImage, defStyle, 0);
-            setTint(a.getColorStateList(R.styleable.TintedImage_chrometint));
-            a.recycle();
-        }
-    }
-
-    /**
-     * Sets the tint color for the given ImageView for all states.
-     * @param tintList The set of colors to use.
-     */
-    public void setTint(ColorStateList tintList) {
-        if (mTintList == tintList) return;
-        mTintList = tintList;
-        updateTintColor();
-    }
-
-    /** Call when the state of the Drawable has changed. */
-    public void drawableStateChanged() {
-        updateTintColor();
-    }
-
-    private void updateTintColor() {
-        if (mImageView.getDrawable() == null) {
-            return;
-        } else if (mTintList == null) {
-            mImageView.clearColorFilter();
-            return;
-        }
-
-        int tintColor = mTintList.getColorForState(mImageView.getDrawableState(), 0);
-        mImageView.setColorFilter(tintColor, PorterDuff.Mode.SRC_IN);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ListMenuButton.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ListMenuButton.java
index 86e4b26..6ce4179d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ListMenuButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ListMenuButton.java
@@ -9,6 +9,7 @@
 import android.graphics.Rect;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.StringRes;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -28,7 +29,7 @@
  * results.
  */
 public class ListMenuButton
-        extends TintedImageButton implements AnchoredPopupWindow.LayoutObserver {
+        extends AppCompatImageButton implements AnchoredPopupWindow.LayoutObserver {
     private final static int INVALID_RES_ID = 0;
 
     /** A class that represents a single item in the popup menu. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/TintedImageButton.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/TintedImageButton.java
deleted file mode 100644
index baf542e..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/TintedImageButton.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2014 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.widget;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-import android.util.AttributeSet;
-import android.widget.ImageButton;
-
-import org.chromium.chrome.browser.widget.ImageViewTinter.ImageViewTinterOwner;
-
-/**
- * Implementation of ImageButton that allows tinting the Drawable for all states.
- * For usage, see {@link ImageViewTinter}.
- */
-public class TintedImageButton extends ImageButton implements ImageViewTinterOwner {
-    private ImageViewTinter mTinter;
-
-    public TintedImageButton(Context context) {
-        super(context);
-        init(null, 0);
-    }
-
-    public TintedImageButton(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init(attrs, 0);
-    }
-
-    public TintedImageButton(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init(attrs, defStyle);
-    }
-
-    private void init(AttributeSet attrs, int defStyle) {
-        mTinter = new ImageViewTinter(this, attrs, defStyle);
-    }
-
-    @Override
-    public void drawableStateChanged() {
-        super.drawableStateChanged();
-        mTinter.drawableStateChanged();
-    }
-
-    @Override
-    public void setImageDrawable(@Nullable Drawable drawable) {
-        super.setImageDrawable(drawable);
-        maybeUpdateTint();
-    }
-
-    @Override
-    public void setImageResource(int resId) {
-        super.setImageResource(resId);
-        maybeUpdateTint();
-    }
-
-    @Override
-    public void setTint(ColorStateList tintList) {
-        mTinter.setTint(tintList);
-    }
-
-    @Override
-    public void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-    }
-
-    private void maybeUpdateTint() {
-        if (mTinter == null) {
-            // Got indirectly invoked from the superclass constructor, nothing to do yet.
-            return;
-        }
-        mTinter.drawableStateChanged();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/TintedImageView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/TintedImageView.java
deleted file mode 100644
index 61c2df7..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/TintedImageView.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2014 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.widget;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.AppCompatImageView;
-import android.util.AttributeSet;
-
-import org.chromium.chrome.browser.widget.ImageViewTinter.ImageViewTinterOwner;
-
-/**
- * Implementation of ImageView that allows tinting its Drawable for all states.
- * For usage, see {@link ImageViewTinter}.
- */
-public class TintedImageView extends AppCompatImageView implements ImageViewTinterOwner {
-    private ImageViewTinter mTinter;
-
-    public TintedImageView(Context context) {
-        super(context);
-        init(null, 0);
-    }
-
-    public TintedImageView(Context context, AttributeSet attrs) {
-        super(context, attrs, 0);
-        init(attrs, 0);
-    }
-
-    public TintedImageView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init(attrs, defStyle);
-    }
-
-    private void init(AttributeSet attrs, int defStyle) {
-        mTinter = new ImageViewTinter(this, attrs, defStyle);
-    }
-
-    @Override
-    public void drawableStateChanged() {
-        super.drawableStateChanged();
-        mTinter.drawableStateChanged();
-    }
-
-    @Override
-    public void setImageDrawable(@Nullable Drawable drawable) {
-        super.setImageDrawable(drawable);
-        maybeUpdateTint();
-    }
-
-    @Override
-    public void setImageResource(int resId) {
-        super.setImageResource(resId);
-        maybeUpdateTint();
-    }
-
-    @Override
-    public void setTint(ColorStateList tintList) {
-        mTinter.setTint(tintList);
-    }
-
-    @Override
-    public void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-    }
-
-    private void maybeUpdateTint() {
-        if (mTinter == null) {
-            // Got indirectly invoked from the superclass constructor, nothing to do yet.
-            return;
-        }
-        mTinter.drawableStateChanged();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java
index c8650e0..c34dbe1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelListItem.java
@@ -13,7 +13,10 @@
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.os.Handler;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
+import android.support.v7.widget.AppCompatImageView;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.GestureDetector;
@@ -34,8 +37,6 @@
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.chrome.browser.widget.TintedImageButton;
-import org.chromium.chrome.browser.widget.TintedImageView;
 
 /**
  * A widget that shows a single row of the {@link AccessibilityTabModelListView} list.
@@ -72,8 +73,8 @@
     private LinearLayout mTabContents;
     private TextView mTitleView;
     private TextView mDescriptionView;
-    private TintedImageView mFaviconView;
-    private TintedImageButton mCloseButton;
+    private AppCompatImageView mFaviconView;
+    private AppCompatImageButton mCloseButton;
 
     // The children on the undo view.
     private LinearLayout mUndoContents;
@@ -311,13 +312,13 @@
             mFaviconView.getBackground().setLevel(mIncognitoLevel);
             ApiCompatibilityUtils.setTextAppearance(mTitleView, R.style.WhiteTitle1);
             ApiCompatibilityUtils.setTextAppearance(mDescriptionView, R.style.WhiteBody);
-            mCloseButton.setTint(mLightCloseIconColor);
+            ImageViewCompat.setImageTintList(mCloseButton, mLightCloseIconColor);
         } else {
             setBackgroundResource(R.color.modern_primary_color);
             mFaviconView.getBackground().setLevel(mDefaultLevel);
             ApiCompatibilityUtils.setTextAppearance(mTitleView, R.style.BlackTitle1);
             ApiCompatibilityUtils.setTextAppearance(mDescriptionView, R.style.BlackBody);
-            mCloseButton.setTint(mDarkCloseIconColor);
+            ImageViewCompat.setImageTintList(mCloseButton, mDarkCloseIconColor);
         }
 
         if (TextUtils.isEmpty(url)) {
@@ -333,11 +334,11 @@
             Bitmap bitmap = mTab.getFavicon();
             if (bitmap != null) {
                 // Don't tint favicon bitmaps.
-                mFaviconView.setTint(null);
+                ImageViewCompat.setImageTintList(mFaviconView, null);
                 mFaviconView.setImageBitmap(bitmap);
             } else {
                 mFaviconView.setImageResource(R.drawable.ic_globe_24dp);
-                mFaviconView.setTint(mDarkIconColor);
+                ImageViewCompat.setImageTintList(mFaviconView, mDarkIconColor);
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
index 01930f8..d5f2c78 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
@@ -7,7 +7,9 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.support.design.widget.TabLayout;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageView;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -21,7 +23,6 @@
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
-import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.browser.widget.accessibility.AccessibilityTabModelAdapter.AccessibilityTabModelAdapterListener;
 
 /**
@@ -36,8 +37,8 @@
     private TabLayout mStackButtonWrapper;
     private TabLayout.Tab mStandardButton;
     private TabLayout.Tab mIncognitoButton;
-    private TintedImageView mStandardButtonIcon;
-    private TintedImageView mIncognitoButtonIcon;
+    private AppCompatImageView mStandardButtonIcon;
+    private AppCompatImageView mIncognitoButtonIcon;
 
     private ColorStateList mTabIconDarkColor;
     private ColorStateList mTabIconLightColor;
@@ -106,12 +107,12 @@
                 AppCompatResources.getColorStateList(getContext(), R.color.white_mode_tint);
         // Setting scaleY here to make sure the icons are not flipped due to the scaleY of its
         // container layout.
-        mStandardButtonIcon = new TintedImageView(getContext());
+        mStandardButtonIcon = new AppCompatImageView(getContext());
         mStandardButtonIcon.setImageResource(R.drawable.btn_normal_tabs);
         mStandardButtonIcon.setScaleY(-1.0f);
         mStandardButtonIcon.setContentDescription(
                 getResources().getString(R.string.accessibility_tab_switcher_standard_stack));
-        mIncognitoButtonIcon = new TintedImageView(getContext());
+        mIncognitoButtonIcon = new AppCompatImageView(getContext());
         mIncognitoButtonIcon.setImageResource(R.drawable.btn_incognito_tabs);
         mIncognitoButtonIcon.setScaleY(-1.0f);
         mIncognitoButtonIcon.setContentDescription(getResources().getString(
@@ -178,15 +179,15 @@
                     getResources(), R.color.incognito_modern_primary_color));
             mStackButtonWrapper.setSelectedTabIndicatorColor(
                     mTabIconSelectedLightColor.getDefaultColor());
-            mStandardButtonIcon.setTint(mTabIconLightColor);
-            mIncognitoButtonIcon.setTint(mTabIconSelectedLightColor);
+            ImageViewCompat.setImageTintList(mStandardButtonIcon, mTabIconLightColor);
+            ImageViewCompat.setImageTintList(mIncognitoButtonIcon, mTabIconSelectedLightColor);
         } else {
             setBackgroundColor(
                     ApiCompatibilityUtils.getColor(getResources(), R.color.modern_primary_color));
             mStackButtonWrapper.setSelectedTabIndicatorColor(
                     mTabIconSelectedDarkColor.getDefaultColor());
-            mStandardButtonIcon.setTint(mTabIconSelectedDarkColor);
-            mIncognitoButtonIcon.setTint(mTabIconDarkColor);
+            ImageViewCompat.setImageTintList(mStandardButtonIcon, mTabIconSelectedDarkColor);
+            ImageViewCompat.setImageTintList(mIncognitoButtonIcon, mTabIconDarkColor);
         }
         // Ensure the tab in tab layout is correctly selected when tab switcher is
         // first opened.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
index e24411c6..933f5c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
@@ -15,6 +15,7 @@
 import android.provider.Settings;
 import android.support.annotation.IntDef;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
+import android.support.v7.widget.AppCompatImageButton;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
@@ -45,7 +46,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.VerticallyFixedEditText;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -73,9 +73,9 @@
     // Toolbar UI
     private TextView mFindStatus;
     protected FindQuery mFindQuery;
-    protected TintedImageButton mCloseFindButton;
-    protected TintedImageButton mFindPrevButton;
-    protected TintedImageButton mFindNextButton;
+    protected AppCompatImageButton mCloseFindButton;
+    protected AppCompatImageButton mFindPrevButton;
+    protected AppCompatImageButton mFindNextButton;
 
     private FindResultBar mResultBar;
 
@@ -310,7 +310,7 @@
 
         mFindStatus = (TextView) findViewById(R.id.find_status);
 
-        mFindPrevButton = (TintedImageButton) findViewById(R.id.find_prev_button);
+        mFindPrevButton = (AppCompatImageButton) findViewById(R.id.find_prev_button);
         mFindPrevButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -318,7 +318,7 @@
             }
         });
 
-        mFindNextButton = (TintedImageButton) findViewById(R.id.find_next_button);
+        mFindNextButton = (AppCompatImageButton) findViewById(R.id.find_next_button);
         mFindNextButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -328,7 +328,7 @@
 
         setPrevNextEnabled(false);
 
-        mCloseFindButton = (TintedImageButton) findViewById(R.id.close_find_button);
+        mCloseFindButton = (AppCompatImageButton) findViewById(R.id.close_find_button);
         mCloseFindButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarPhone.java
index a2874a5..0685416 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbarPhone.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
 import android.view.View;
@@ -48,17 +49,17 @@
             setBackgroundColor(ColorUtils.getDefaultThemeColor(getResources(), true));
             ColorStateList white =
                     AppCompatResources.getColorStateList(getContext(), R.color.light_mode_tint);
-            mFindNextButton.setTint(white);
-            mFindPrevButton.setTint(white);
-            mCloseFindButton.setTint(white);
+            ImageViewCompat.setImageTintList(mFindNextButton, white);
+            ImageViewCompat.setImageTintList(mFindPrevButton, white);
+            ImageViewCompat.setImageTintList(mCloseFindButton, white);
             queryTextColorId = R.color.find_in_page_query_white_color;
         } else {
             setBackgroundColor(Color.WHITE);
             ColorStateList dark =
                     AppCompatResources.getColorStateList(getContext(), R.color.dark_mode_tint);
-            mFindNextButton.setTint(dark);
-            mFindPrevButton.setTint(dark);
-            mCloseFindButton.setTint(dark);
+            ImageViewCompat.setImageTintList(mFindNextButton, dark);
+            ImageViewCompat.setImageTintList(mFindPrevButton, dark);
+            ImageViewCompat.setImageTintList(mCloseFindButton, dark);
             queryTextColorId = R.color.default_text_color;
         }
         mFindQuery.setTextColor(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/incognitotoggle/IncognitoToggleButton.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/incognitotoggle/IncognitoToggleButton.java
index f0cc03a..f932324 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/incognitotoggle/IncognitoToggleButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/incognitotoggle/IncognitoToggleButton.java
@@ -6,7 +6,9 @@
 
 import android.content.Context;
 import android.support.annotation.StringRes;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.util.AttributeSet;
 import android.view.View;
 
@@ -16,7 +18,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 
 /**
  * A {@link View} that allows a user to toggle between incognito and normal {@link TabModel}s. This
@@ -24,7 +25,7 @@
  * TabModelSelector switches between normal and incognito modes. It can be subclassed (e.g. as is
  * done in IncognitoToggleButtonTablet) to add additional behaviors.
  */
-public class IncognitoToggleButton extends TintedImageButton {
+public class IncognitoToggleButton extends AppCompatImageButton {
     // TODO(crbug.com/843749): refactor this class so it doesn't need to hold a reference to
     // TabModelSelector.
     protected TabModelSelector mTabModelSelector;
@@ -73,8 +74,9 @@
      */
     protected void setImage(boolean isIncognitoSelected) {
         setImageResource(R.drawable.incognito_simple);
-        setTint(AppCompatResources.getColorStateList(getContext(),
-                isIncognitoSelected ? R.color.white_mode_tint : R.color.dark_mode_tint));
+        ImageViewCompat.setImageTintList(this,
+                AppCompatResources.getColorStateList(getContext(),
+                        isIncognitoSelected ? R.color.white_mode_tint : R.color.dark_mode_tint));
     }
 
     private void updateButtonResource() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
index 294b6e8..55f827ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableItemView.java
@@ -10,13 +10,14 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
+import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageView;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.widget.TintedDrawable;
-import org.chromium.chrome.browser.widget.TintedImageView;
 
 /**
  * Default implementation of SelectableItemViewBase.
@@ -28,7 +29,7 @@
     protected final int mSelectedLevel;
     protected final AnimatedVectorDrawableCompat mCheckDrawable;
 
-    protected TintedImageView mIconView;
+    protected AppCompatImageView mIconView;
     protected TextView mTitleView;
     protected TextView mDescriptionView;
     protected ColorStateList mIconColorList;
@@ -52,13 +53,13 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mIconView = (TintedImageView) findViewById(R.id.icon_view);
+        mIconView = (AppCompatImageView) findViewById(R.id.icon_view);
         mTitleView = (TextView) findViewById(R.id.title);
         mDescriptionView = (TextView) findViewById(R.id.description);
 
         if (mIconView != null) {
             mIconView.setBackgroundResource(R.drawable.list_item_icon_modern_bg);
-            mIconView.setTint(getDefaultIconTint());
+            ImageViewCompat.setImageTintList(mIconView, getDefaultIconTint());
         }
     }
 
@@ -82,12 +83,12 @@
         if (isChecked()) {
             mIconView.getBackground().setLevel(mSelectedLevel);
             mIconView.setImageDrawable(mCheckDrawable);
-            mIconView.setTint(mIconColorList);
+            ImageViewCompat.setImageTintList(mIconView, mIconColorList);
             mCheckDrawable.start();
         } else {
             mIconView.getBackground().setLevel(mDefaultLevel);
             mIconView.setImageDrawable(mIconDrawable);
-            mIconView.setTint(getDefaultIconTint());
+            ImageViewCompat.setImageTintList(mIconView, getDefaultIconTint());
         }
     }
 
@@ -112,7 +113,7 @@
      * @param isSelected    Whether the item is selected or not.
      */
     public static void applyModernIconStyle(
-            TintedImageView imageView, Drawable defaultIcon, boolean isSelected) {
+            AppCompatImageView imageView, Drawable defaultIcon, boolean isSelected) {
         imageView.setBackgroundResource(R.drawable.list_item_icon_modern_bg);
         imageView.setImageDrawable(isSelected
                         ? TintedDrawable.constructTintedDrawable(imageView.getContext(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
index 4fd14ee..1cd0dfb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/selection/SelectableListToolbar.java
@@ -16,6 +16,7 @@
 import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.content.res.AppCompatResources;
+import android.support.v7.widget.AppCompatImageButton;
 import android.support.v7.widget.Toolbar;
 import android.text.Editable;
 import android.text.TextUtils;
@@ -44,7 +45,6 @@
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.widget.NumberRollView;
 import org.chromium.chrome.browser.widget.TintedDrawable;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.displaystyle.DisplayStyleObserver;
 import org.chromium.chrome.browser.widget.displaystyle.HorizontalDisplayStyle;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
@@ -98,7 +98,7 @@
     private LinearLayout mSearchView;
     private EditText mSearchText;
     private EditText mSearchEditText;
-    private TintedImageButton mClearTextButton;
+    private AppCompatImageButton mClearTextButton;
     private SearchDelegate mSearchDelegate;
     private boolean mSearchEnabled;
     private boolean mIsVrEnabled;
@@ -296,7 +296,7 @@
             public void afterTextChanged(Editable s) {}
         });
 
-        mClearTextButton = (TintedImageButton) findViewById(R.id.clear_text_button);
+        mClearTextButton = (AppCompatImageButton) findViewById(R.id.clear_text_button);
         mClearTextButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 3f1434fc..a216bd58 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1502,7 +1502,6 @@
   "java/src/org/chromium/chrome/browser/toolbar/MenuButton.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java",
   "java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java",
-  "java/src/org/chromium/chrome/browser/toolbar/IncognitoToggleTabLayout.java",
   "java/src/org/chromium/chrome/browser/toolbar/KeyboardNavigationListener.java",
   "java/src/org/chromium/chrome/browser/toolbar/ScrollingBottomViewResourceFrameLayout.java",
   "java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java",
@@ -1622,7 +1621,6 @@
   "java/src/org/chromium/chrome/browser/widget/FadingShadow.java",
   "java/src/org/chromium/chrome/browser/widget/FadingShadowView.java",
   "java/src/org/chromium/chrome/browser/widget/FullscreenControlContainer.java",
-  "java/src/org/chromium/chrome/browser/widget/ImageViewTinter.java",
   "java/src/org/chromium/chrome/browser/widget/ListMenuButton.java",
   "java/src/org/chromium/chrome/browser/widget/LoadingView.java",
   "java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java",
@@ -1646,8 +1644,6 @@
   "java/src/org/chromium/chrome/browser/widget/ThumbnailProvider.java",
   "java/src/org/chromium/chrome/browser/widget/ThumbnailProviderImpl.java",
   "java/src/org/chromium/chrome/browser/widget/TintedDrawable.java",
-  "java/src/org/chromium/chrome/browser/widget/TintedImageButton.java",
-  "java/src/org/chromium/chrome/browser/widget/TintedImageView.java",
   "java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java",
   "java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java",
   "java/src/org/chromium/chrome/browser/widget/VerticallyFixedEditText.java",
@@ -2160,7 +2156,6 @@
   "javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/DualControlLayoutTest.java",
-  "javatests/src/org/chromium/chrome/browser/widget/ImageViewTinterTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/OverviewListLayoutTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/PromoDialogTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/RadioButtonLayoutTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java
index 48fc68b8..5137015 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/history/HistoryActivityTest.java
@@ -23,6 +23,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.espresso.intent.rule.IntentsTestRule;
 import android.support.test.filters.SmallTest;
+import android.support.v7.widget.AppCompatImageButton;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.text.TextUtils;
@@ -52,7 +53,6 @@
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
 import org.chromium.chrome.browser.signin.SignoutReason;
 import org.chromium.chrome.browser.widget.DateDividedAdapter;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 import org.chromium.chrome.browser.widget.selection.SelectableItemViewHolder;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate.SelectionObserver;
@@ -190,7 +190,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                ((TintedImageButton) itemView.findViewById(R.id.remove)).performClick();
+                ((AppCompatImageButton) itemView.findViewById(R.id.remove)).performClick();
             }
         });
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
index 0bc7323..0919498 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.omnibox;
 
 import android.support.test.filters.SmallTest;
+import android.support.v7.widget.AppCompatImageButton;
 import android.view.View;
 
 import org.junit.Assert;
@@ -24,7 +25,6 @@
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceTestUtils;
 import org.chromium.chrome.browser.toolbar.ToolbarModel;
-import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
@@ -131,16 +131,17 @@
         return (LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
     }
 
-    private TintedImageButton getDeleteButton() {
-        return (TintedImageButton) mActivityTestRule.getActivity().findViewById(R.id.delete_button);
+    private AppCompatImageButton getDeleteButton() {
+        return (AppCompatImageButton) mActivityTestRule.getActivity().findViewById(
+                R.id.delete_button);
     }
 
-    private TintedImageButton getMicButton() {
-        return (TintedImageButton) mActivityTestRule.getActivity().findViewById(R.id.mic_button);
+    private AppCompatImageButton getMicButton() {
+        return (AppCompatImageButton) mActivityTestRule.getActivity().findViewById(R.id.mic_button);
     }
 
-    private TintedImageButton getSecurityButton() {
-        return (TintedImageButton) mActivityTestRule.getActivity().findViewById(
+    private AppCompatImageButton getSecurityButton() {
+        return (AppCompatImageButton) mActivityTestRule.getActivity().findViewById(
                 R.id.security_button);
     }
 
@@ -269,7 +270,7 @@
         mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.NONE);
         setUrlToPageUrl(locationBar);
 
-        TintedImageButton securityButton = getSecurityButton();
+        AppCompatImageButton securityButton = getSecurityButton();
         Assert.assertNotEquals(SEARCH_TERMS, urlBar.getText().toString());
         ThreadUtils.runOnUiThreadBlocking(() -> {
             Assert.assertNotEquals(mTestToolbarModel.getSecurityIconResource(
@@ -289,7 +290,7 @@
         mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
-        TintedImageButton securityButton = getSecurityButton();
+        AppCompatImageButton securityButton = getSecurityButton();
         Assert.assertEquals(securityButton.getVisibility(), View.VISIBLE);
         ThreadUtils.runOnUiThreadBlocking(() -> {
             Assert.assertEquals(mTestToolbarModel.getSecurityIconResource(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ImageViewTinterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ImageViewTinterTest.java
deleted file mode 100644
index 9ec150a3d..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ImageViewTinterTest.java
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.widget;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.UiThreadTestRule;
-import android.support.v7.content.res.AppCompatResources;
-import android.view.LayoutInflater;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.ImageViewTinter.ImageViewTinterOwner;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-
-/**
- * Tests the classes that use ImageViewTinter.
- *
- * In an ideal world, these tests would simply use an XmlPullParser and XML that is defined inside
- * this test, but Android explicitly disallows that because it pre-processes the XML files:
- * https://developer.android.com/reference/android/view/LayoutInflater.html
- *
- * An alternative would be to have test-specific layout directories, but these don't seem to be
- * able to reference the instrumented package's resources.  Instead, the tests reference XML for
- * actual controls used in the production app.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-public class ImageViewTinterTest {
-    @Rule
-    public UiThreadTestRule mRule = new UiThreadTestRule();
-
-    private Context mContext;
-
-    @Before
-    public void setUp() throws Exception {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mContext.setTheme(R.style.MainTheme);
-    }
-
-    @Test
-    @SmallTest
-    public void testTintedImageView_attributeParsingExplicitTint() throws Exception {
-        // The tint is explicitly set to a blue in the XML.
-        int color = ApiCompatibilityUtils.getColor(mContext.getResources(), R.color.blue_mode_tint);
-        TintedImageView clearStorageView = (TintedImageView) LayoutInflater.from(mContext).inflate(
-                R.layout.clear_storage, null, false);
-        Assert.assertNotNull(clearStorageView.getColorFilter());
-        Assert.assertTrue(checkIfTintWasApplied(clearStorageView, color));
-    }
-
-    @Test
-    @SmallTest
-    public void testTintedImageButton_attributeParsingExplicitTint() throws Exception {
-        // The tint was explicitly set to a color.
-        int color = ApiCompatibilityUtils.getColor(mContext.getResources(), R.color.dark_mode_tint);
-        TintedImageButton colorTint =
-                createImageView(R.layout.search_toolbar, R.id.clear_text_button);
-        Assert.assertNotNull(colorTint.getColorFilter());
-        Assert.assertTrue(checkIfTintWasApplied(colorTint, color));
-    }
-
-    @Test
-    @SmallTest
-    public void testTintedImageView_attributeParsingNullTint() throws Exception {
-        // The tint is explicitly set to null in the XML.
-        int color = ApiCompatibilityUtils.getColor(mContext.getResources(), R.color.blue_mode_tint);
-        TintedImageView nullTint = createImageView(R.layout.title_button_menu_item, R.id.checkbox);
-        Assert.assertNull(nullTint.getColorFilter());
-        Assert.assertFalse(checkIfTintWasApplied(nullTint, color));
-    }
-
-    @Test
-    @SmallTest
-    public void testTintedImageButton_attributeParsingNullTint() throws Exception {
-        // The tint is explicitly set to null in the XML.  An image resource needs to be set here
-        // because the layout doesn't define one by default.
-        int color =
-                ApiCompatibilityUtils.getColor(mContext.getResources(), R.color.blue_when_enabled);
-        TintedImageButton nullTint = createImageView(R.layout.title_button_menu_item, R.id.button);
-        Assert.assertNull(nullTint.getColorFilter());
-        nullTint.setImageResource(R.drawable.plus);
-        Assert.assertFalse(checkIfTintWasApplied(nullTint, color));
-    }
-
-    @Test
-    @SmallTest
-    public void testTintedImageView_setTint() throws Exception {
-        // The tint is explicitly set to null for this object in the XML.
-        TintedImageView nullTint = createImageView(R.layout.title_button_menu_item, R.id.checkbox);
-        checkSetTintWorksCorrectly(nullTint);
-    }
-
-    @Test
-    @SmallTest
-    public void testTintedImageButton_setTint() throws Exception {
-        // The tint is explicitly set to null for this object in the XML.
-        TintedImageButton nullTint = createImageView(R.layout.title_button_menu_item, R.id.button);
-        checkSetTintWorksCorrectly(nullTint);
-    }
-
-    private void checkSetTintWorksCorrectly(ImageViewTinterOwner view) {
-        ImageView imageView = (ImageView) view;
-        int color = ApiCompatibilityUtils.getColor(
-                mContext.getResources(), R.color.default_icon_color_blue);
-
-        Assert.assertNull(imageView.getColorFilter());
-        if (imageView.getDrawable() == null) {
-            // An image resource is set here in case the layout does not define one.
-            imageView.setImageResource(R.drawable.plus);
-        }
-        Assert.assertFalse(checkIfTintWasApplied(view, color));
-
-        // Set the tint to one color.
-        ColorStateList colorList =
-                AppCompatResources.getColorStateList(mContext, R.color.light_active_color);
-        view.setTint(colorList);
-        Assert.assertNotNull(imageView.getColorFilter());
-        Assert.assertTrue(checkIfTintWasApplied(view, color));
-
-        // Clear it out.
-        view.setTint(null);
-        Assert.assertNull(imageView.getColorFilter());
-        Assert.assertFalse(checkIfTintWasApplied(view, color));
-
-        // Set it to another color.
-        int otherColor =
-                ApiCompatibilityUtils.getColor(mContext.getResources(), R.color.google_red_700);
-        ColorStateList otherColorList =
-                AppCompatResources.getColorStateList(mContext, R.color.google_red_700);
-        view.setTint(otherColorList);
-        Assert.assertNotNull(imageView.getColorFilter());
-        Assert.assertTrue(checkIfTintWasApplied(view, otherColor));
-    }
-
-    @SuppressWarnings("unchecked")
-    private <T extends ImageView> T createImageView(int layoutId, int ownerId) {
-        ViewGroup root = (ViewGroup) LayoutInflater.from(mContext).inflate(layoutId, null, false);
-        return (T) root.findViewById(ownerId);
-    }
-
-    private boolean checkIfTintWasApplied(
-            ImageViewTinterOwner imageViewTinterOwner, int expectedColor) {
-        int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        Assert.assertTrue(imageViewTinterOwner instanceof ImageView);
-        ImageView imageView = (ImageView) imageViewTinterOwner;
-        imageView.measure(unspecifiedSpec, unspecifiedSpec);
-        imageView.layout(0, 0, imageView.getMeasuredWidth(), imageView.getMeasuredHeight());
-
-        // Draw the ImageView into a Canvas so we can check that the tint was applied.
-        Drawable drawable = imageView.getDrawable();
-        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
-                drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        imageViewTinterOwner.onDraw(canvas);
-
-        // Search for any pixel that is of the expected color.
-        for (int x = 0; x < bitmap.getWidth(); x++) {
-            for (int y = 0; y < bitmap.getHeight(); y++) {
-                if (expectedColor == bitmap.getPixel(x, y)) return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 7457de4..dc892268 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-71.0.3566.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-71.0.3567.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
index dc7ebf9..49cd8e7 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java
@@ -118,6 +118,29 @@
         ThreadUtils.runOnUiThreadBlocking(() -> ProfileSyncService.resetForTests());
     }
 
+    /**
+     * Minimal test fixture to debug flakiness in the actual tests.
+     * TODO(crbug.com/879246): Remove after investigation.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Sync"})
+    public void testSetupOnly() {
+        mSyncTestRule.setUpTestAccountAndSignIn();
+    }
+
+    /**
+     * Minimal test fixture to debug flakiness in the actual tests.
+     * TODO(crbug.com/879246): Remove after investigation.
+     */
+    @Test
+    @SmallTest
+    @Feature({"Sync"})
+    public void testSetupAndWaitForSyncActive() {
+        mSyncTestRule.setUpTestAccountAndSignIn();
+        SyncTestUtil.waitForSyncActive();
+    }
+
     @Test
     @SmallTest
     @Feature({"Sync"})
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4adc6a2f..4099de8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1792,7 +1792,6 @@
     "//components/password_manager/content/browser",
     "//components/password_manager/core/browser",
     "//components/password_manager/core/common",
-    "//components/password_manager/sync/browser",
     "//components/payments/core",
     "//components/policy:generated",
     "//components/policy/content/",
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index b217fbc40..9b8865a 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -12,8 +12,10 @@
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/command_line.h"
+#include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/common/channel_info.h"
 #include "components/autofill_assistant/browser/controller.h"
+#include "components/variations/variations_associated_data.h"
 #include "components/version_info/channel.h"
 #include "content/public/browser/web_contents.h"
 #include "google_apis/google_api_keys.h"
@@ -143,6 +145,11 @@
   return api_key;
 }
 
+std::string UiControllerAndroid::GetServerUrl() {
+  return variations::GetVariationParamValueByFeature(
+      chrome::android::kAutofillAssistant, "url");
+}
+
 UiController* UiControllerAndroid::GetUiController() {
   return this;
 }
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index df4a9d7..64846ba 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -39,6 +39,7 @@
 
   // Overrides Client:
   std::string GetApiKey() override;
+  std::string GetServerUrl() override;
   UiController* GetUiController() override;
 
   // Called by Java.
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index fc2ed9d..25db3d6b 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/views_mode_controller.h"
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
 #include "chrome/common/chrome_switches.h"
@@ -1158,35 +1157,6 @@
   GetFirstAppWindow()->GetBaseWindow()->Close();
 }
 
-// This test currently only passes on OS X (on other platforms the print preview
-// dialog's size is limited by the size of the window being printed). It also
-// doesn't pass in Views mode on OS X.
-#if !defined(OS_MACOSX)
-#define MAYBE_PrintPreviewShouldNotBeTooSmall \
-  DISABLED_PrintPreviewShouldNotBeTooSmall
-#else
-#define MAYBE_PrintPreviewShouldNotBeTooSmall PrintPreviewShouldNotBeTooSmall
-#endif
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       MAYBE_PrintPreviewShouldNotBeTooSmall) {
-#if defined(OS_MACOSX)
-  if (!views_mode_controller::IsViewsBrowserCocoa())
-    return;
-#endif
-  // Print preview dialogs with widths less than 410 pixels will have preview
-  // areas that are too small, and ones with heights less than 191 pixels will
-  // have vertical scrollers for their controls that are too small.
-  gfx::Size minimum_dialog_size(410, 191);
-  ScopedPreviewTestingDelegate preview_delegate;
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
-  preview_delegate.WaitUntilPreviewIsReady();
-  EXPECT_GE(preview_delegate.dialog_size().width(),
-            minimum_dialog_size.width());
-  EXPECT_GE(preview_delegate.dialog_size().height(),
-            minimum_dialog_size.height());
-  GetFirstAppWindow()->GetBaseWindow()->Close();
-}
 #endif  // ENABLE_PRINT_PREVIEW
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc
index e4dfba4..46e6056 100644
--- a/chrome/browser/background/background_mode_manager_unittest.cc
+++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -35,9 +35,9 @@
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "components/keep_alive_registry/scoped_keep_alive.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/common/extension_builder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/image/image.h"
@@ -280,16 +280,6 @@
   }
 
  protected:
-  scoped_refptr<extensions::Extension> CreateExtension(
-      extensions::Manifest::Location location,
-      const std::string& data,
-      const std::string& id) {
-    std::unique_ptr<base::DictionaryValue> parsed_manifest(
-        extensions::api_test_utils::ParseDictionary(data));
-    return extensions::api_test_utils::CreateExtension(
-        location, parsed_manifest.get(), id);
-  }
-
   // From views::MenuModelAdapter::IsCommandEnabled with modification.
   bool IsCommandEnabled(ui::MenuModel* model, int id) const {
     int index = 0;
@@ -652,43 +642,31 @@
 }
 
 TEST_F(BackgroundModeManagerWithExtensionsTest, BackgroundMenuGeneration) {
-  scoped_refptr<extensions::Extension> component_extension(
-    CreateExtension(
-        extensions::Manifest::COMPONENT,
-        "{\"name\": \"Component Extension\","
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-1"));
+  scoped_refptr<const extensions::Extension> component_extension =
+      extensions::ExtensionBuilder("Component Extension")
+          .SetLocation(extensions::Manifest::COMPONENT)
+          .AddPermission("background")
+          .Build();
 
-  scoped_refptr<extensions::Extension> component_extension_with_options(
-    CreateExtension(
-        extensions::Manifest::COMPONENT,
-        "{\"name\": \"Component Extension with Options\","
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"],"
-        "\"options_page\": \"test.html\"}",
-        "ID-2"));
+  scoped_refptr<const extensions::Extension> component_extension_with_options =
+      extensions::ExtensionBuilder("Component Extension with Options")
+          .SetLocation(extensions::Manifest::COMPONENT)
+          .AddPermission("background")
+          .SetManifestKey("options_page", "test.html")
+          .Build();
 
-  scoped_refptr<extensions::Extension> regular_extension(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Regular Extension\", "
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-3"));
+  scoped_refptr<const extensions::Extension> regular_extension =
+      extensions::ExtensionBuilder("Regular Extension")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .Build();
 
-  scoped_refptr<extensions::Extension> regular_extension_with_options(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Regular Extension with Options\","
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"],"
-        "\"options_page\": \"test.html\"}",
-        "ID-4"));
+  scoped_refptr<const extensions::Extension> regular_extension_with_options =
+      extensions::ExtensionBuilder("Regular Extension with Options")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .SetManifestKey("options_page", "test.html")
+          .Build();
 
   static_cast<extensions::TestExtensionSystem*>(
       extensions::ExtensionSystem::Get(profile_))
@@ -728,43 +706,31 @@
 
 TEST_F(BackgroundModeManagerWithExtensionsTest,
        BackgroundMenuGenerationMultipleProfile) {
-  scoped_refptr<extensions::Extension> component_extension(
-    CreateExtension(
-        extensions::Manifest::COMPONENT,
-        "{\"name\": \"Component Extension\","
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-1"));
+  scoped_refptr<const extensions::Extension> component_extension =
+      extensions::ExtensionBuilder("Component Extension")
+          .SetLocation(extensions::Manifest::COMPONENT)
+          .AddPermission("background")
+          .Build();
 
-  scoped_refptr<extensions::Extension> component_extension_with_options(
-    CreateExtension(
-        extensions::Manifest::COMPONENT,
-        "{\"name\": \"Component Extension with Options\","
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"],"
-        "\"options_page\": \"test.html\"}",
-        "ID-2"));
+  scoped_refptr<const extensions::Extension> component_extension_with_options =
+      extensions::ExtensionBuilder("Component Extension with Options")
+          .SetLocation(extensions::Manifest::COMPONENT)
+          .AddPermission("background")
+          .SetManifestKey("options_page", "test.html")
+          .Build();
 
-  scoped_refptr<extensions::Extension> regular_extension(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Regular Extension\", "
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-3"));
+  scoped_refptr<const extensions::Extension> regular_extension =
+      extensions::ExtensionBuilder("Regular Extension")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .Build();
 
-  scoped_refptr<extensions::Extension> regular_extension_with_options(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Regular Extension with Options\","
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"],"
-        "\"options_page\": \"test.html\"}",
-        "ID-4"));
+  scoped_refptr<const extensions::Extension> regular_extension_with_options =
+      extensions::ExtensionBuilder("Regular Extension with Options")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .SetManifestKey("options_page", "test.html")
+          .Build();
 
   static_cast<extensions::TestExtensionSystem*>(
       extensions::ExtensionSystem::Get(profile_))
@@ -883,41 +849,32 @@
 }
 
 TEST_F(BackgroundModeManagerWithExtensionsTest, BalloonDisplay) {
-  scoped_refptr<extensions::Extension> bg_ext(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Background Extension\", "
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-1"));
+  scoped_refptr<const extensions::Extension> bg_ext =
+      extensions::ExtensionBuilder("Background Extension")
+          .SetVersion("1.0")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .Build();
 
-  scoped_refptr<extensions::Extension> upgraded_bg_ext(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Background Extension\", "
-        "\"version\": \"2.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-1"));
+  scoped_refptr<const extensions::Extension> upgraded_bg_ext =
+      extensions::ExtensionBuilder("Background Extension")
+          .SetVersion("2.0")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .Build();
 
-  scoped_refptr<extensions::Extension> no_bg_ext(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Regular Extension\", "
-        "\"version\": \"1.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": []}",
-        "ID-2"));
+  scoped_refptr<const extensions::Extension> no_bg_ext =
+      extensions::ExtensionBuilder("Regular Extension")
+          .SetVersion("1.0")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .Build();
 
-  scoped_refptr<extensions::Extension> upgraded_no_bg_ext_has_bg(
-    CreateExtension(
-        extensions::Manifest::COMMAND_LINE,
-        "{\"name\": \"Regular Extension\", "
-        "\"version\": \"2.0\","
-        "\"manifest_version\": 2,"
-        "\"permissions\": [\"background\"]}",
-        "ID-2"));
+  scoped_refptr<const extensions::Extension> upgraded_no_bg_ext_has_bg =
+      extensions::ExtensionBuilder("Regular Extension")
+          .SetVersion("1.0")
+          .SetLocation(extensions::Manifest::COMMAND_LINE)
+          .AddPermission("background")
+          .Build();
 
   static_cast<extensions::TestExtensionSystem*>(
       extensions::ExtensionSystem::Get(profile_))
diff --git a/chrome/browser/background_fetch/background_fetch_browsertest.cc b/chrome/browser/background_fetch/background_fetch_browsertest.cc
index 8f7bc11a..cca2f43f 100644
--- a/chrome/browser/background_fetch/background_fetch_browsertest.cc
+++ b/chrome/browser/background_fetch/background_fetch_browsertest.cc
@@ -506,6 +506,7 @@
   EXPECT_EQ(offline_item.title, GetExpectedTitle(kSingleFileDownloadTitle));
   EXPECT_EQ(offline_item.filter, OfflineItemFilter::FILTER_OTHER);
   EXPECT_TRUE(offline_item.is_transient);
+  EXPECT_TRUE(offline_item.is_resumable);
   EXPECT_FALSE(offline_item.is_suggested);
   EXPECT_FALSE(offline_item.is_off_the_record);
 
@@ -517,7 +518,6 @@
   // Change-detector tests for values we might want to provide or change.
   EXPECT_TRUE(offline_item.description.empty());
   EXPECT_TRUE(offline_item.page_url.is_empty());
-  EXPECT_FALSE(offline_item.is_resumable);
   EXPECT_FALSE(offline_item.is_off_the_record);
 }
 
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index efa22ba2..ec8c3cb 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -112,8 +112,9 @@
         base::StringPrintf("%s (%s)", fetch_description->title.c_str(),
                            fetch_description->origin.Serialize().c_str());
   }
-  // TODO(delphick): Figure out what to put in offline_item.description.
+
   offline_item.is_transient = true;
+  offline_item.is_resumable = true;
 
   using OfflineItemState = offline_items_collection::OfflineItemState;
   if (cancelled) {
@@ -519,11 +520,14 @@
 
 void BackgroundFetchDelegateImpl::CancelDownload(
     const offline_items_collection::ContentId& id) {
-  Abort(id.id);
+  // Save a copy before Abort() deletes the reference.
+  const std::string unique_id = id.id;
+  Abort(unique_id);
 
   if (client()) {
     client()->OnJobCancelled(
-        id.id, blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI);
+        unique_id,
+        blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI);
   }
 }
 
diff --git a/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc b/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc
index 05dbc16..1350390 100644
--- a/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_navigation_throttle_unittest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/browser_switcher/browser_switcher_service.h"
 #include "chrome/browser/browser_switcher/browser_switcher_service_factory.h"
 #include "chrome/browser/browser_switcher/browser_switcher_sitelist.h"
+#include "chrome/browser/browser_switcher/ieem_sitelist_parser.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/navigation_handle.h"
@@ -44,6 +45,8 @@
   ~MockBrowserSwitcherSitelist() override = default;
 
   MOCK_CONST_METHOD1(ShouldSwitch, bool(const GURL&));
+  MOCK_METHOD1(SetIeemSitelist, void(ParsedXml&&));
+  MOCK_METHOD1(SetExternalSitelist, void(ParsedXml&&));
 };
 
 class MockBrowserClient : public content::ContentBrowserClient {
diff --git a/chrome/browser/browser_switcher/browser_switcher_sitelist.cc b/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
index 3000c1c..7a2a47f 100644
--- a/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_sitelist.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/browser_switcher/browser_switcher_sitelist.h"
 
+#include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chrome/browser/browser_switcher/browser_switcher_prefs.h"
+#include "chrome/browser/browser_switcher/ieem_sitelist_parser.h"
 #include "components/prefs/pref_service.h"
 #include "url/gurl.h"
 
@@ -16,6 +18,13 @@
 
 namespace {
 
+// This type is cheap and lives on the stack, which can be faster compared to
+// calling |GURL::host()| multiple times.
+struct NoCopyUrl {
+  base::StringPiece host;
+  base::StringPiece spec;
+};
+
 // Returns true if |input| contains |token|, ignoring case for ASCII
 // characters.
 bool StringContainsInsensitiveASCII(base::StringPiece input,
@@ -36,65 +45,75 @@
   return (prefix.empty() || re2::RE2::FullMatch(converted_prefix, *re));
 }
 
-// URL is passed as a (url_spec, url_host) to avoid heap-allocating a string for
-// the host every time this is called.
-bool UrlMatches(base::StringPiece url_spec,
-                base::StringPiece url_host,
-                base::StringPiece pattern) {
+bool IsInverted(base::StringPiece pattern) {
+  return (!pattern.empty() && pattern[0] == '!');
+}
+
+bool UrlMatchesPattern(const NoCopyUrl& url, base::StringPiece pattern) {
   if (pattern == "*") {
     // Wildcard, always match.
     return true;
   }
   if (pattern.find('/') != base::StringPiece::npos) {
     // Check prefix using the normalized URL, case sensitive.
-    size_t pos = url_spec.find(pattern);
-    if (pos == std::string::npos)
+    size_t pos = url.spec.find(pattern);
+    if (pos == base::StringPiece::npos)
       return false;
-    return IsValidPrefix(base::StringPiece(url_spec.data(), pos));
+    return IsValidPrefix(base::StringPiece(url.spec.data(), pos));
   }
   // Compare hosts, case-insensitive.
-  return StringContainsInsensitiveASCII(url_host, pattern);
+  return StringContainsInsensitiveASCII(url.host, pattern);
 }
 
-// Checks whether |patterns| contains a pattern that matches |url|, and puts the
-// longest matching pattern in |*reason|.
+// Checks whether |patterns| contains a pattern that matches |url|, and returns
+// the longest matching pattern. If there are no matches, an empty pattern is
+// returned.
 //
 // If |contains_inverted_matches| is true, treat patterns that start with "!" as
-// inverted matches (which return false if matched).
-bool UrlListMatches(const GURL& url,
-                    const base::ListValue* patterns,
-                    bool contains_inverted_matches,
-                    base::StringPiece* reason) {
-  const std::string url_host = url.host();
-  const std::string& url_spec = url.spec();
-  *reason = "";
-  bool matched = false;
-  for (const base::Value& pattern_value : *patterns) {
-    if (!pattern_value.is_string())
+// inverted matches.
+base::StringPiece MatchUrlToList(const NoCopyUrl& url,
+                                 const std::vector<std::string>& patterns,
+                                 bool contains_inverted_matches) {
+  base::StringPiece reason;
+  for (const std::string& pattern : patterns) {
+    if (pattern.size() <= reason.size())
       continue;
-    base::StringPiece pattern = pattern_value.GetString();
-    if (pattern.size() <= reason->size())
-      continue;
-    bool inverted =
-        base::StartsWith(pattern, "!", base::CompareCase::SENSITIVE);
+    bool inverted = IsInverted(pattern);
     if (inverted && !contains_inverted_matches)
       continue;
-    if (UrlMatches(url_spec, url_host,
-                   (inverted ? pattern.substr(1) : pattern))) {
-      matched = !inverted;
-      *reason = pattern;
+    if (UrlMatchesPattern(url, (inverted ? pattern.substr(1) : pattern))) {
+      reason = pattern;
     }
   }
-  return matched;
+  return reason;
+}
+
+bool StringSizeCompare(const base::StringPiece& a, const base::StringPiece& b) {
+  return a.size() < b.size();
 }
 
 }  // namespace
 
-BrowserSwitcherSitelist::~BrowserSwitcherSitelist() {}
+BrowserSwitcherSitelistImpl::RuleSet::RuleSet() = default;
+BrowserSwitcherSitelistImpl::RuleSet::~RuleSet() = default;
+
+BrowserSwitcherSitelist::~BrowserSwitcherSitelist() = default;
 
 BrowserSwitcherSitelistImpl::BrowserSwitcherSitelistImpl(PrefService* prefs)
     : prefs_(prefs) {
   DCHECK(prefs_);
+  change_registrar_.Init(prefs);
+  change_registrar_.Add(
+      prefs::kUrlList,
+      base::BindRepeating(&BrowserSwitcherSitelistImpl::OnUrlListChanged,
+                          base::Unretained(this)));
+  change_registrar_.Add(
+      prefs::kUrlGreylist,
+      base::BindRepeating(&BrowserSwitcherSitelistImpl::OnGreylistChanged,
+                          base::Unretained(this)));
+  // Ensure |chrome_policies_| is initialized.
+  OnUrlListChanged();
+  OnGreylistChanged();
 }
 
 BrowserSwitcherSitelistImpl::~BrowserSwitcherSitelistImpl() {}
@@ -106,22 +125,57 @@
     return false;
   }
 
-  const base::ListValue* url_list = prefs_->GetList(prefs::kUrlList);
-  base::StringPiece reason_to_go;
-  bool should_go = UrlListMatches(url, url_list, true, &reason_to_go);
+  std::string url_host = url.host();
+  NoCopyUrl no_copy_url = {url_host, url.spec()};
 
-  const base::ListValue* url_greylist = prefs_->GetList(prefs::kUrlGreylist);
-  base::StringPiece reason_to_stay;
-  bool should_stay = UrlListMatches(url, url_greylist, false, &reason_to_stay);
+  base::StringPiece reason_to_go = std::max(
+      {
+          MatchUrlToList(no_copy_url, chrome_policies_.sitelist, true),
+          MatchUrlToList(no_copy_url, ieem_sitelist_.sitelist, true),
+          MatchUrlToList(no_copy_url, external_sitelist_.sitelist, true),
+      },
+      StringSizeCompare);
 
-  // Always prefer the more specific entry of the two lists.
-  if (should_stay) {
-    if (reason_to_go == "*")
-      return false;
-    if (!reason_to_go.empty() && reason_to_go.size() < reason_to_stay.size())
-      return false;
+  // If sitelists don't match, no need to check the greylists.
+  if (reason_to_go.empty() || IsInverted(reason_to_go)) {
+    return false;
   }
-  return should_go;
+
+  base::StringPiece reason_to_stay = std::max(
+      {
+          MatchUrlToList(no_copy_url, chrome_policies_.greylist, false),
+          MatchUrlToList(no_copy_url, ieem_sitelist_.greylist, false),
+          MatchUrlToList(no_copy_url, external_sitelist_.greylist, false),
+      },
+      StringSizeCompare);
+
+  if (reason_to_go == "*" && !reason_to_stay.empty())
+    return false;
+  return reason_to_go.size() >= reason_to_stay.size();
+}
+
+void BrowserSwitcherSitelistImpl::SetIeemSitelist(ParsedXml&& parsed_xml) {
+  DCHECK(!parsed_xml.error);
+  ieem_sitelist_.sitelist = std::move(parsed_xml.sitelist);
+  ieem_sitelist_.greylist = std::move(parsed_xml.greylist);
+}
+
+void BrowserSwitcherSitelistImpl::SetExternalSitelist(ParsedXml&& parsed_xml) {
+  DCHECK(!parsed_xml.error);
+  external_sitelist_.sitelist = std::move(parsed_xml.sitelist);
+  external_sitelist_.greylist = std::move(parsed_xml.greylist);
+}
+
+void BrowserSwitcherSitelistImpl::OnUrlListChanged() {
+  chrome_policies_.sitelist.clear();
+  for (const auto& url : *prefs_->GetList(prefs::kUrlList))
+    chrome_policies_.sitelist.push_back(url.GetString());
+}
+
+void BrowserSwitcherSitelistImpl::OnGreylistChanged() {
+  chrome_policies_.greylist.clear();
+  for (const auto& url : *prefs_->GetList(prefs::kUrlGreylist))
+    chrome_policies_.greylist.push_back(url.GetString());
 }
 
 }  // namespace browser_switcher
diff --git a/chrome/browser/browser_switcher/browser_switcher_sitelist.h b/chrome/browser/browser_switcher/browser_switcher_sitelist.h
index e7684bc..5369704 100644
--- a/chrome/browser/browser_switcher/browser_switcher_sitelist.h
+++ b/chrome/browser/browser_switcher/browser_switcher_sitelist.h
@@ -6,12 +6,15 @@
 #define CHROME_BROWSER_BROWSER_SWITCHER_BROWSER_SWITCHER_SITELIST_H_
 
 #include "base/macros.h"
+#include "components/prefs/pref_change_registrar.h"
 
 class PrefService;
 class GURL;
 
 namespace browser_switcher {
 
+class ParsedXml;
+
 // Interface that decides whether a navigation should trigger a browser
 // switch.
 class BrowserSwitcherSitelist {
@@ -20,6 +23,16 @@
 
   // Returns true if the given URL should be open in an alternative browser.
   virtual bool ShouldSwitch(const GURL& url) const = 0;
+
+  // Set the Internet Explorer Enterprise Mode sitelist to use, in addition to
+  // Chrome's sitelist/greylist policies. Consumes the object, and performs no
+  // copy.
+  virtual void SetIeemSitelist(ParsedXml&& sitelist) = 0;
+
+  // Set the XML sitelist file to use, in addition to Chrome's sitelist/greylist
+  // policies. This XML file is in the same format as an IEEM sitelist.
+  // Consumes the object, and performs no copy.
+  virtual void SetExternalSitelist(ParsedXml&& sitelist) = 0;
 };
 
 // Manages the sitelist configured by the administrator for
@@ -32,9 +45,27 @@
 
   // BrowserSwitcherSitelist
   bool ShouldSwitch(const GURL& url) const override;
+  void SetIeemSitelist(ParsedXml&& sitelist) override;
+  void SetExternalSitelist(ParsedXml&& sitelist) override;
 
  private:
+  void OnUrlListChanged();
+  void OnGreylistChanged();
+
+  struct RuleSet {
+    RuleSet();
+    ~RuleSet();
+
+    std::vector<std::string> sitelist;
+    std::vector<std::string> greylist;
+  };
+
+  RuleSet chrome_policies_;
+  RuleSet ieem_sitelist_;
+  RuleSet external_sitelist_;
+
   PrefService* const prefs_;
+  PrefChangeRegistrar change_registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserSwitcherSitelistImpl);
 };
diff --git a/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc b/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc
index 3b4c5b6..2e3b59e6 100644
--- a/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_sitelist_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/values.h"
 #include "chrome/browser/browser_switcher/browser_switcher_prefs.h"
+#include "chrome/browser/browser_switcher/ieem_sitelist_parser.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -35,6 +36,7 @@
     sitelist_ = std::make_unique<BrowserSwitcherSitelistImpl>(&prefs_);
   }
 
+  PrefService* prefs() { return &prefs_; }
   BrowserSwitcherSitelist* sitelist() { return sitelist_.get(); }
 
  private:
@@ -134,4 +136,59 @@
   EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("https://reddit.com/r/pics")));
 }
 
+TEST_F(BrowserSwitcherSitelistTest, ShouldPickUpPrefChanges) {
+  Initialize({}, {});
+  prefs()->Set(prefs::kUrlList, StringArrayToValue({"example.com"}));
+  prefs()->Set(prefs::kUrlGreylist, StringArrayToValue({"foo.example.com"}));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://example.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://bar.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://foo.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://google.com/")));
+}
+
+TEST_F(BrowserSwitcherSitelistTest, SetIeemSitelist) {
+  Initialize({}, {});
+  ParsedXml ieem;
+  ieem.sitelist = {"example.com"};
+  ieem.greylist = {"foo.example.com"};
+  sitelist()->SetIeemSitelist(std::move(ieem));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://example.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://bar.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://foo.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://google.com/")));
+}
+
+TEST_F(BrowserSwitcherSitelistTest, SetExternalSitelist) {
+  Initialize({}, {});
+  ParsedXml external;
+  external.sitelist = {"example.com"};
+  external.greylist = {"foo.example.com"};
+  sitelist()->SetExternalSitelist(std::move(external));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://example.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://bar.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://foo.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://google.com/")));
+}
+
+TEST_F(BrowserSwitcherSitelistTest, All3Sources) {
+  Initialize({"google.com"}, {"mail.google.com"});
+  ParsedXml ieem;
+  ieem.sitelist = {"example.com"};
+  ieem.greylist = {"foo.example.com"};
+  sitelist()->SetIeemSitelist(std::move(ieem));
+  ParsedXml external;
+  external.sitelist = {"yahoo.com"};
+  external.greylist = {"finance.yahoo.com"};
+  sitelist()->SetExternalSitelist(std::move(external));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://google.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://drive.google.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://mail.google.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://example.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://bar.example.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://foo.example.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://yahoo.com/")));
+  EXPECT_TRUE(sitelist()->ShouldSwitch(GURL("http://news.yahoo.com/")));
+  EXPECT_FALSE(sitelist()->ShouldSwitch(GURL("http://finance.yahoo.com/")));
+}
+
 }  // namespace browser_switcher
diff --git a/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc b/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
index c0b7ca4d..5f77334 100644
--- a/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
+++ b/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
@@ -74,8 +74,8 @@
     base::WaitableEvent waitable_event(
         base::WaitableEvent::ResetPolicy::AUTOMATIC,
         base::WaitableEvent::InitialState::NOT_SIGNALED);
-    store_->ScheduleTask(base::Bind(&base::WaitableEvent::Signal,
-                                    base::Unretained(&waitable_event)));
+    store_->ScheduleTask(base::BindOnce(&base::WaitableEvent::Signal,
+                                        base::Unretained(&waitable_event)));
     waitable_event.Wait();
 
     // At this point, the calculation on DB thread should have finished, and
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index f2f94ab1..976f240 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -101,6 +101,7 @@
     "//chromeos/services/multidevice_setup/public/cpp:prefs",
     "//chromeos/services/secure_channel/public/cpp/client",
     "//components/arc",
+    "//components/arc/common:struct_traits",
     "//components/browser_sync",
     "//components/captive_portal",
     "//components/component_updater:crl_set_remover",
@@ -445,6 +446,8 @@
     "arc/input_method_manager/arc_input_method_manager_bridge_impl.h",
     "arc/input_method_manager/arc_input_method_manager_service.cc",
     "arc/input_method_manager/arc_input_method_manager_service.h",
+    "arc/input_method_manager/input_connection_impl.cc",
+    "arc/input_method_manager/input_connection_impl.h",
     "arc/intent_helper/arc_external_protocol_dialog.cc",
     "arc/intent_helper/arc_external_protocol_dialog.h",
     "arc/intent_helper/arc_navigation_throttle.cc",
diff --git a/chrome/browser/chromeos/arc/downloads_watcher/OWNERS b/chrome/browser/chromeos/arc/downloads_watcher/OWNERS
new file mode 100644
index 0000000..3de9873
--- /dev/null
+++ b/chrome/browser/chromeos/arc/downloads_watcher/OWNERS
@@ -0,0 +1,2 @@
+hashimoto@chromium.org
+nya@chromium.org
diff --git a/chrome/browser/chromeos/arc/fileapi/OWNERS b/chrome/browser/chromeos/arc/fileapi/OWNERS
new file mode 100644
index 0000000..3de9873
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/OWNERS
@@ -0,0 +1,2 @@
+hashimoto@chromium.org
+nya@chromium.org
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h
index 9269c7a..186621ce 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h
@@ -20,15 +20,9 @@
 
   // Received mojo calls and connection state changes are passed to this
   // delegate.
-  class Delegate {
+  class Delegate : public mojom::InputMethodManagerHost {
    public:
-    virtual ~Delegate() = default;
-
-    // Mojo calls:
-    virtual void OnActiveImeChanged(const std::string& ime_id) = 0;
-    virtual void OnImeDisabled(const std::string& ime_id) = 0;
-    virtual void OnImeInfoChanged(
-        const std::vector<mojom::ImeInfoPtr> ime_info_array) = 0;
+    ~Delegate() override = default;
 
     // Mojo connection state changes:
     virtual void OnConnectionClosed() = 0;
@@ -45,6 +39,9 @@
                              EnableImeCallback callback) = 0;
   virtual void SendSwitchImeTo(const std::string& ime_id,
                                SwitchImeToCallback callback) = 0;
+  virtual void SendFocus(mojom::InputConnectionPtr connection,
+                         mojom::TextInputStatePtr state) = 0;
+  virtual void SendUpdateTextInputState(mojom::TextInputStatePtr state) = 0;
 };
 
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc
index dbf4eca8..512e7ed 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc
@@ -54,6 +54,33 @@
   imm_instance->SwitchImeTo(ime_id, std::move(callback));
 }
 
+void ArcInputMethodManagerBridgeImpl::SendFocus(
+    mojom::InputConnectionPtr connection,
+    mojom::TextInputStatePtr state) {
+  auto* imm_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      bridge_service_->input_method_manager(), Focus);
+  if (!imm_instance)
+    return;
+
+  if (!base::FeatureList::IsEnabled(kEnableInputMethodFeature))
+    return;
+
+  imm_instance->Focus(std::move(connection), std::move(state));
+}
+
+void ArcInputMethodManagerBridgeImpl::SendUpdateTextInputState(
+    mojom::TextInputStatePtr state) {
+  auto* imm_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      bridge_service_->input_method_manager(), UpdateTextInputState);
+  if (!imm_instance)
+    return;
+
+  if (!base::FeatureList::IsEnabled(kEnableInputMethodFeature))
+    return;
+
+  imm_instance->UpdateTextInputState(std::move(state));
+}
+
 void ArcInputMethodManagerBridgeImpl::OnConnectionClosed() {
   delegate_->OnConnectionClosed();
 }
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h
index a135615..fa817c6d 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h
@@ -31,6 +31,9 @@
                      EnableImeCallback callback) override;
   void SendSwitchImeTo(const std::string& ime_id,
                        SwitchImeToCallback callback) override;
+  void SendFocus(mojom::InputConnectionPtr connection,
+                 mojom::TextInputStatePtr state) override;
+  void SendUpdateTextInputState(mojom::TextInputStatePtr state) override;
 
   // ConnectionObserver<mojom::InputMethodManagerInstance> overrides:
   void OnConnectionClosed() override;
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
index 35b7242..98a450d 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
@@ -20,11 +20,14 @@
 #include "chrome/common/pref_names.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "components/arc/arc_features.h"
+#include "components/arc/common/ime_struct_traits.h"
 #include "components/crx_file/id_util.h"
 #include "components/prefs/pref_service.h"
 #include "ui/base/ime/chromeos/component_extension_ime_manager.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_util.h"
+#include "ui/base/ime/ime_bridge.h"
+#include "ui/keyboard/keyboard_util.h"
 
 namespace arc {
 
@@ -89,15 +92,17 @@
 class ArcInputMethodManagerService::ArcProxyInputMethodObserver
     : public input_method::InputMethodEngineBase::Observer {
  public:
-  ArcProxyInputMethodObserver() = default;
+  explicit ArcProxyInputMethodObserver(ArcInputMethodManagerService* owner)
+      : owner_(owner) {}
   ~ArcProxyInputMethodObserver() override = default;
 
   // input_method::InputMethodEngineBase::Observer overrides:
-  // TODO(yhanada): Implement below methods to forward those events to ARC.
   void OnActivate(const std::string& engine_id) override {}
   void OnFocus(
-      const ui::IMEEngineHandlerInterface::InputContext& context) override {}
-  void OnBlur(int context_id) override {}
+      const ui::IMEEngineHandlerInterface::InputContext& context) override {
+    owner_->Focus(context.id);
+  }
+  void OnBlur(int context_id) override { owner_->Blur(); }
   void OnKeyEvent(
       const std::string& engine_id,
       const input_method::InputMethodEngineBase::KeyboardEvent& event,
@@ -105,21 +110,32 @@
   void OnReset(const std::string& engine_id) override {}
   void OnDeactivated(const std::string& engine_id) override {}
   void OnCompositionBoundsChanged(
-      const std::vector<gfx::Rect>& bounds) override {}
+      const std::vector<gfx::Rect>& bounds) override {
+    owner_->UpdateTextInputState();
+  }
   bool IsInterestedInKeyEvent() const override { return false; }
   void OnSurroundingTextChanged(const std::string& engine_id,
                                 const std::string& text,
                                 int cursor_pos,
                                 int anchor_pos,
-                                int offset_pos) override {}
+                                int offset_pos) override {
+    owner_->UpdateTextInputState();
+  }
   void OnInputContextUpdate(
-      const ui::IMEEngineHandlerInterface::InputContext& context) override {}
+      const ui::IMEEngineHandlerInterface::InputContext& context) override {
+    owner_->UpdateTextInputState();
+  }
   void OnCandidateClicked(
       const std::string& component_id,
       int candidate_id,
       input_method::InputMethodEngineBase::MouseButtonEvent button) override {}
   void OnMenuItemActivated(const std::string& component_id,
                            const std::string& menu_id) override {}
+
+ private:
+  ArcInputMethodManagerService* const owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcProxyInputMethodObserver);
 };
 
 class ArcInputMethodManagerService::TabletModeObserver
@@ -170,8 +186,9 @@
   imm->AddObserver(this);
   imm->AddImeMenuObserver(this);
 
-  proxy_ime_engine_->Initialize(std::make_unique<ArcProxyInputMethodObserver>(),
-                                proxy_ime_extension_id_.c_str(), profile_);
+  proxy_ime_engine_->Initialize(
+      std::make_unique<ArcProxyInputMethodObserver>(this),
+      proxy_ime_extension_id_.c_str(), profile_);
 
   // TabletModeClient should be already created here because it's created in
   // PreProfileInit() and this service is created in PostProfileInit().
@@ -352,6 +369,11 @@
   SwitchImeTo(state->GetCurrentInputMethod().id());
 }
 
+InputConnectionImpl*
+ArcInputMethodManagerService::GetInputConnectionForTesting() {
+  return active_connection_.get();
+}
+
 void ArcInputMethodManagerService::EnableIme(const std::string& ime_id,
                                              bool enable) {
   auto component_id =
@@ -380,6 +402,28 @@
       component_id, base::BindOnce(&SwitchImeToCallback, ime_id, component_id));
 }
 
+void ArcInputMethodManagerService::Focus(int context_id) {
+  DCHECK(!active_connection_);
+  active_connection_ = std::make_unique<InputConnectionImpl>(
+      proxy_ime_engine_.get(), imm_bridge_.get(), context_id);
+  mojom::InputConnectionPtr connection_ptr;
+  active_connection_->Bind(&connection_ptr);
+
+  imm_bridge_->SendFocus(std::move(connection_ptr),
+                         active_connection_->GetTextInputState(false));
+}
+
+void ArcInputMethodManagerService::Blur() {
+  active_connection_.reset();
+}
+
+void ArcInputMethodManagerService::UpdateTextInputState() {
+  if (!active_connection_)
+    return;
+  active_connection_->UpdateTextInputState(
+      false /* is_input_state_update_requested */);
+}
+
 chromeos::input_method::InputMethodDescriptor
 ArcInputMethodManagerService::BuildInputMethodDescriptor(
     const mojom::ImeInfo* info) {
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h
index 4192072..315cf3a 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h
@@ -12,6 +12,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h"
+#include "chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.h"
 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
 #include "components/arc/common/input_method_manager.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -66,6 +67,8 @@
                           Profile* profile,
                           bool show_message) override;
 
+  InputConnectionImpl* GetInputConnectionForTesting();
+
  private:
   class ArcProxyInputMethodObserver;
   class TabletModeObserver;
@@ -74,6 +77,11 @@
   void SwitchImeTo(const std::string& ime_id);
   chromeos::input_method::InputMethodDescriptor BuildInputMethodDescriptor(
       const mojom::ImeInfo* info);
+  void Focus(int input_context_id);
+  void Blur();
+  void UpdateTextInputState();
+  mojom::TextInputStatePtr GetTextInputState(
+      bool is_input_state_update_requested);
 
   // Removes ARC IME from IME related prefs that are current active IME pref,
   // previous active IME pref, enabled IME list pref and preloading IME list
@@ -98,6 +106,8 @@
   const std::string proxy_ime_extension_id_;
   std::unique_ptr<chromeos::InputMethodEngine> proxy_ime_engine_;
 
+  std::unique_ptr<InputConnectionImpl> active_connection_;
+
   std::unique_ptr<TabletModeObserver> tablet_mode_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcInputMethodManagerService);
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
index c45b34b..f29cc82 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "chrome/common/pref_names.h"
@@ -25,6 +26,11 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/mock_input_method_manager.h"
+#include "ui/base/ime/dummy_text_input_client.h"
+#include "ui/base/ime/ime_bridge.h"
+#include "ui/base/ime/mock_ime_input_context_handler.h"
+#include "ui/base/ime/mock_input_method.h"
+#include "ui/keyboard/keyboard_controller.h"
 
 namespace arc {
 namespace {
@@ -57,7 +63,7 @@
         const im::InputMethodDescriptors& descriptors,
         ui::IMEEngineHandlerInterface* instance) override {
       added_input_method_extensions_.push_back(
-          std::make_tuple(extension_id, descriptors));
+          std::make_tuple(extension_id, descriptors, instance));
     }
 
     void RemoveInputMethodExtension(const std::string& extension_id) override {
@@ -110,7 +116,9 @@
              base::ContainsValue(allowed_input_methods_, ime_id);
     }
 
-    std::vector<std::tuple<std::string, im::InputMethodDescriptors>>
+    std::vector<std::tuple<std::string,
+                           im::InputMethodDescriptors,
+                           ui::IMEEngineHandlerInterface*>>
         added_input_method_extensions_;
     std::vector<std::string> removed_input_method_extensions_;
     std::vector<std::string> enabled_input_methods_;
@@ -142,6 +150,19 @@
   DISALLOW_COPY_AND_ASSIGN(TestInputMethodManager);
 };
 
+class TestIMEInputContextHandler : public ui::MockIMEInputContextHandler {
+ public:
+  explicit TestIMEInputContextHandler(ui::InputMethod* input_method)
+      : input_method_(input_method) {}
+
+  ui::InputMethod* GetInputMethod() override { return input_method_; }
+
+ private:
+  ui::InputMethod* const input_method_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestIMEInputContextHandler);
+};
+
 class TestInputMethodManagerBridge : public ArcInputMethodManagerBridge {
  public:
   TestInputMethodManagerBridge() = default;
@@ -159,8 +180,21 @@
     std::move(callback).Run(true);
   }
 
+  void SendFocus(mojom::InputConnectionPtr connection,
+                 mojom::TextInputStatePtr state) override {
+    ++focus_calls_count_;
+  }
+
+  void SendUpdateTextInputState(mojom::TextInputStatePtr state) override {
+    ++update_text_input_state_calls_count_;
+    last_text_input_state = state.Clone();
+  }
+
   std::vector<std::tuple<std::string, bool>> enable_ime_calls_;
   std::vector<std::string> switch_ime_to_calls_;
+  int focus_calls_count_ = 0;
+  int update_text_input_state_calls_count_ = 0;
+  mojom::TextInputStatePtr last_text_input_state;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerBridge);
@@ -185,10 +219,12 @@
   }
 
   void SetUp() override {
+    ui::IMEBridge::Initialize();
     input_method_manager_ = new TestInputMethodManager();
     chromeos::input_method::InputMethodManager::Initialize(
         input_method_manager_);
     tablet_mode_client_ = std::make_unique<TabletModeClient>();
+    keyboard_controller_ = std::make_unique<keyboard::KeyboardController>();
     profile_ = std::make_unique<TestingProfile>();
     service_ = ArcInputMethodManagerService::GetForBrowserContextForTesting(
         profile_.get());
@@ -201,8 +237,10 @@
     test_bridge_ = nullptr;
     service_->Shutdown();
     profile_.reset(nullptr);
+    keyboard_controller_.reset(nullptr);
     tablet_mode_client_.reset(nullptr);
     chromeos::input_method::InputMethodManager::Shutdown();
+    ui::IMEBridge::Shutdown();
   }
 
  private:
@@ -210,6 +248,7 @@
   std::unique_ptr<ArcServiceManager> arc_service_manager_;
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<TabletModeClient> tablet_mode_client_;
+  std::unique_ptr<keyboard::KeyboardController> keyboard_controller_;
   TestInputMethodManager* input_method_manager_ = nullptr;
   TestInputMethodManagerBridge* test_bridge_ = nullptr;  // Owned by |service_|
 
@@ -431,8 +470,9 @@
   info2->settings_url = settings_url2;
 
   std::vector<
-      std::tuple<std::string, chromeos::input_method::InputMethodDescriptors>>&
-      added_extensions = imm()->state()->added_input_method_extensions_;
+      std::tuple<std::string, chromeos::input_method::InputMethodDescriptors,
+                 ui::IMEEngineHandlerInterface*>>& added_extensions =
+      imm()->state()->added_input_method_extensions_;
   ASSERT_EQ(0u, added_extensions.size());
 
   {
@@ -445,7 +485,7 @@
   {
     // Adding one ARC IME.
     std::vector<mojom::ImeInfoPtr> info_array;
-    info_array.push_back(info1.Clone());
+    info_array.emplace_back(info1.Clone());
     service()->OnImeInfoChanged(std::move(info_array));
     ASSERT_EQ(1u, added_extensions.size());
     ASSERT_EQ(1u, std::get<1>(added_extensions[0]).size());
@@ -473,8 +513,8 @@
   {
     // Adding two ARC IMEs. One is already enabled.
     std::vector<mojom::ImeInfoPtr> info_array;
-    info_array.push_back(info1.Clone());
-    info_array.push_back(info2.Clone());
+    info_array.emplace_back(info1.Clone());
+    info_array.emplace_back(info2.Clone());
     service()->OnImeInfoChanged(std::move(info_array));
     // The ARC IMEs should be registered as two IMEs in one extension.
     ASSERT_EQ(1u, added_extensions.size());
@@ -588,4 +628,149 @@
   EXPECT_FALSE(imm()->state()->IsInputMethodAllowed(arc_ime_id));
 }
 
+TEST_F(ArcInputMethodManagerServiceTest, FocusAndBlur) {
+  base::test::ScopedFeatureList feature;
+  feature.InitAndEnableFeature(kEnableInputMethodFeature);
+  ToggleTabletMode(true);
+
+  // Adding one ARC IME.
+  {
+    const std::string android_ime_id = "test.arc.ime";
+    const std::string display_name = "DisplayName";
+    const std::string settings_url = "url_to_settings";
+    mojom::ImeInfoPtr info = mojom::ImeInfo::New();
+    info->ime_id = android_ime_id;
+    info->display_name = display_name;
+    info->enabled = false;
+    info->settings_url = settings_url;
+
+    std::vector<mojom::ImeInfoPtr> info_array;
+    info_array.emplace_back(std::move(info));
+    service()->OnImeInfoChanged(std::move(info_array));
+  }
+  // The proxy IME engine should be added.
+  ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size());
+  ui::IMEEngineHandlerInterface* engine_handler =
+      std::get<2>(imm()->state()->added_input_method_extensions_.at(0));
+  // Enable it
+  ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
+  engine_handler->Enable(
+      chromeos::extension_ime_util::GetComponentIDByInputMethodID(
+          std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
+              .at(0)
+              .id()));
+
+  constexpr int test_context_id = 0;
+  const ui::IMEEngineHandlerInterface::InputContext test_context{
+      test_context_id,
+      ui::TEXT_INPUT_TYPE_TEXT,
+      ui::TEXT_INPUT_MODE_DEFAULT,
+      0 /* flags */,
+      ui::TextInputClient::FOCUS_REASON_MOUSE,
+      true /* should_do_learning */};
+  ui::MockInputMethod mock_input_method(nullptr);
+  TestIMEInputContextHandler test_context_handler(&mock_input_method);
+  ui::DummyTextInputClient dummy_text_input_client;
+  ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler);
+  mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client);
+
+  ASSERT_EQ(0, bridge()->focus_calls_count_);
+
+  engine_handler->FocusIn(test_context);
+  EXPECT_EQ(1, bridge()->focus_calls_count_);
+
+  bridge()->update_text_input_state_calls_count_ = 0;
+
+  engine_handler->SetCompositionBounds({});
+  EXPECT_EQ(1, bridge()->update_text_input_state_calls_count_);
+  EXPECT_FALSE(bridge()->last_text_input_state->first_update_after_operation);
+
+  engine_handler->SetSurroundingText("", 0, 0, 0);
+  EXPECT_EQ(2, bridge()->update_text_input_state_calls_count_);
+  EXPECT_FALSE(bridge()->last_text_input_state->first_update_after_operation);
+
+  engine_handler->FocusOut();
+  EXPECT_EQ(1, bridge()->focus_calls_count_);
+
+  mock_input_method.DetachTextInputClient(&dummy_text_input_client);
+  ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
+}
+
+TEST_F(ArcInputMethodManagerServiceTest, IMEOperations) {
+  base::test::ScopedFeatureList feature;
+  feature.InitAndEnableFeature(kEnableInputMethodFeature);
+  ToggleTabletMode(true);
+
+  // Adding one ARC IME.
+  {
+    const std::string android_ime_id = "test.arc.ime";
+    const std::string display_name = "DisplayName";
+    const std::string settings_url = "url_to_settings";
+    mojom::ImeInfoPtr info = mojom::ImeInfo::New();
+    info->ime_id = android_ime_id;
+    info->display_name = display_name;
+    info->enabled = false;
+    info->settings_url = settings_url;
+
+    std::vector<mojom::ImeInfoPtr> info_array;
+    info_array.emplace_back(std::move(info));
+    service()->OnImeInfoChanged(std::move(info_array));
+  }
+  // The proxy IME engine should be added.
+  ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size());
+  ui::IMEEngineHandlerInterface* engine_handler =
+      std::get<2>(imm()->state()->added_input_method_extensions_.at(0));
+  // Enable it
+  ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler);
+  engine_handler->Enable(
+      chromeos::extension_ime_util::GetComponentIDByInputMethodID(
+          std::get<1>(imm()->state()->added_input_method_extensions_.at(0))
+              .at(0)
+              .id()));
+
+  constexpr int test_context_id = 0;
+  const ui::IMEEngineHandlerInterface::InputContext test_context{
+      test_context_id,
+      ui::TEXT_INPUT_TYPE_TEXT,
+      ui::TEXT_INPUT_MODE_DEFAULT,
+      0 /* flags */,
+      ui::TextInputClient::FOCUS_REASON_MOUSE,
+      true /* should_do_learning */};
+  ui::MockInputMethod mock_input_method(nullptr);
+  TestIMEInputContextHandler test_context_handler(&mock_input_method);
+  ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT);
+  ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler);
+  mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client);
+
+  engine_handler->FocusIn(test_context);
+  bridge()->update_text_input_state_calls_count_ = 0;
+
+  InputConnectionImpl* connection = service()->GetInputConnectionForTesting();
+  ASSERT_NE(nullptr, connection);
+  connection->CommitText(base::ASCIIToUTF16("text"), 0);
+  // It's called from both of FinishComposingText() and CommitText().
+  EXPECT_EQ(2, test_context_handler.commit_text_call_count());
+  // Trigger an observer method to trigger text input state updating.
+  engine_handler->SetSurroundingText("", 0, 0, 0);
+  EXPECT_EQ(1, bridge()->update_text_input_state_calls_count_);
+  EXPECT_TRUE(bridge()->last_text_input_state->first_update_after_operation);
+
+  test_context_handler.Reset();
+  connection->DeleteSurroundingText(1, 1);
+  EXPECT_EQ(1, test_context_handler.delete_surrounding_text_call_count());
+
+  test_context_handler.Reset();
+  connection->FinishComposingText();
+  EXPECT_EQ(1, test_context_handler.commit_text_call_count());
+
+  test_context_handler.Reset();
+  connection->SetComposingText(base::ASCIIToUTF16("text"), 0);
+  EXPECT_EQ(1, test_context_handler.update_preedit_text_call_count());
+
+  engine_handler->FocusOut();
+
+  mock_input_method.DetachTextInputClient(&dummy_text_input_client);
+  ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
+}
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc
new file mode 100644
index 0000000..76803fe
--- /dev/null
+++ b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.cc
@@ -0,0 +1,156 @@
+// Copyright 2018 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/input_method_manager/input_connection_impl.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/base/ime/ime_bridge.h"
+
+namespace arc {
+
+namespace {
+
+// Timeout threshold after the IME operation is sent to TextInputClient.
+// If no text input state observer methods in below ArcProxyInputMethodObserver
+// is called during this time period, the current text input state is sent to
+// Android.
+// TODO(yhanada): Implement a way to observe an IME operation completion and
+// send the current text input state right after the IME operation completion.
+constexpr base::TimeDelta kStateUpdateTimeout = base::TimeDelta::FromSeconds(1);
+
+}  // namespace
+
+InputConnectionImpl::InputConnectionImpl(
+    chromeos::InputMethodEngine* ime_engine,
+    ArcInputMethodManagerBridge* imm_bridge,
+    int input_context_id)
+    : ime_engine_(ime_engine),
+      imm_bridge_(imm_bridge),
+      input_context_id_(input_context_id),
+      binding_(this),
+      composing_text_(),
+      state_update_timer_() {}
+
+InputConnectionImpl::~InputConnectionImpl() = default;
+
+void InputConnectionImpl::Bind(mojom::InputConnectionPtr* interface_ptr) {
+  binding_.Bind(mojo::MakeRequest(interface_ptr));
+}
+
+void InputConnectionImpl::UpdateTextInputState(
+    bool is_input_state_update_requested) {
+  if (state_update_timer_.IsRunning()) {
+    // There is a pending request.
+    is_input_state_update_requested = true;
+  }
+  state_update_timer_.Stop();
+  imm_bridge_->SendUpdateTextInputState(
+      GetTextInputState(is_input_state_update_requested));
+}
+
+mojom::TextInputStatePtr InputConnectionImpl::GetTextInputState(
+    bool is_input_state_update_requested) const {
+  ui::IMEBridge* bridge = ui::IMEBridge::Get();
+  DCHECK(bridge);
+  ui::IMEInputContextHandlerInterface* handler =
+      bridge->GetInputContextHandler();
+  DCHECK(handler);
+  ui::TextInputClient* client = handler->GetInputMethod()->GetTextInputClient();
+  DCHECK(client);
+
+  gfx::Range text_range, selection_range;
+  base::string16 text;
+  client->GetTextRange(&text_range);
+  client->GetSelectionRange(&selection_range);
+  client->GetTextFromRange(text_range, &text);
+
+  return mojom::TextInputStatePtr(
+      base::in_place, selection_range.start(), text, text_range,
+      selection_range, client->GetTextInputType(), client->ShouldDoLearning(),
+      client->GetTextInputFlags(), is_input_state_update_requested);
+}
+
+void InputConnectionImpl::CommitText(const base::string16& text,
+                                     int new_cursor_pos) {
+  StartStateUpdateTimer();
+
+  // Confirm the current composing text at first.
+  FinishComposingTextInternal();
+
+  std::string error;
+  if (!ime_engine_->CommitText(input_context_id_,
+                               base::UTF16ToUTF8(text).c_str(), &error))
+    LOG(ERROR) << "CommitText failed: error=\"" << error << "\"";
+}
+
+void InputConnectionImpl::DeleteSurroundingText(int before, int after) {
+  StartStateUpdateTimer();
+
+  std::string error;
+  // DeleteSurroundingText takes a start position relative to the current cursor
+  // position and a length of the text is going to be deleted.
+  // |before| is a number of characters is going to be deleted before the cursor
+  // and |after| is a number of characters is going to be deleted after the
+  // cursor.
+  if (!ime_engine_->DeleteSurroundingText(input_context_id_, -before,
+                                          before + after, &error)) {
+    LOG(ERROR) << "DeleteSurroundingText failed: before = " << before
+               << ", after = " << after << ", error = \"" << error << "\"";
+  }
+}
+
+void InputConnectionImpl::FinishComposingText() {
+  StartStateUpdateTimer();
+  FinishComposingTextInternal();
+}
+
+void InputConnectionImpl::SetComposingText(const base::string16& text,
+                                           int new_cursor_pos) {
+  // If new_cursor_pos > 0, it's relative to (the end of the text - 1).
+  if (new_cursor_pos > 0)
+    new_cursor_pos += text.length() - 1;
+
+  StartStateUpdateTimer();
+
+  std::string error;
+  if (!ime_engine_->SetComposition(
+          input_context_id_, base::UTF16ToUTF8(text).c_str(), 0, 0,
+          new_cursor_pos,
+          std::vector<input_method::InputMethodEngineBase::SegmentInfo>(),
+          &error)) {
+    LOG(ERROR) << "SetComposingText failed: pos=" << new_cursor_pos
+               << ", error=\"" << error << "\"";
+    return;
+  }
+  composing_text_ = text;
+}
+
+void InputConnectionImpl::RequestTextInputState(
+    mojom::InputConnection::RequestTextInputStateCallback callback) {
+  std::move(callback).Run(GetTextInputState(false));
+}
+
+void InputConnectionImpl::StartStateUpdateTimer() {
+  // It's safe to use Unretained() here because the timer is automatically
+  // canceled when it go out of scope.
+  state_update_timer_.Start(
+      FROM_HERE, kStateUpdateTimeout,
+      base::BindOnce(&InputConnectionImpl::UpdateTextInputState,
+                     base::Unretained(this),
+                     true /* is_input_state_update_requested */));
+}
+
+void InputConnectionImpl::FinishComposingTextInternal() {
+  std::string error;
+  if (!ime_engine_->CommitText(input_context_id_,
+                               base::UTF16ToUTF8(composing_text_).c_str(),
+                               &error)) {
+    LOG(ERROR) << "FinishComposingText: CommitText() failed, error=\"" << error
+               << "\"";
+  }
+  composing_text_.clear();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.h b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.h
new file mode 100644
index 0000000..3952fd22
--- /dev/null
+++ b/chrome/browser/chromeos/arc/input_method_manager/input_connection_impl.h
@@ -0,0 +1,69 @@
+// Copyright 2018 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_INPUT_METHOD_MANAGER_INPUT_CONNECTION_IMPL_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_INPUT_METHOD_MANAGER_INPUT_CONNECTION_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h"
+#include "chrome/browser/chromeos/input_method/input_method_engine.h"
+#include "components/arc/common/input_method_manager.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace arc {
+
+// The implementation of mojom::InputConnection interface. It's generated for
+// each text field and accepts text edit commands from the ARC container.
+class InputConnectionImpl : public mojom::InputConnection {
+ public:
+  InputConnectionImpl(chromeos::InputMethodEngine* ime_engine,
+                      ArcInputMethodManagerBridge* imm_bridge,
+                      int input_context_id);
+  ~InputConnectionImpl() override;
+
+  // Binds this class to a passed interface pointer.
+  void Bind(mojom::InputConnectionPtr* interface_ptr);
+  // Sends current text input state to the ARC container.
+  void UpdateTextInputState(bool is_input_state_update_requested);
+  // Gets current text input state.
+  mojom::TextInputStatePtr GetTextInputState(
+      bool is_input_state_update_requested) const;
+
+  // mojom::InputConnection overrides:
+  void CommitText(const base::string16& text, int new_cursor_pos) override;
+  void DeleteSurroundingText(int before, int after) override;
+  void FinishComposingText() override;
+  void SetComposingText(const base::string16& text,
+                        int new_cursor_pos) override;
+  void RequestTextInputState(
+      mojom::InputConnection::RequestTextInputStateCallback callback) override;
+
+ private:
+  // Starts the timer to send new TextInputState.
+  // This method should be called before doing any IME operation to catch state
+  // update surely. Some implementations of TextInputClient are synchronous. If
+  // starting timer is after API call, the timer won't be cancelled.
+  void StartStateUpdateTimer();
+  void FinishComposingTextInternal();
+
+  chromeos::InputMethodEngine* const ime_engine_;  // Not owned
+  ArcInputMethodManagerBridge* const imm_bridge_;  // Not owned
+  const int input_context_id_;
+
+  mojo::Binding<mojom::InputConnection> binding_;
+
+  base::string16 composing_text_;
+
+  base::OneShotTimer state_update_timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(InputConnectionImpl);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_INPUT_METHOD_MANAGER_INPUT_CONNECTION_IMPL_H_
diff --git a/chrome/browser/chromeos/arc/notification/OWNERS b/chrome/browser/chromeos/arc/notification/OWNERS
new file mode 100644
index 0000000..407b30d
--- /dev/null
+++ b/chrome/browser/chromeos/arc/notification/OWNERS
@@ -0,0 +1 @@
+yoshiki@chromium.org
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
index a4d45a6..ec9957e 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
@@ -264,6 +264,8 @@
                 /* invert_bool_value */ false, &filtered_policies);
   MapObjectToPresenceBool("setWallpaperDisabled", policy::key::kWallpaperImage,
                           policy_map, &filtered_policies, {"url", "hash"});
+  MapBoolToBool("vpnConfigDisabled", policy::key::kVpnConfigAllowed, policy_map,
+                /* invert_bool_value */ true, &filtered_policies);
 
   // Add CA certificates.
   AddOncCaCertsToPolicies(policy_map, &filtered_policies);
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
index 3ba3241..5f9ee338 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -538,6 +538,15 @@
   GetPoliciesAndVerifyResult("{\"guid\":\"" + instance_guid() + "\"}");
 }
 
+TEST_F(ArcPolicyBridgeTest, VpnConfigAllowedTest) {
+  policy_map().Set(policy::key::kVpnConfigAllowed,
+                   policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
+                   policy::POLICY_SOURCE_CLOUD,
+                   std::make_unique<base::Value>(false), nullptr);
+  GetPoliciesAndVerifyResult("{\"guid\":\"" + instance_guid() +
+                             "\",\"vpnConfigDisabled\":true}");
+}
+
 TEST_P(ArcPolicyBridgeAffiliatedTest, ApkCacheEnabledTest) {
   const std::string apk_cache_enabled_policy(
       "{\"apkCacheEnabled\":true,\"guid\":\"" + instance_guid() + "\"}");
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index d394265..928e003 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -70,7 +70,6 @@
 #include "chrome/browser/chromeos/policy/app_install_event_log_manager_wrapper.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/settings/install_attributes.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/tether/tether_service.h"
 #include "chrome/browser/chromeos/tpm_firmware_update_notification.h"
@@ -1285,6 +1284,12 @@
   BootTimesRecorder* btl = BootTimesRecorder::Get();
   btl->AddLoginTimeMarker("UserProfileGotten", false);
 
+  // Associates AppListClient with the current active profile.
+  // Make sure AppListClient is active when AppListSyncableService builds model
+  // to avoid oem folder being created with invalid position. Note we should put
+  // this call before OAuth check in case of gaia sign in.
+  AppListClientImpl::GetInstance()->UpdateProfile();
+
   if (user_context_.IsUsingOAuth()) {
     // Retrieve the policy that indicates whether to continue copying
     // authentication cookies set by a SAML IdP on subsequent logins after the
@@ -1682,9 +1687,8 @@
   // Negative ping delay means to send ping immediately after a first search is
   // recorded.
   bool send_ping_immediately = ping_delay < 0;
-  base::TimeDelta delay =
-      base::TimeDelta::FromSeconds(abs(ping_delay)) -
-          params.time_since_oobe_completion;
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(abs(ping_delay)) -
+                          params.time_since_oobe_completion;
   rlz::RLZTracker::SetRlzDelegate(
       base::WrapUnique(new ChromeRLZTrackerDelegate));
   rlz::RLZTracker::InitRlzDelayed(
@@ -2061,9 +2065,6 @@
     profile->GetPrefs()->ClearPref(prefs::kShowSyncSettingsOnSessionStart);
     chrome::ShowSettingsSubPageForProfile(profile, "syncSetup");
   }
-
-  // Associates AppListClient with the current active profile.
-  AppListClientImpl::GetInstance()->UpdateProfile();
 }
 
 void UserSessionManager::RespectLocalePreferenceWrapper(
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 866067f4..0aeed73d 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -507,6 +507,7 @@
 
   registry->RegisterBooleanPref(prefs::kTPMFirmwareUpdateCleanupDismissed,
                                 false);
+  registry->RegisterBooleanPref(prefs::kVpnConfigAllowed, true);
 }
 
 void Preferences::InitUserPrefs(sync_preferences::PrefServiceSyncable* prefs) {
diff --git a/chrome/browser/extensions/extension_api_unittest.cc b/chrome/browser/extensions/extension_api_unittest.cc
index 4cf82724..b28dfcad 100644
--- a/chrome/browser/extensions/extension_api_unittest.cc
+++ b/chrome/browser/extensions/extension_api_unittest.cc
@@ -7,9 +7,9 @@
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/ui/browser.h"
-#include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_handlers/background_info.h"
 
@@ -25,8 +25,7 @@
 
 void ExtensionApiUnittest::SetUp() {
   BrowserWithTestWindowTest::SetUp();
-  extension_ = api_test_utils::CreateEmptyExtensionWithLocation(
-      Manifest::UNPACKED);
+  extension_ = ExtensionBuilder("Test").Build();
 }
 
 std::unique_ptr<base::Value> ExtensionApiUnittest::RunFunctionAndReturnValue(
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
index 6fbb881..5573415 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -36,7 +36,6 @@
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "components/version_info/version_info.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/extension_pref_value_map.h"
 #include "extensions/browser/extension_pref_value_map_factory.h"
 #include "extensions/browser/extension_prefs.h"
@@ -396,15 +395,6 @@
   }
 
  protected:
-  scoped_refptr<Extension> CreateExtension(
-      Manifest::Location location,
-      const std::string& data,
-      const std::string& id) {
-    std::unique_ptr<base::DictionaryValue> parsed_manifest(
-        api_test_utils::ParseDictionary(data));
-    return api_test_utils::CreateExtension(location, parsed_manifest.get(), id);
-  }
-
   ExtensionService* service_;
 
  private:
diff --git a/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc b/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
index e1912f6..d3b2f725 100644
--- a/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_audio_quality_browsertest.cc
@@ -702,7 +702,7 @@
   DeleteFileUnlessTestFailed(recording, false);
 }
 
-#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_WIN)
 #define MAYBE_MANUAL_TestCallQualityWithAudioFromFakeDevice \
   MANUAL_TestCallQualityWithAudioFromFakeDevice
 #else
@@ -720,7 +720,8 @@
 #define MAYBE_MANUAL_TestCallQualityWithAudioFromWebAudio \
   MANUAL_TestCallQualityWithAudioFromWebAudio
 #else
-// Not implemented on Android, ChromeOS etc.
+// Not implemented on Android, ChromeOS etc. Temporary disabled on Mac
+// (https://crbug.com/882780).
 #define MAYBE_MANUAL_TestCallQualityWithAudioFromWebAudio \
   DISABLED_MANUAL_TestCallQualityWithAudioFromWebAudio
 #endif
@@ -835,12 +836,12 @@
   DeleteFileUnlessTestFailed(actual_files_dir, true);
 }
 
-#if defined(OS_LINUX) || defined(OS_MACOSX)
+#if defined(OS_LINUX)
 #define MAYBE_MANUAL_TestAutoGainControlOnLowAudio \
   MANUAL_TestAutoGainControlOnLowAudio
 #else
 // Not implemented on Android, ChromeOS etc. Temporary disabled on Windows
-// (https://crbug.com/850936).
+// (https://crbug.com/850936) and on Mac (https://crbug.com/882780).
 #define MAYBE_MANUAL_TestAutoGainControlOnLowAudio \
   DISABLED_MANUAL_TestAutoGainControlOnLowAudio
 #endif
@@ -855,12 +856,12 @@
       TestAutoGainControl(kAudioCallWithoutEchoCancellation, "_with_agc"));
 }
 
-#if defined(OS_LINUX) || defined(OS_MACOSX)
+#if defined(OS_LINUX)
 #define MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff \
   MANUAL_TestAutoGainIsOffWithAudioProcessingOff
 #else
 // Not implemented on Android, ChromeOS etc. Temporary disabled on Windows
-// (https://crbug.com/850936).
+// (https://crbug.com/850936) and on Mac (https://crbug.com/882780).
 #define MAYBE_MANUAL_TestAutoGainIsOffWithAudioProcessingOff \
   DISABLED_MANUAL_TestAutoGainIsOffWithAudioProcessingOff
 #endif
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 94fbb12..0ae984aa 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/field_trial.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
@@ -44,23 +44,21 @@
 #include "components/password_manager/core/browser/hsts_query.h"
 #include "components/password_manager/core/browser/log_manager.h"
 #include "components/password_manager/core/browser/log_receiver.h"
-#include "components/password_manager/core/browser/password_bubble_experiment.h"
 #include "components/password_manager/core/browser/password_form_manager_for_ui.h"
 #include "components/password_manager/core/browser/password_manager_internals_service.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "components/password_manager/core/browser/password_requirements_service.h"
+#include "components/password_manager/core/browser/store_metrics_reporter.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/password_manager/sync/browser/password_sync_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/sessions/content/content_record_password_state.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
@@ -126,39 +124,6 @@
   return SigninManagerFactory::GetForProfile(profile);
 }
 
-// This routine is called when PasswordManagerClient is constructed.
-// Currently we report metrics only once at startup. We require
-// that this is only ever called from a single thread in order to
-// avoid needing to lock (a static boolean flag is then sufficient to
-// guarantee running only once).
-void ReportMetrics(bool password_manager_enabled,
-                   password_manager::PasswordManagerClient* client,
-                   Profile* profile) {
-  static base::PlatformThreadId initial_thread_id =
-      base::PlatformThread::CurrentId();
-  DCHECK_EQ(base::PlatformThread::CurrentId(), initial_thread_id);
-
-  static bool ran_once = false;
-  if (ran_once)
-    return;
-  ran_once = true;
-
-  password_manager::PasswordStore* store = client->GetPasswordStore();
-  // May be null in tests.
-  if (store) {
-    store->ReportMetrics(
-        password_manager::sync_util::GetSyncUsernameIfSyncingPasswords(
-            GetSyncService(profile), GetSigninManager(profile)),
-        client->GetPasswordSyncState() ==
-            password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE);
-  }
-  UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
-  UMA_HISTOGRAM_BOOLEAN(
-      "PasswordManager.ShouldShowAutoSignInFirstRunExperience",
-      password_bubble_experiment::ShouldShowAutoSignInPromptFirstRunExperience(
-          profile->GetPrefs()));
-}
-
 #if !defined(OS_ANDROID)
 // Adds |observer| to the input observers of |widget_host|.
 void AddToWidgetInputEventObservers(
@@ -218,7 +183,9 @@
 
   saving_and_filling_passwords_enabled_.Init(
       password_manager::prefs::kCredentialsEnableService, GetPrefs());
-  ReportMetrics(*saving_and_filling_passwords_enabled_, this, profile_);
+  static base::NoDestructor<password_manager::StoreMetricsReporter> reporter(
+      *saving_and_filling_passwords_enabled_, this, GetSyncService(profile_),
+      GetSigninManager(profile_), GetPrefs());
   driver_factory_->RequestSendLoggingAvailability();
 }
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 176dbe0..31a96ab 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -21,7 +21,7 @@
 #include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_reuse_detection_manager.h"
-#include "components/password_manager/sync/browser/sync_credentials_filter.h"
+#include "components/password_manager/core/browser/sync_credentials_filter.h"
 #include "components/prefs/pref_member.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/web_contents_binding_set.h"
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index 7e626167..d75d030b 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -28,7 +28,6 @@
 #include "components/password_manager/core/browser/login_database.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_default.h"
 #include "components/password_manager/core/browser/password_store_factory_util.h"
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index e2c484d..df749362 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -815,6 +815,10 @@
   { key::kCastReceiverEnabled,
     prefs::kCastReceiverEnabled,
     base::Value::Type::BOOLEAN },
+
+  { key::kVpnConfigAllowed,
+    prefs::kVpnConfigAllowed,
+    base::Value::Type::BOOLEAN },
 #endif
 
   { key::kRoamingProfileSupportEnabled,
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index 0e97d18..c9ab027 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -154,8 +154,8 @@
     new PresentationInfoRecord('Prev', '', 'fromPrevious', false, ''),
     new PresentationInfoRecord(
         'Tran',
-        'http://code.google.com/codesearch#OAMlx_jo-ck/src/content/public/' +
-        'common/page_transition_types.h&exact_package=chromium&l=24',
+        'https://cs.chromium.org/chromium/src/ui/base/page_transition_types.h' +
+        '?q=page_transition_types.h&sq=package:chromium&dr=CSs&l=14',
         'transition', false, 'How the user got to the result.'),
     new PresentationInfoRecord(
         'Done', '', 'providerDone', false,
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
index 3972d6a..d1413bb 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -730,6 +730,7 @@
   } else {
     base::UmaHistogramSparse("SBClientDownload.DmgFileFailureByType",
                              uma_file_type);
+    type_ = ClientDownloadRequest::MAC_ARCHIVE_FAILED_PARSING;
   }
 
   if (archived_executable_) {
@@ -745,16 +746,6 @@
   UMA_HISTOGRAM_TIMES("SBClientDownload.ExtractDmgFeaturesTime",
                       base::TimeTicks::Now() - dmg_analysis_start_time_);
 
-  if (!archived_executable_) {
-    if (!results.success) {
-      type_ = ClientDownloadRequest::INVALID_MAC_ARCHIVE;
-    } else {
-      PostFinishTask(DownloadCheckResult::SAFE,
-                     REASON_ARCHIVE_WITHOUT_BINARIES);
-      return;
-    }
-  }
-
   OnFileFeatureExtractionDone();
 }
 #endif  // defined(OS_MACOSX)
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
index 667767e..ad5fef1d 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -593,8 +593,9 @@
   EXPECT_EQ(0, GetClientDownloadRequest()->archived_binary_size());
   EXPECT_TRUE(GetClientDownloadRequest()->has_download_type());
   ClientDownloadRequest::DownloadType expected_type =
-      type == ZIP ? ClientDownloadRequest_DownloadType_INVALID_ZIP
-                  : ClientDownloadRequest_DownloadType_INVALID_MAC_ARCHIVE;
+      type == ZIP
+          ? ClientDownloadRequest_DownloadType_INVALID_ZIP
+          : ClientDownloadRequest_DownloadType_MAC_ARCHIVE_FAILED_PARSING;
   EXPECT_EQ(expected_type, GetClientDownloadRequest()->download_type());
   ClearClientDownloadRequest();
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
index ce48f2f..dc6a6e0 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder.cc
@@ -68,7 +68,7 @@
 // Platform-specific types are relevant only for their own platforms.
 #if defined(OS_MACOSX)
   if (download_type == ClientDownloadRequest::MAC_EXECUTABLE ||
-      download_type == ClientDownloadRequest::INVALID_MAC_ARCHIVE)
+      download_type == ClientDownloadRequest::MAC_ARCHIVE_FAILED_PARSING)
     return true;
 #elif defined(OS_ANDROID)
   if (download_type == ClientDownloadRequest::ANDROID_APK)
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc
index 82d4d98..b5daa08 100644
--- a/chrome/browser/signin/dice_browsertest.cc
+++ b/chrome/browser/signin/dice_browsertest.cc
@@ -782,7 +782,12 @@
 
 // Checks that Dice request header is not set from request from WebUI.
 // See https://crbug.com/428396
-IN_PROC_BROWSER_TEST_F(DiceBrowserTest, NoDiceFromWebUI) {
+#if defined(OS_WIN)
+#define MAYBE_NoDiceFromWebUI DISABLED_NoDiceFromWebUI
+#else
+#define MAYBE_NoDiceFromWebUI NoDiceFromWebUI
+#endif
+IN_PROC_BROWSER_TEST_F(DiceBrowserTest, MAYBE_NoDiceFromWebUI) {
   // Navigate to Gaia and from the native tab, which uses an extension.
   ui_test_utils::NavigateToURL(browser(), GURL("chrome:chrome-signin"));
 
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index dbc0364e..4f26426 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -60,8 +60,8 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/invalidation/impl/invalidation_switches.h"
 #include "components/invalidation/impl/profile_invalidation_provider.h"
+#include "components/password_manager/core/browser/password_model_worker.h"
 #include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/sync/browser/password_model_worker.h"
 #include "components/search_engines/search_engine_data_type_controller.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/sync/base/pref_names.h"
diff --git a/chrome/browser/sync/test/integration/passwords_helper.cc b/chrome/browser/sync/test/integration/passwords_helper.cc
index 5cf2448..bc24c4e50b 100644
--- a/chrome/browser/sync/test/integration/passwords_helper.cc
+++ b/chrome/browser/sync/test/integration/passwords_helper.cc
@@ -82,7 +82,7 @@
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
   store->AddLogin(form);
-  store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
+  store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
   wait_event.Wait();
 }
 
@@ -92,7 +92,7 @@
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
   store->UpdateLogin(form);
-  store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
+  store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
   wait_event.Wait();
 }
 
@@ -111,7 +111,7 @@
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
   store->RemoveLogin(form);
-  store->ScheduleTask(base::Bind(&PasswordStoreCallback, &wait_event));
+  store->ScheduleTask(base::BindOnce(&PasswordStoreCallback, &wait_event));
   wait_event.Wait();
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 5566278..3fb0956 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -50,7 +50,6 @@
       "cocoa/browser_dialogs_views_mac.h",
       "cocoa/browser_window_cocoa.h",
       "cocoa/browser_window_cocoa.mm",
-      "cocoa/browser_window_cocoa_views_mac.mm",
       "cocoa/browser_window_controller.h",
       "cocoa/browser_window_controller.mm",
       "cocoa/browser_window_controller_private.h",
@@ -552,7 +551,6 @@
     "//components/onc",
     "//components/password_manager/content/browser",
     "//components/password_manager/core/browser",
-    "//components/password_manager/sync/browser",
     "//components/payments/content:utils",
     "//components/pdf/browser",
     "//components/policy/core/browser",
@@ -965,6 +963,10 @@
       "global_error/global_error_service.h",
       "global_error/global_error_service_factory.cc",
       "global_error/global_error_service_factory.h",
+      "hats/hats_service.cc",
+      "hats/hats_service.h",
+      "hats/hats_service_factory.cc",
+      "hats/hats_service_factory.h",
       "hung_renderer/hung_renderer_core.cc",
       "hung_renderer/hung_renderer_core.h",
       "javascript_dialogs/javascript_dialog_views.cc",
@@ -2049,7 +2051,6 @@
       "cocoa/bookmarks/bookmark_menu_cocoa_controller.mm",
       "cocoa/browser_window_command_handler.h",
       "cocoa/browser_window_command_handler.mm",
-      "cocoa/browser_window_views_mac.h",
       "cocoa/chrome_command_dispatcher_delegate.h",
       "cocoa/chrome_command_dispatcher_delegate.mm",
       "cocoa/chrome_style.cc",
@@ -3142,6 +3143,7 @@
       "app_list/app_list_controller_delegate.h",
       "app_list/app_list_model_builder.cc",
       "app_list/app_list_model_builder.h",
+      "app_list/app_list_model_updater.cc",
       "app_list/app_list_model_updater.h",
       "app_list/app_list_model_updater_delegate.h",
       "app_list/app_list_syncable_service.cc",
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
index cb81ccac..7637972c 100644
--- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -49,8 +49,8 @@
   DISALLOW_COPY_AND_ASSIGN(FakeAppContextMenuDelegate);
 };
 
-class FakeAppListControllerDelegate :
-    public test::TestAppListControllerDelegate {
+class FakeAppListControllerDelegate
+    : public test::TestAppListControllerDelegate {
  public:
   FakeAppListControllerDelegate() = default;
   ~FakeAppListControllerDelegate() override = default;
@@ -95,7 +95,7 @@
 std::unique_ptr<KeyedService> MenuManagerFactory(
     content::BrowserContext* context) {
   return extensions::MenuManagerFactory::BuildServiceInstanceForTesting(
-              context);
+      context);
 }
 
 std::unique_ptr<ui::MenuModel> GetContextMenuModel(ChromeAppListItem* item) {
@@ -160,21 +160,14 @@
  protected:
   struct MenuState {
     // Defines separator.
-    MenuState() : command_id(-1), is_enabled(true), is_checked(false) {
-    }
+    MenuState() : command_id(-1), is_enabled(true), is_checked(false) {}
 
     // Defines enabled unchecked command.
     explicit MenuState(int command_id)
-        : command_id(command_id),
-          is_enabled(true),
-          is_checked(false) {
-    }
+        : command_id(command_id), is_enabled(true), is_checked(false) {}
 
     MenuState(int command_id, bool enabled, bool checked)
-        : command_id(command_id),
-          is_enabled(enabled),
-          is_checked(checked) {
-    }
+        : command_id(command_id), is_enabled(enabled), is_checked(checked) {}
 
     int command_id;
     bool is_enabled;
@@ -186,7 +179,7 @@
                          const MenuState& state) {
     EXPECT_EQ(state.command_id, menu_model->GetCommandIdAt(index));
     if (state.command_id == -1)
-      return;   // Don't check separator.
+      return;  // Don't check separator.
     EXPECT_EQ(state.is_enabled, menu_model->IsEnabledAt(index));
     EXPECT_EQ(state.is_checked, menu_model->IsItemCheckedAt(index));
   }
@@ -202,17 +195,11 @@
     EXPECT_EQ(state_index, states.size());
   }
 
-  FakeAppListControllerDelegate* controller() {
-    return controller_.get();
-  }
+  FakeAppListControllerDelegate* controller() { return controller_.get(); }
 
-  FakeAppContextMenuDelegate* menu_delegate() {
-    return menu_delegate_.get();
-  }
+  FakeAppContextMenuDelegate* menu_delegate() { return menu_delegate_.get(); }
 
-  Profile* profile() {
-    return profile_.get();
-  }
+  Profile* profile() { return profile_.get(); }
 
   void AddSeparator(std::vector<MenuState>* states) {
     // TODO(newcomer): Remove this function when touchable app context menus are
@@ -246,9 +233,7 @@
     controller_->SetAppPinnable(app_id, pinnable);
     controller_->SetCanShowAppInfo(can_show_app_info);
     controller_->SetExtensionLaunchType(profile(), app_id, launch_type);
-    app_list::ExtensionAppContextMenu menu(menu_delegate(),
-                                           profile(),
-                                           app_id,
+    app_list::ExtensionAppContextMenu menu(menu_delegate(), profile(), app_id,
                                            controller());
     menu.set_is_platform_app(platform_app);
     std::unique_ptr<ui::MenuModel> menu_model = GetMenuModel(&menu);
@@ -314,10 +299,8 @@
   void TestChromeApp(bool can_show_app_info) {
     controller_ = std::make_unique<FakeAppListControllerDelegate>();
     controller_->SetCanShowAppInfo(can_show_app_info);
-    app_list::ExtensionAppContextMenu menu(menu_delegate(),
-                                           profile(),
-                                           extension_misc::kChromeAppId,
-                                           controller());
+    app_list::ExtensionAppContextMenu menu(
+        menu_delegate(), profile(), extension_misc::kChromeAppId, controller());
     std::unique_ptr<ui::MenuModel> menu_model = GetMenuModel(&menu);
     ASSERT_NE(nullptr, menu_model);
 
@@ -347,29 +330,23 @@
   app_list::ExtensionAppContextMenu::DisableInstalledExtensionCheckForTesting(
       false);
   for (extensions::LaunchType launch_type = extensions::LAUNCH_TYPE_FIRST;
-      launch_type < extensions::NUM_LAUNCH_TYPES;
-      launch_type = static_cast<extensions::LaunchType>(launch_type+1)) {
+       launch_type < extensions::NUM_LAUNCH_TYPES;
+       launch_type = static_cast<extensions::LaunchType>(launch_type + 1)) {
     AppListControllerDelegate::Pinnable pinnable;
     for (pinnable = AppListControllerDelegate::NO_PIN;
-        pinnable <= AppListControllerDelegate::PIN_FIXED;
-        pinnable =
-            static_cast<AppListControllerDelegate::Pinnable>(pinnable+1)) {
+         pinnable <= AppListControllerDelegate::PIN_FIXED;
+         pinnable =
+             static_cast<AppListControllerDelegate::Pinnable>(pinnable + 1)) {
       for (size_t combinations = 0; combinations < (1 << 2); ++combinations) {
         TestExtensionApp(AppListTestBase::kHostedAppId,
                          (combinations & (1 << 0)) != 0,
-                         (combinations & (1 << 1)) != 0,
-                         pinnable,
-                         launch_type);
+                         (combinations & (1 << 1)) != 0, pinnable, launch_type);
         TestExtensionApp(AppListTestBase::kPackagedApp1Id,
                          (combinations & (1 << 0)) != 0,
-                         (combinations & (1 << 1)) != 0,
-                         pinnable,
-                         launch_type);
+                         (combinations & (1 << 1)) != 0, pinnable, launch_type);
         TestExtensionApp(AppListTestBase::kPackagedApp2Id,
                          (combinations & (1 << 0)) != 0,
-                         (combinations & (1 << 1)) != 0,
-                         pinnable,
-                         launch_type);
+                         (combinations & (1 << 1)) != 0, pinnable, launch_type);
       }
     }
   }
@@ -385,8 +362,7 @@
 TEST_P(AppContextMenuTest, NonExistingExtensionApp) {
   app_list::ExtensionAppContextMenu::DisableInstalledExtensionCheckForTesting(
       false);
-  app_list::ExtensionAppContextMenu menu(menu_delegate(),
-                                         profile(),
+  app_list::ExtensionAppContextMenu menu(menu_delegate(), profile(),
                                          "some_non_existing_extension_app",
                                          controller());
   std::unique_ptr<ui::MenuModel> menu_model = GetMenuModel(&menu);
@@ -714,7 +690,8 @@
 
     controller()->SetAppPinnable(internal_app.app_id,
                                  AppListControllerDelegate::PIN_EDITABLE);
-    InternalAppItem item(profile(), nullptr, internal_app);
+    InternalAppItem item(profile(), nullptr /* model_updater */,
+                         nullptr /* sync_item */, internal_app);
     std::unique_ptr<ui::MenuModel> menu = GetContextMenuModel(&item);
     ASSERT_NE(nullptr, menu);
     EXPECT_EQ(1, menu->GetItemCount());
diff --git a/chrome/browser/ui/app_list/app_list_model_updater.cc b/chrome/browser/ui/app_list/app_list_model_updater.cc
new file mode 100644
index 0000000..2dcc3676
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_list_model_updater.cc
@@ -0,0 +1,48 @@
+// Copyright 2018 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/ui/app_list/app_list_model_updater.h"
+
+#include <algorithm>
+
+#include "ash/public/cpp/app_list/app_list_config.h"
+#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
+
+// static
+syncer::StringOrdinal AppListModelUpdater::GetFirstAvailablePositionInternal(
+    const std::vector<ChromeAppListItem*>& top_level_items) {
+  // Sort the top level items by their positions.
+  std::vector<ChromeAppListItem*> sorted_items(top_level_items);
+  std::sort(sorted_items.begin(), sorted_items.end(),
+            [](ChromeAppListItem* const& item1,
+               ChromeAppListItem* const& item2) -> bool {
+              return item1->position().LessThan(item2->position());
+            });
+
+  // Find the first empty position in app list. If all pages are full, return
+  // the next position after last item.
+  int items_in_page = 0;
+  int page = 0;
+  for (size_t i = 0; i < sorted_items.size(); ++i) {
+    if (!sorted_items[i]->is_page_break()) {
+      ++items_in_page;
+      continue;
+    }
+
+    // There may be multiple "page break" items at the end of page while empty
+    // pages will not be shown in app list, so skip them.
+    const int max_items_in_page =
+        app_list::AppListConfig::instance().GetMaxNumOfItemsPerPage(page);
+    if (items_in_page > 0 && items_in_page < max_items_in_page) {
+      return sorted_items[i - 1]->position().CreateBetween(
+          sorted_items[i]->position());
+    }
+    if (items_in_page > 0)
+      ++page;
+    items_in_page = 0;
+  }
+
+  if (sorted_items.empty())
+    return syncer::StringOrdinal::CreateInitialOrdinal();
+  return sorted_items.back()->position().CreateAfter();
+}
diff --git a/chrome/browser/ui/app_list/app_list_model_updater.h b/chrome/browser/ui/app_list/app_list_model_updater.h
index 36c0090..b5221cf1 100644
--- a/chrome/browser/ui/app_list/app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/app_list_model_updater.h
@@ -107,6 +107,7 @@
   virtual void ContextMenuItemSelected(const std::string& id,
                                        int command_id,
                                        int event_flags) {}
+  virtual syncer::StringOrdinal GetFirstAvailablePosition() const = 0;
 
   // Methods for AppListSyncableService:
   virtual void AddItemToOemFolder(
@@ -141,6 +142,13 @@
   virtual void OnPageBreakItemDeleted(const std::string& id) = 0;
 
   virtual void SetDelegate(AppListModelUpdaterDelegate* delegate) = 0;
+
+ protected:
+  // Returns the first available position in app list. |top_level_items| are
+  // items without parents. Note that all items in |top_level_items| should have
+  // valid position.
+  static syncer::StringOrdinal GetFirstAvailablePositionInternal(
+      const std::vector<ChromeAppListItem*>& top_level_items);
 };
 
 #endif  // CHROME_BROWSER_UI_APP_LIST_APP_LIST_MODEL_UPDATER_H_
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
index b909bf8..1453aa6 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
@@ -95,6 +95,10 @@
   if (profile->IsSystemProfile())
     return nullptr;
 
+  // No service for sign in profile.
+  if (chromeos::ProfileHelper::IsSigninProfile(profile))
+    return nullptr;
+
   // Use profile as-is for guest session.
   if (profile->IsGuestSession())
     return chrome::GetBrowserContextOwnInstanceInIncognito(context);
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
index 6c1f5ff..9049e8f 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "ash/public/cpp/app_list/app_list_config.h"
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_number_conversions.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
@@ -188,6 +190,8 @@
     app_list_syncable_service_ =
         std::make_unique<app_list::AppListSyncableService>(profile_.get(),
                                                            extension_system);
+    content::RunAllTasksUntilIdle();
+
     model_updater_test_api_ =
         std::make_unique<AppListModelUpdater::TestApi>(model_updater());
   }
@@ -609,3 +613,48 @@
   ASSERT_TRUE(GetSyncItem(kItemId2));
   ASSERT_FALSE(GetSyncItem(kPageBreakItemId5));
 }
+
+TEST_F(AppListSyncableServiceTest, FirstAvailablePosition) {
+  RemoveAllExistingItems();
+
+  // Populate the first page with items and leave 1 empty slot at the end.
+  const int max_items_in_first_page =
+      app_list::AppListConfig::instance().GetMaxNumOfItemsPerPage(0);
+  syncer::StringOrdinal last_app_position =
+      syncer::StringOrdinal::CreateInitialOrdinal();
+  for (int i = 0; i < max_items_in_first_page - 1; ++i) {
+    std::unique_ptr<ChromeAppListItem> item =
+        std::make_unique<ChromeAppListItem>(
+            profile_.get(), GenerateId("item_id" + base::IntToString(i)),
+            model_updater());
+    item->SetPosition(last_app_position);
+    model_updater()->AddItem(std::move(item));
+    if (i < max_items_in_first_page - 2)
+      last_app_position = last_app_position.CreateAfter();
+  }
+  EXPECT_TRUE(last_app_position.CreateAfter().Equals(
+      model_updater()->GetFirstAvailablePosition()));
+
+  // Add a "page break" item at the end of first page.
+  std::unique_ptr<ChromeAppListItem> page_break_item =
+      std::make_unique<ChromeAppListItem>(
+          profile_.get(), GenerateId("page_break_item_id"), model_updater());
+  const syncer::StringOrdinal page_break_position =
+      last_app_position.CreateAfter();
+  page_break_item->SetPosition(page_break_position);
+  page_break_item->SetIsPageBreak(true);
+  model_updater()->AddItem((std::move(page_break_item)));
+  EXPECT_TRUE(last_app_position.CreateBetween(page_break_position)
+                  .Equals(model_updater()->GetFirstAvailablePosition()));
+
+  // Fill up the first page.
+  std::unique_ptr<ChromeAppListItem> app_item =
+      std::make_unique<ChromeAppListItem>(
+          profile_.get(),
+          GenerateId("item_id" + base::IntToString(max_items_in_first_page)),
+          model_updater());
+  app_item->SetPosition(last_app_position.CreateBetween(page_break_position));
+  model_updater()->AddItem(std::move(app_item));
+  EXPECT_TRUE(page_break_position.CreateAfter().Equals(
+      model_updater()->GetFirstAvailablePosition()));
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_item.cc b/chrome/browser/ui/app_list/arc/arc_app_item.cc
index 637b4c6..e4eb457 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_item.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_item.cc
@@ -26,7 +26,7 @@
   if (sync_item && sync_item->item_ordinal.IsValid())
     UpdateFromSync(sync_item);
   else
-    SetDefaultPositionIfApplicable();
+    SetDefaultPositionIfApplicable(model_updater);
 
   // Set model updater last to avoid being called during construction.
   set_model_updater(model_updater);
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.cc b/chrome/browser/ui/app_list/chrome_app_list_item.cc
index 41cb0e9c..0b326e1 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.cc
@@ -67,8 +67,7 @@
       profile_(profile),
       model_updater_(model_updater) {}
 
-ChromeAppListItem::~ChromeAppListItem() {
-}
+ChromeAppListItem::~ChromeAppListItem() = default;
 
 void ChromeAppListItem::SetIsInstalling(bool is_installing) {
   AppListModelUpdater* updater = model_updater();
@@ -146,19 +145,29 @@
     SetName(sync_item->item_name);
 }
 
-void ChromeAppListItem::SetDefaultPositionIfApplicable() {
+void ChromeAppListItem::SetDefaultPositionIfApplicable(
+    AppListModelUpdater* model_updater) {
   syncer::StringOrdinal page_ordinal;
   syncer::StringOrdinal launch_ordinal;
   extensions::AppSorting* app_sorting = GetAppSorting();
-  if (!app_sorting->GetDefaultOrdinals(id(), &page_ordinal,
-                                       &launch_ordinal) ||
-      !page_ordinal.IsValid() || !launch_ordinal.IsValid()) {
-    app_sorting->EnsureValidOrdinals(id(), syncer::StringOrdinal());
-    page_ordinal = app_sorting->GetPageOrdinal(id());
-    launch_ordinal = app_sorting->GetAppLaunchOrdinal(id());
+  if (app_sorting->GetDefaultOrdinals(id(), &page_ordinal, &launch_ordinal) &&
+      page_ordinal.IsValid() && launch_ordinal.IsValid()) {
+    // Set the default position if it exists.
+    SetPosition(syncer::StringOrdinal(page_ordinal.ToInternalValue() +
+                                      launch_ordinal.ToInternalValue()));
+    return;
   }
-  DCHECK(page_ordinal.IsValid());
-  DCHECK(launch_ordinal.IsValid());
+
+  if (model_updater) {
+    // Set the first available position in the app list.
+    SetPosition(model_updater->GetFirstAvailablePosition());
+    return;
+  }
+
+  // Set the natural position.
+  app_sorting->EnsureValidOrdinals(id(), syncer::StringOrdinal());
+  page_ordinal = app_sorting->GetPageOrdinal(id());
+  launch_ordinal = app_sorting->GetAppLaunchOrdinal(id());
   SetPosition(syncer::StringOrdinal(page_ordinal.ToInternalValue() +
                                     launch_ordinal.ToInternalValue()));
 }
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.h b/chrome/browser/ui/app_list/chrome_app_list_item.h
index edd14e8..ca547e1 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.h
@@ -112,8 +112,9 @@
 
   std::string ToDebugString() const;
 
-  // Set the default position if it exists.
-  void SetDefaultPositionIfApplicable();
+  // Set the default position if it exists. Otherwise set the first available
+  // position in the app list if |model_updater| is not null.
+  void SetDefaultPositionIfApplicable(AppListModelUpdater* model_updater);
 
  protected:
   ChromeAppListItem(Profile* profile, const std::string& app_id);
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
index ab97bab..a0cbc37 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
@@ -7,6 +7,7 @@
 #include <unordered_map>
 #include <utility>
 
+#include "ash/public/cpp/app_list/app_list_config.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
@@ -372,6 +373,21 @@
     chrome_item->ContextMenuItemSelected(command_id, event_flags);
 }
 
+syncer::StringOrdinal ChromeAppListModelUpdater::GetFirstAvailablePosition()
+    const {
+  std::vector<ChromeAppListItem*> top_level_items;
+  for (auto& entry : items_) {
+    ChromeAppListItem* item = entry.second.get();
+    DCHECK(item->position().IsValid())
+        << "Item with invalid position: id=" << item->id()
+        << ", name=" << item->name() << ", is_folder=" << item->is_folder()
+        << ", is_page_break=" << item->is_page_break();
+    if (item->folder_id().empty() && item->position().IsValid())
+      top_level_items.emplace_back(item);
+  }
+  return GetFirstAvailablePositionInternal(top_level_items);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Methods for AppListSyncableService
 
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
index b0e9ffb0..02fee0b 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
@@ -88,6 +88,7 @@
   void ContextMenuItemSelected(const std::string& id,
                                int command_id,
                                int event_flags) override;
+  syncer::StringOrdinal GetFirstAvailablePosition() const override;
 
   // Methods for AppListSyncableService:
   void AddItemToOemFolder(
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
new file mode 100644
index 0000000..e46f1b5e
--- /dev/null
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc
@@ -0,0 +1,85 @@
+// Copyright 2018 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/path_service.h"
+#include "chrome/browser/chromeos/login/login_manager_test.h"
+#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/ui/app_list/app_list_client_impl.h"
+#include "chrome/browser/ui/app_list/app_list_model_updater.h"
+#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
+#include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
+#include "chrome/common/chrome_constants.cc"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/account_id/account_id.h"
+#include "components/session_manager/core/session_manager.h"
+#include "extensions/browser/extension_system.h"
+
+namespace {
+
+constexpr char kTestUser[] = "test-user@gmail.com";
+constexpr char kTestUserGaiaId[] = "1234567890";
+constexpr char kOemAppId[] = "emfkafnhnpcmabnnkckkchdilgeoekbo";
+
+}  // namespace
+
+class OemAppPositionTest : public chromeos::LoginManagerTest {
+ public:
+  OemAppPositionTest()
+      : LoginManagerTest(true /* should_launch_browser */,
+                         true /* should_initialize_webui */) {}
+  ~OemAppPositionTest() override = default;
+
+  // LoginManagerTest:
+  bool SetUpUserDataDirectory() override {
+    // Create test user profile directory and copy extensions and preferences
+    // from the test data directory to it.
+    base::FilePath user_data_dir;
+    base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+    const std::string user_id_hash =
+        chromeos::ProfileHelper::GetUserIdHashByUserIdForTesting(kTestUser);
+    const base::FilePath user_profile_path = user_data_dir.Append(
+        chromeos::ProfileHelper::GetUserProfileDir(user_id_hash));
+    base::CreateDirectory(user_profile_path);
+
+    base::FilePath src_dir;
+    base::PathService::Get(chrome::DIR_TEST_DATA, &src_dir);
+    src_dir = src_dir.AppendASCII("extensions").AppendASCII("app_list_oem");
+
+    base::CopyFile(src_dir.Append(chrome::kPreferencesFilename),
+                   user_profile_path.Append(chrome::kPreferencesFilename));
+    base::CopyDirectory(src_dir.AppendASCII("Extensions"), user_profile_path,
+                        true);
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OemAppPositionTest);
+};
+
+IN_PROC_BROWSER_TEST_F(OemAppPositionTest, PRE_ValidOemAppPosition) {
+  RegisterUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
+  chromeos::StartupUtils::MarkOobeCompleted();
+}
+
+// Tests that an Oem app and its folder are created with valid positions after
+// sign-in.
+IN_PROC_BROWSER_TEST_F(OemAppPositionTest, ValidOemAppPosition) {
+  LoginUser(AccountId::FromUserEmailGaiaId(kTestUser, kTestUserGaiaId));
+
+  AppListClientImpl* client = AppListClientImpl::GetInstance();
+  ASSERT_TRUE(client);
+  client->UpdateProfile();
+  AppListModelUpdater* model_updater = test::GetModelUpdater(client);
+
+  const ChromeAppListItem* oem_app = model_updater->FindItem(kOemAppId);
+  EXPECT_TRUE(oem_app);
+  EXPECT_TRUE(oem_app->position().IsValid());
+
+  const ChromeAppListItem* oem_folder =
+      model_updater->FindItem(ash::kOemFolderId);
+  EXPECT_TRUE(oem_folder);
+  EXPECT_TRUE(oem_folder->position().IsValid());
+}
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_item.cc b/chrome/browser/ui/app_list/crostini/crostini_app_item.cc
index 14e0c95..972fda1 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_item.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_item.cc
@@ -34,7 +34,7 @@
   if (sync_item && sync_item->item_ordinal.IsValid()) {
     UpdateFromSync(sync_item);
   } else {
-    SetDefaultPositionIfApplicable();
+    SetDefaultPositionIfApplicable(model_updater);
 
     // Crostini app is created from scratch. Move it to default folder.
     DCHECK(folder_id().empty());
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
index 491c4707..1999fed 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder.cc
@@ -135,6 +135,6 @@
   crositini_folder->SetChromeIsFolder(true);
   crositini_folder->SetName(
       l10n_util::GetStringUTF8(IDS_APP_LIST_CROSTINI_DEFAULT_FOLDER_NAME));
-  crositini_folder->SetDefaultPositionIfApplicable();
+  crositini_folder->SetDefaultPositionIfApplicable(model_updater());
   InsertApp(std::move(crositini_folder));
 }
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index 3b2bc34..bd25f8d 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -57,14 +57,13 @@
   if (sync_item && sync_item->item_ordinal.IsValid())
     UpdateFromSync(sync_item);
   else
-    SetDefaultPositionIfApplicable();
+    SetDefaultPositionIfApplicable(model_updater);
 
   // Set model updater last to avoid being called during construction.
   set_model_updater(model_updater);
 }
 
-ExtensionAppItem::~ExtensionAppItem() {
-}
+ExtensionAppItem::~ExtensionAppItem() = default;
 
 void ExtensionAppItem::Reload() {
   const Extension* extension = GetExtension();
@@ -93,8 +92,7 @@
 const Extension* ExtensionAppItem::GetExtension() const {
   const extensions::ExtensionRegistry* registry =
       extensions::ExtensionRegistry::Get(profile());
-  const Extension* extension = registry->GetInstalledExtension(
-      extension_id());
+  const Extension* extension = registry->GetInstalledExtension(extension_id());
   return extension;
 }
 
@@ -104,8 +102,8 @@
     return false;
 
   if (!extension_enable_flow_) {
-    extension_enable_flow_ = std::make_unique<ExtensionEnableFlow>(
-        profile(), extension_id(), this);
+    extension_enable_flow_ =
+        std::make_unique<ExtensionEnableFlow>(profile(), extension_id(), this);
     extension_enable_flow_->StartForNativeWindow(nullptr);
   }
   return true;
@@ -153,8 +151,7 @@
     return;
 
   extensions::RecordAppListMainLaunch(extension);
-  GetController()->ActivateApp(profile(),
-                               extension,
+  GetController()->ActivateApp(profile(), extension,
                                AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
                                event_flags);
 }
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_item.cc b/chrome/browser/ui/app_list/internal_app/internal_app_item.cc
index b2c7b46..e314a96 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_item.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_item.cc
@@ -7,14 +7,14 @@
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/ui/app_list/app_context_menu.h"
+#include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
 
 void RecordActiveHistogram(app_list::InternalAppName name) {
-  UMA_HISTOGRAM_ENUMERATION(
-      "Apps.AppListInternalApp.Activate", name);
+  UMA_HISTOGRAM_ENUMERATION("Apps.AppListInternalApp.Activate", name);
 }
 
 }  // namespace
@@ -24,6 +24,7 @@
 
 InternalAppItem::InternalAppItem(
     Profile* profile,
+    AppListModelUpdater* model_updater,
     const app_list::AppListSyncableService::SyncItem* sync_item,
     const app_list::InternalApp& internal_app)
     : ChromeAppListItem(profile, internal_app.app_id) {
@@ -34,7 +35,7 @@
   if (sync_item && sync_item->item_ordinal.IsValid())
     UpdateFromSync(sync_item);
   else
-    SetDefaultPositionIfApplicable();
+    SetDefaultPositionIfApplicable(model_updater);
 }
 
 InternalAppItem::~InternalAppItem() = default;
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_item.h b/chrome/browser/ui/app_list/internal_app/internal_app_item.h
index 0c520e03..d9158e7 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_item.h
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_item.h
@@ -11,7 +11,7 @@
 namespace app_list {
 class AppContextMenu;
 struct InternalApp;
-}
+}  // namespace app_list
 
 // A class that represents an internal app in launcher.
 class InternalAppItem : public ChromeAppListItem {
@@ -19,6 +19,7 @@
   static const char kItemType[];
 
   InternalAppItem(Profile* profile,
+                  AppListModelUpdater* model_updater,
                   const app_list::AppListSyncableService::SyncItem* sync_item,
                   const app_list::InternalApp& internal_app);
   ~InternalAppItem() override;
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc b/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc
index fd5c769..81bd0557 100644
--- a/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/internal_app/internal_app_model_builder.cc
@@ -19,6 +19,7 @@
       continue;
 
     InsertApp(std::make_unique<InternalAppItem>(
-        profile(), GetSyncItem(internal_app.app_id), internal_app));
+        profile(), model_updater(), GetSyncItem(internal_app.app_id),
+        internal_app));
   }
 }
diff --git a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc
index b4101ac..d8f4468 100644
--- a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc
@@ -107,6 +107,20 @@
   std::move(callback).Run(id_to_app_list_index);
 }
 
+syncer::StringOrdinal FakeAppListModelUpdater::GetFirstAvailablePosition()
+    const {
+  std::vector<ChromeAppListItem*> top_level_items;
+  for (auto& item : items_) {
+    DCHECK(item->position().IsValid())
+        << "Item with invalid position: id=" << item->id()
+        << ", name=" << item->name() << ", is_folder=" << item->is_folder()
+        << ", is_page_break=" << item->is_page_break();
+    if (item->folder_id().empty() && item->position().IsValid())
+      top_level_items.emplace_back(item.get());
+  }
+  return GetFirstAvailablePositionInternal(top_level_items);
+}
+
 void FakeAppListModelUpdater::GetContextMenuModel(
     const std::string& id,
     GetMenuModelCallback callback) {
@@ -144,7 +158,6 @@
         std::make_unique<ChromeAppListItem>(nullptr, ash::kOemFolderId,
                                             nullptr);
     oem_folder = new_folder.get();
-    AddItem(std::move(new_folder));
     ash::mojom::AppListItemMetadataPtr folder_data =
         oem_folder->CloneMetadata();
     folder_data->position = preferred_oem_position.IsValid()
@@ -152,6 +165,7 @@
                                 : GetOemFolderPos();
     folder_data->name = oem_folder_name;
     oem_folder->SetMetadata(std::move(folder_data));
+    AddItem(std::move(new_folder));
   }
   return oem_folder->CloneMetadata();
 }
@@ -161,8 +175,11 @@
   // We don't have the information in Chrome, so the returned position
   // here is not guaranteed correct.
   size_t web_store_app_index;
-  if (!FindItemIndexForTest(extensions::kWebStoreAppId, &web_store_app_index))
+  if (!FindItemIndexForTest(extensions::kWebStoreAppId, &web_store_app_index)) {
+    if (items_.empty())
+      return syncer::StringOrdinal::CreateInitialOrdinal();
     return items_.back()->position().CreateAfter();
+  }
   const ChromeAppListItem* web_store_app_item =
       ItemAtForTest(web_store_app_index);
   return web_store_app_item->position().CreateAfter();
diff --git a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h
index 6ddfd3a2..63678fe 100644
--- a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h
@@ -51,6 +51,7 @@
   ChromeAppListItem* FindFolderItem(const std::string& folder_id) override;
   bool FindItemIndexForTest(const std::string& id, size_t* index) override;
   void GetIdToAppListIndexMap(GetIdToAppListIndexMapCallback callback) override;
+  syncer::StringOrdinal GetFirstAvailablePosition() const override;
   void GetContextMenuModel(const std::string& id,
                            GetMenuModelCallback callback) override;
   size_t BadgedItemCount() override;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm b/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm
deleted file mode 100644
index 286231c..0000000
--- a/chrome/browser/ui/cocoa/browser_window_cocoa_views_mac.mm
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018 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.
-
-#import "chrome/browser/ui/cocoa/browser_window_views_mac.h"
-
-#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
-
-TabWindowController* TabWindowControllerForWindow(NSWindow* window) {
-  return [TabWindowController tabWindowControllerForWindow:window];
-}
diff --git a/chrome/browser/ui/cocoa/browser_window_command_handler.mm b/chrome/browser/ui/cocoa/browser_window_command_handler.mm
index bc091e0..cb6b244 100644
--- a/chrome/browser/ui/cocoa/browser_window_command_handler.mm
+++ b/chrome/browser/ui/cocoa/browser_window_command_handler.mm
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/browser_window_views_mac.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_views_mac.h b/chrome/browser/ui/cocoa/browser_window_views_mac.h
deleted file mode 100644
index c85d389..0000000
--- a/chrome/browser/ui/cocoa/browser_window_views_mac.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 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_UI_COCOA_BROWSER_WINDOW_VIEWS_MAC_H_
-#define CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_VIEWS_MAC_H_
-
-// This file contains functions to support browser window code on Mac which may
-// need to deal with either a views browser window or a Cocoa browser window.
-
-// TODO(tapted): BrowserWindowController and TabWindowController shouldn't be
-// visible here (or in any files that import this header). Declare a protocol
-// instead that describes the dependencies needed outside of Cocoa-specific
-// code.
-@class NSWindow;
-@class TabWindowController;
-
-// Returns the TabWindowController backing a Cocoa browser window. Always
-// returns nil if |window| is a views browser window.
-TabWindowController* TabWindowControllerForWindow(NSWindow* window);
-
-#endif  // CHROME_BROWSER_UI_COCOA_BROWSER_WINDOW_VIEWS_MAC_H_
diff --git a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
index c08891c..8a011b1 100644
--- a/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
+++ b/chrome/browser/ui/cocoa/chrome_command_dispatcher_delegate.mm
@@ -12,7 +12,6 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
-#import "chrome/browser/ui/cocoa/browser_window_views_mac.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "ui/content_accelerators/accelerator_util.h"
 #include "ui/views/widget/widget.h"
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
index 488ff778..d2a667b 100644
--- a/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions.mm
@@ -118,9 +118,14 @@
   // there, let's try a pragmatic hack.
   if ([eventString characterAtIndex:0] > 0x7f &&
       [[event characters] length] > 0 &&
-      [[event characters] characterAtIndex:0] <= 0x7f)
+      [[event characters] characterAtIndex:0] <= 0x7f) {
     eventString = [event characters];
 
+    // Process the shift if necessary.
+    if (eventModifiers & NSShiftKeyMask)
+      eventString = [eventString uppercaseString];
+  }
+
   // We intentionally leak this object.
   static __attribute__((unused)) KeyboardInputSourceListener* listener =
       [[KeyboardInputSourceListener alloc] init];
diff --git a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
index 9884e1d..5bd4a29 100644
--- a/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
+++ b/chrome/browser/ui/cocoa/nsmenuitem_additions_unittest.mm
@@ -316,6 +316,21 @@
   key = KeyEvent(0x60103, @"\x19", @"\x19", 1);
   ExpectKeyFiresItem(key, MenuItem(@"\x9", NSShiftKeyMask | NSControlKeyMask),
                      false);
+
+  // In 2-set Korean layout, (cmd + shift + t) and (cmd + t) both produce
+  // multi-byte unmodified chars. For keyEquivalent purposes, we use their
+  // raw characters, where "shift" should be handled correctly.
+  key = KeyEvent(0x100108, @"t", @"\u3145", 17);
+  ExpectKeyFiresItem(key, MenuItem(@"t", NSCommandKeyMask),
+                     /*compareCocoa=*/false);
+  ExpectKeyDoesntFireItem(key, MenuItem(@"T", NSCommandKeyMask),
+                          /*compareCocoa=*/false);
+
+  key = KeyEvent(0x12010a, @"t", @"\u3146", 17);
+  ExpectKeyDoesntFireItem(key, MenuItem(@"t", NSCommandKeyMask),
+                          /*compareCocoa=*/false);
+  ExpectKeyFiresItem(key, MenuItem(@"T", NSCommandKeyMask),
+                     /*compareCocoa=*/false);
 }
 
 NSString* keyCodeToCharacter(NSUInteger keyCode,
diff --git a/chrome/browser/ui/cocoa/share_menu_controller.mm b/chrome/browser/ui/cocoa/share_menu_controller.mm
index 2b35530..ac979a5e 100644
--- a/chrome/browser/ui/cocoa/share_menu_controller.mm
+++ b/chrome/browser/ui/cocoa/share_menu_controller.mm
@@ -6,6 +6,7 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_util.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/mac/sdk_forward_declarations.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
@@ -13,19 +14,19 @@
 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/accelerators_cocoa.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/browser_window_views_mac.h"
-#import "chrome/browser/ui/cocoa/fast_resize_view.h"
-#import "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "net/base/mac/url_conversions.h"
 #include "ui/base/accelerators/platform_accelerator_cocoa.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/image.h"
+#include "ui/gfx/mac/coordinate_conversion.h"
 #include "ui/snapshot/snapshot.h"
+#include "ui/views/view.h"
 
 // Private method, used to identify instantiated services.
 @interface NSSharingService (ExposeName)
@@ -86,12 +87,12 @@
   [menu removeAllItems];
   [menu setAutoenablesItems:NO];
 
-  Browser* lastActiveBrowser = chrome::GetLastActiveBrowser();
+  Browser* lastActiveBrowser = chrome::FindLastActive();
   BOOL canShare =
       lastActiveBrowser != nullptr &&
       // Avoid |CanEmailPageLocation| segfault in interactive UI tests
       lastActiveBrowser->tab_strip_model()->GetActiveWebContents() != nullptr &&
-      chrome::CanEmailPageLocation(chrome::GetLastActiveBrowser());
+      chrome::CanEmailPageLocation(lastActiveBrowser);
   // Using a real URL instead of empty string to avoid system log about relative
   // URLs in the pasteboard. This URL will not actually be shared to, just used
   // to fetch sharing services that can handle the NSURL type.
@@ -156,17 +157,23 @@
 // Saves details required by delegate methods for the transition animation.
 - (void)saveTransitionDataFromBrowser:(Browser*)browser {
   windowForShare_ = browser->window()->GetNativeWindow();
+  BrowserView* browserView = BrowserView::GetBrowserViewForBrowser(browser);
+  if (!browserView)
+    return;
 
-  TabWindowController* tabWindowController =
-      TabWindowControllerForWindow(windowForShare_);
-  NSView* contentsView = [tabWindowController tabContentArea];
-  NSRect rectInWindow =
-      [[contentsView superview] convertRect:[contentsView frame] toView:nil];
-  rectForShare_ = [windowForShare_ convertRectToScreen:rectInWindow];
+  views::View* contentsView = browserView->contents_container();
+  if (!contentsView)
+    return;
 
+  gfx::Rect screenRect = contentsView->bounds();
+  views::View::ConvertRectToScreen(browserView, &screenRect);
+
+  rectForShare_ = ScreenRectToNSRect(screenRect);
+
+  gfx::Rect rectInWidget =
+      browserView->ConvertRectToWidget(contentsView->bounds());
   gfx::Image image;
-  gfx::Rect rect = gfx::Rect(NSRectToCGRect([contentsView bounds]));
-  if (ui::GrabViewSnapshot(contentsView, rect, &image)) {
+  if (ui::GrabWindowSnapshot(windowForShare_, rectInWidget, &image)) {
     snapshotForShare_.reset(image.CopyNSImage());
   }
 }
@@ -183,7 +190,7 @@
 
 // Performs the share action using the sharing service represented by |sender|.
 - (void)performShare:(NSMenuItem*)sender {
-  Browser* browser = chrome::GetLastActiveBrowser();
+  Browser* browser = chrome::FindLastActive();
   DCHECK(browser);
   [self saveTransitionDataFromBrowser:browser];
 
diff --git a/chrome/browser/ui/forced_reauthentication_dialog.h b/chrome/browser/ui/forced_reauthentication_dialog.h
index 7f087b4..6beab174 100644
--- a/chrome/browser/ui/forced_reauthentication_dialog.h
+++ b/chrome/browser/ui/forced_reauthentication_dialog.h
@@ -9,8 +9,11 @@
 
 #include "base/macros.h"
 
+namespace identity {
+class IdentityManager;
+}
+
 class Profile;
-class SigninManager;
 
 namespace base {
 class TimeDelta;
@@ -23,12 +26,12 @@
 
   virtual ~ForcedReauthenticationDialog() {}
   // Show the ForcedReauthenticationDialog for |profile|. If there're no opened
-  // browser windows for |profile|, |signin_manager| will be called to signed
+  // browser windows for |profile|, |identity_manager| will be called to signed
   // out immediately. Otherwise, dialog will be closed with all browser windows
   // are associated to |profile| after |countdown_duration| if there is no
   // reauth.
   virtual void ShowDialog(Profile* profile,
-                          SigninManager* signin_manager,
+                          identity::IdentityManager* identity_manager,
                           base::TimeDelta countdown_duration) = 0;
 
  protected:
diff --git a/chrome/browser/ui/hats/README.md b/chrome/browser/ui/hats/README.md
new file mode 100644
index 0000000..3f81cd2
--- /dev/null
+++ b/chrome/browser/ui/hats/README.md
@@ -0,0 +1,6 @@
+chrome/browser/ui/hats
+=====================
+
+This directory contains HaTS (Happiness Tracking Survey) code that is used to service the display of surveys launched from any trigger point within Chrome.
+
+This code will coordinate with user's profiles to ensure that Chrome is not serving too many surveys to a single profile, only targeting profiles have UMA enabled, and not targeting enterprise users.
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
new file mode 100644
index 0000000..7f7b538
--- /dev/null
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -0,0 +1,64 @@
+// Copyright 2018 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/ui/hats/hats_service.h"
+
+#include <stddef.h>
+
+#include <iostream>
+
+#include "base/metrics/field_trial_params.h"
+#include "base/rand_util.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/common/chrome_features.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+// which survey we're triggering
+const char kHatsSurveyTrigger[] = "survey";
+
+const char kHatsSurveyProbability[] = "probability";
+
+const char kHatsSurveyEnSiteID[] = "en_site_id";
+
+const char kHatsSurveyTriggerDefault[] = "test";
+
+const double kHatsSurveyProbabilityDefault = 1;
+
+const char kHatsSurveyEnSiteIDDefault[] = "z4cctguzopq5x2ftal6vdgjrui";
+
+HatsFinchConfig CreateHatsFinchConfig() {
+  HatsFinchConfig config;
+  config.trigger = base::FeatureParam<std::string>(
+                       &features::kHappinessTrackingSurveysForDesktop,
+                       kHatsSurveyTrigger, kHatsSurveyTriggerDefault)
+                       .Get();
+
+  config.probability =
+      base::FeatureParam<double>(&features::kHappinessTrackingSurveysForDesktop,
+                                 kHatsSurveyProbability,
+                                 kHatsSurveyProbabilityDefault)
+          .Get();
+
+  config.site_ids.insert(
+      std::make_pair("en", base::FeatureParam<std::string>(
+                               &features::kHappinessTrackingSurveysForDesktop,
+                               kHatsSurveyEnSiteID, kHatsSurveyEnSiteIDDefault)
+                               .Get()));
+  return config;
+}
+
+}  // namespace
+
+HatsFinchConfig::HatsFinchConfig() = default;
+HatsFinchConfig::~HatsFinchConfig() = default;
+HatsFinchConfig::HatsFinchConfig(const HatsFinchConfig& other) = default;
+
+HatsService::HatsService(Profile* profile)
+    : profile_(profile), hats_finch_config_(CreateHatsFinchConfig()) {}
+
+bool HatsService::ShouldShowSurvey() {
+  return (base::RandDouble() < hats_finch_config_.probability);
+  // TODO add pref checks to avoid too many surveys for a single profile
+}
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h
new file mode 100644
index 0000000..192b0cd8
--- /dev/null
+++ b/chrome/browser/ui/hats/hats_service.h
@@ -0,0 +1,50 @@
+// Copyright 2018 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_UI_HATS_HATS_SERVICE_H_
+#define CHROME_BROWSER_UI_HATS_HATS_SERVICE_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+class Profile;
+
+struct HatsFinchConfig {
+  HatsFinchConfig();
+  ~HatsFinchConfig();
+  HatsFinchConfig(const HatsFinchConfig& other);
+
+  double probability;   // This is the percent of users [0,1] that will see the
+                        // survey
+  std::string trigger;  // This is the name of the survey in question.
+
+  // This is a map between the locale being presented and the site ID used to
+  // fetch the survey.
+  std::map<std::string, std::string> site_ids;
+};
+
+// This class provides the client side logic for determining if a
+// survey should be shown for any trigger based on input from a finch
+// configuration. It is created on a per profile basis.
+class HatsService : public KeyedService {
+ public:
+  explicit HatsService(Profile* profile);
+  bool ShouldShowSurvey();
+
+ private:
+  Profile* profile_;
+  const HatsFinchConfig hats_finch_config_;
+
+  FRIEND_TEST_ALL_PREFIXES(HatsForceEnabledTest, ParamsWithAForcedFlagTest);
+
+  DISALLOW_COPY_AND_ASSIGN(HatsService);
+};
+
+#endif  // CHROME_BROWSER_UI_HATS_HATS_SERVICE_H_
diff --git a/chrome/browser/ui/hats/hats_service_factory.cc b/chrome/browser/ui/hats/hats_service_factory.cc
new file mode 100644
index 0000000..2fa63971
--- /dev/null
+++ b/chrome/browser/ui/hats/hats_service_factory.cc
@@ -0,0 +1,39 @@
+// Copyright 2018 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/ui/hats/hats_service_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/hats/hats_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+// static
+HatsService* HatsServiceFactory::GetForProfile(Profile* profile,
+                                               bool create_if_necessary) {
+  return static_cast<HatsService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, create_if_necessary));
+}
+
+// static
+HatsServiceFactory* HatsServiceFactory::GetInstance() {
+  return base::Singleton<HatsServiceFactory>::get();
+}
+
+HatsServiceFactory::HatsServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "HatsService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(IdentityManagerFactory::GetInstance());
+}
+
+KeyedService* HatsServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+
+  return new HatsService(profile);
+}
+
+HatsServiceFactory::~HatsServiceFactory() {}
diff --git a/chrome/browser/ui/hats/hats_service_factory.h b/chrome/browser/ui/hats/hats_service_factory.h
new file mode 100644
index 0000000..cd75912
--- /dev/null
+++ b/chrome/browser/ui/hats/hats_service_factory.h
@@ -0,0 +1,33 @@
+// Copyright 2018 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_UI_HATS_HATS_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_UI_HATS_HATS_SERVICE_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class HatsService;
+class Profile;
+
+class HatsServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static HatsService* GetForProfile(Profile* profile, bool create_if_necessary);
+  static HatsServiceFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<HatsServiceFactory>;
+
+  HatsServiceFactory();
+  ~HatsServiceFactory() override;
+
+  // Overrides from BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(HatsServiceFactory);
+};
+
+#endif  // CHROME_BROWSER_UI_HATS_HATS_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/hats/hats_unittest.cc b/chrome/browser/ui/hats/hats_unittest.cc
new file mode 100644
index 0000000..ed56f9a42
--- /dev/null
+++ b/chrome/browser/ui/hats/hats_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2018 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/ui/hats/hats_service.h"
+
+#include <memory>
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/common/chrome_features.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class HatsForceEnabledTest : public testing::Test {
+ public:
+  HatsForceEnabledTest() {}
+
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatureState(
+        features::kHappinessTrackingSurveysForDesktop, true);
+    // I'm passing in a null pointer for profile for now.
+    hats_service_ = std::make_unique<HatsService>(nullptr);
+  }
+
+ protected:
+  std::unique_ptr<HatsService> hats_service_;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(HatsForceEnabledTest, ParamsWithAForcedFlagTest) {
+  ASSERT_EQ(1, hats_service_->hats_finch_config_.probability);
+}
diff --git a/chrome/browser/ui/passwords/password_manager_presenter.cc b/chrome/browser/ui/passwords/password_manager_presenter.cc
index 46cc748..cbd01dda 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter.cc
@@ -30,9 +30,9 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_sync_util.h"
 #include "components/password_manager/core/browser/password_ui_utils.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "components/password_manager/sync/browser/password_sync_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/undo/undo_operation.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index eb3aba1..48f0d7f2 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -19,11 +19,14 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
+#include "chrome/browser/ui/hats/hats_service.h"
+#include "chrome/browser/ui/hats/hats_service_factory.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/omnibox/clipboard_utils.h"
 #include "chrome/browser/ui/search/ntp_user_data_logger.h"
 #include "chrome/browser/ui/search/search_ipc_router_policy_impl.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/browser_sync/profile_sync_service.h"
@@ -220,6 +223,17 @@
     if (search::IsInstantNTP(web_contents_))
       RecordNewTabLoadTime(web_contents_);
   }
+
+#if !defined(OS_ANDROID)
+  if (base::FeatureList::IsEnabled(
+          features::kHappinessTrackingSurveysForDesktop)) {
+    HatsService* hats_service =
+        HatsServiceFactory::GetForProfile(profile(), true);
+    if (hats_service->ShouldShowSurvey()) {
+      // TODO launch bubble;
+    }
+  }
+#endif  // !defined(OS_ANDROID)
 }
 
 void SearchTabHelper::NavigationEntryCommitted(
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index 1cb8021..5c3afd34 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/signin_tracker_factory.h"
 #include "chrome/browser/signin/signin_util.h"
@@ -40,7 +39,6 @@
 #include "components/account_id/account_id.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/sync/base/sync_prefs.h"
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
index ec15b40f..e1352c6 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_browsertest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
-#include "chrome/browser/ui/views_mode_controller.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -53,15 +52,6 @@
 
 // Clicks the location icon to open the page info bubble.
 void OpenPageInfoBubble(Browser* browser) {
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-  if (views_mode_controller::IsViewsBrowserCocoa()) {
-    content::WebContents* contents =
-        browser->tab_strip_model()->GetActiveWebContents();
-    ShowPageInfoDialog(contents);
-    return;
-  }
-#endif
-
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
   LocationIconView* location_icon_view =
       browser_view->toolbar()->location_bar()->location_icon_view();
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
index 125c152..663dd8a0 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
@@ -68,11 +68,7 @@
         AccountTrackerServiceFactory::GetForProfile(profile_));
   }
 
-  // In non-touch mode we use a larger-than-normal icon size for avatars as 16dp
-  // is hard to read for user avatars. This constant is correspondingly smaller
-  // than GetLayoutInsets(TOOLBAR_BUTTON).
-  if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled())
-    SetLayoutInsets(GetLayoutInsets(TOOLBAR_BUTTON) - gfx::Insets(2));
+  SetInsets();
 
   // Activate on press for left-mouse-button only to mimic other MenuButtons
   // without drag-drop actions (specifically the adjacent browser menu).
@@ -102,9 +98,11 @@
   // outside as GetThemeProvider() is not available until the button is added to
   // ToolbarView's hierarchy.
   UpdateText();
+
+  md_observer_.Add(ui::MaterialDesignController::GetInstance());
 }
 
-AvatarToolbarButton::~AvatarToolbarButton() = default;
+AvatarToolbarButton::~AvatarToolbarButton() {}
 
 void AvatarToolbarButton::UpdateIcon() {
   SetImage(views::Button::STATE_NORMAL, GetAvatarIcon());
@@ -193,6 +191,11 @@
   UpdateIcon();
 }
 
+void AvatarToolbarButton::OnMdModeChanged() {
+  SetInsets();
+  PreferredSizeChanged();
+}
+
 bool AvatarToolbarButton::IsIncognito() const {
   return profile_->IsOffTheRecord() && !profile_->IsGuestSession();
 }
@@ -331,3 +334,12 @@
 #endif  // !defined(OS_CHROMEOS)
   return SyncState::kNormal;
 }
+
+void AvatarToolbarButton::SetInsets() {
+  // In non-touch mode we use a larger-than-normal icon size for avatars as 16dp
+  // is hard to read for user avatars. This constant is correspondingly smaller
+  // than GetLayoutInsets(TOOLBAR_BUTTON).
+  SetLayoutInsets(ui::MaterialDesignController::IsTouchOptimizedUiEnabled()
+                      ? gfx::Insets()
+                      : GetLayoutInsets(TOOLBAR_BUTTON) - gfx::Insets(2));
+}
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
index 123fcfa..5f34f77 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
+#include "ui/base/material_design/material_design_controller_observer.h"
 #include "ui/events/event.h"
 
 class Browser;
@@ -22,7 +23,8 @@
                             public AvatarButtonErrorControllerDelegate,
                             public ProfileAttributesStorage::Observer,
                             public GaiaCookieManagerService::Observer,
-                            public AccountTrackerService::Observer {
+                            public AccountTrackerService::Observer,
+                            public ui::MaterialDesignControllerObserver {
  public:
   explicit AvatarToolbarButton(Browser* browser);
   ~AvatarToolbarButton() override;
@@ -62,6 +64,9 @@
                              const gfx::Image& image) override;
   void OnAccountRemoved(const AccountInfo& info) override;
 
+  // ui::MaterialDesignControllerObserver:
+  void OnMdModeChanged() override;
+
   bool IsIncognito() const;
   bool ShouldShowGenericIcon() const;
   base::string16 GetAvatarTooltipText() const;
@@ -69,6 +74,8 @@
   gfx::Image GetIconImageFromProfile() const;
   SyncState GetSyncState() const;
 
+  void SetInsets();
+
   Browser* const browser_;
   Profile* const profile_;
 
@@ -81,6 +88,8 @@
       cookie_manager_service_observer_;
   ScopedObserver<AccountTrackerService, AvatarToolbarButton>
       account_tracker_service_observer_;
+  ScopedObserver<ui::MaterialDesignController, AvatarToolbarButton>
+      md_observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(AvatarToolbarButton);
 };
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc
index 5db069e5..4178179 100644
--- a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc
+++ b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.cc
@@ -25,6 +25,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
@@ -43,8 +44,9 @@
 // finish sign in.
 constexpr int kCloseDirectlyTimer = 60;
 
-void Signout(SigninManager* signin_manager) {
-  signin_manager->SignOut(
+void Signout(identity::IdentityManager* identity_manager) {
+  identity_manager->ClearPrimaryAccount(
+      identity::IdentityManager::ClearAccountTokensAction::kDefault,
       signin_metrics::AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN,
       signin_metrics::SignoutDelete::KEEPING);
 }
@@ -87,10 +89,10 @@
 
 ForcedReauthenticationDialogView::ForcedReauthenticationDialogView(
     Browser* browser,
-    SigninManager* signin_manager,
+    identity::IdentityManager* identity_manager,
     base::TimeDelta countdown_duration)
     : browser_(browser),
-      signin_manager_(signin_manager),
+      identity_manager_(identity_manager),
       desired_close_time_(base::TimeTicks::Now() + countdown_duration),
       weak_factory_(this) {
   constrained_window::CreateBrowserModalDialogViews(
@@ -105,22 +107,22 @@
 // static
 ForcedReauthenticationDialogView* ForcedReauthenticationDialogView::ShowDialog(
     Profile* profile,
-    SigninManager* signin_manager,
+    identity::IdentityManager* identity_manager,
     base::TimeDelta countdown_duration) {
   Browser* browser = FindBrowserWithProfile(profile);
   if (browser == nullptr) {  // If there is no browser, we can just sign
                              // out profile directly.
-    Signout(signin_manager);
+    Signout(identity_manager);
     return nullptr;
   }
 
-  return new ForcedReauthenticationDialogView(browser, signin_manager,
+  return new ForcedReauthenticationDialogView(browser, identity_manager,
                                               countdown_duration);
 }
 
 bool ForcedReauthenticationDialogView::Accept() {
   if (GetTimeRemaining() < base::TimeDelta::FromSeconds(kCloseDirectlyTimer)) {
-    Signout(signin_manager_);
+    Signout(identity_manager_);
   } else {
     browser_->signin_view_controller()->ShowSignin(
         profiles::BubbleViewMode::BUBBLE_VIEW_MODE_GAIA_REAUTH, browser_,
@@ -163,7 +165,7 @@
           GetNativeTheme(), ui::kSigninConfirmationPromptBarBackgroundAlpha);
   // Create the prompt label.
   size_t offset;
-  std::string email = signin_manager_->GetAuthenticatedAccountInfo().email;
+  std::string email = identity_manager_->GetPrimaryAccountInfo().email;
   const base::string16 domain =
       base::ASCIIToUTF16(gaia::ExtractDomainName(email));
   const base::string16 prompt_text =
@@ -270,10 +272,10 @@
 
 void ForcedReauthenticationDialogImpl::ShowDialog(
     Profile* profile,
-    SigninManager* signin_manager,
+    identity::IdentityManager* identity_manager,
     base::TimeDelta countdown_duration) {
   dialog_view_ = ForcedReauthenticationDialogView::ShowDialog(
-                     profile, signin_manager, countdown_duration)
+                     profile, identity_manager, countdown_duration)
                      ->AsWeakPtr();
 }
 
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h
index 653ec7cf..d4a9885 100644
--- a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h
+++ b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view.h
@@ -16,9 +16,12 @@
 #include "ui/views/controls/button/button.h"
 #include "ui/views/window/dialog_delegate.h"
 
+namespace identity {
+class IdentityManager;
+}
+
 class Browser;
 class Profile;
-class SigninManager;
 
 // A modal dialog that displays a warning message of the auth failure
 // and ask user to sign in again.
@@ -33,7 +36,7 @@
   // Dialog will delete itself after closing.
   static ForcedReauthenticationDialogView* ShowDialog(
       Profile* profile,
-      SigninManager* signin_manager,
+      identity::IdentityManager* identity_manager,
       base::TimeDelta countdown_duration);
 
   // override views::DialogDelegateView
@@ -57,14 +60,14 @@
  private:
   // Show the dialog for |browser|. The dialog will delete itself after closing.
   ForcedReauthenticationDialogView(Browser* browser,
-                                   SigninManager* signin_manager,
+                                   identity::IdentityManager* identity_manager,
                                    base::TimeDelta countdown_duration);
 
   void OnCountDown();
   base::TimeDelta GetTimeRemaining() const;
 
   Browser* const browser_;
-  SigninManager* signin_manager_;
+  identity::IdentityManager* identity_manager_;
 
   const base::TimeTicks desired_close_time_;
 
@@ -84,7 +87,7 @@
 
   // override ForcedReauthenticationDialog
   void ShowDialog(Profile* profile,
-                  SigninManager* signin_manager,
+                  identity::IdentityManager* identity_manager,
                   base::TimeDelta countdown_duration) override;
 
  private:
diff --git a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc
index 24abcba..8080fdb 100644
--- a/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/forced_reauthentication_dialog_view_browsertest.cc
@@ -6,12 +6,15 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/signin/core/browser/signin_manager.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
 #include "ui/base/ui_base_types.h"
 
 class ForcedReauthenticationDialogViewBrowserTest : public DialogBrowserTest {
@@ -21,8 +24,14 @@
   // override DialogBrowserTest
   void ShowUi(const std::string& name) override {
     Profile* profile = browser()->profile();
-    SigninManager* manager = SigninManagerFactory::GetForProfile(profile);
-    manager->SetAuthenticatedAccountInfo("test1", "test@xyz.com");
+    identity::IdentityManager* manager =
+        IdentityManagerFactory::GetForProfile(profile);
+
+    identity::MakePrimaryAccountAvailable(
+        SigninManagerFactory::GetForProfile(profile),
+        ProfileOAuth2TokenServiceFactory::GetForProfile(profile), manager,
+        "test@xyz.com");
+
     ForcedReauthenticationDialogView::ShowDialog(
         profile, manager, base::TimeDelta::FromSeconds(60));
   }
@@ -43,9 +52,10 @@
                        NotOpenDialogDueToNoBrowser) {
   Profile* profile = browser()->profile();
   CloseBrowserSynchronously(browser());
-  EXPECT_EQ(nullptr, ForcedReauthenticationDialogView::ShowDialog(
-                         profile, SigninManagerFactory::GetForProfile(profile),
-                         base::TimeDelta::FromSeconds(60)));
+  EXPECT_EQ(nullptr,
+            ForcedReauthenticationDialogView::ShowDialog(
+                profile, IdentityManagerFactory::GetForProfile(profile),
+                base::TimeDelta::FromSeconds(60)));
 }
 
 IN_PROC_BROWSER_TEST_F(ForcedReauthenticationDialogViewBrowserTest,
@@ -55,7 +65,8 @@
   ASSERT_EQ(1, model->count());
   model->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
   ASSERT_TRUE(model->empty());
-  EXPECT_EQ(nullptr, ForcedReauthenticationDialogView::ShowDialog(
-                         profile, SigninManagerFactory::GetForProfile(profile),
-                         base::TimeDelta::FromSeconds(60)));
+  EXPECT_EQ(nullptr,
+            ForcedReauthenticationDialogView::ShowDialog(
+                profile, IdentityManagerFactory::GetForProfile(profile),
+                base::TimeDelta::FromSeconds(60)));
 }
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index 91e0c60..f08461aa1 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -68,11 +68,6 @@
 
   set_ink_drop_visible_opacity(kToolbarInkDropVisibleOpacity);
 
-  const int size = GetLayoutConstant(LOCATION_BAR_HEIGHT);
-  const int radii = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
-      views::EMPHASIS_MAXIMUM, gfx::Size(size, size));
-  set_ink_drop_corner_radii(radii, radii);
-
   md_observer_.Add(ui::MaterialDesignController::GetInstance());
 }
 
@@ -152,6 +147,11 @@
     image()->SetBoundsRect(GetContentsBounds());
   }
 
+  const int size = GetLayoutConstant(LOCATION_BAR_HEIGHT);
+  const int radii = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
+      views::EMPHASIS_MAXIMUM, gfx::Size(size, size));
+  set_ink_drop_corner_radii(radii, radii);
+
   AppMenuButton::Layout();
 }
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index ec1e1f0..0431382 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -76,11 +76,6 @@
 
   set_ink_drop_visible_opacity(kToolbarInkDropVisibleOpacity);
 
-  const int size = GetLayoutConstant(LOCATION_BAR_HEIGHT);
-  const int radii = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
-      views::EMPHASIS_MAXIMUM, gfx::Size(size, size));
-  set_ink_drop_corner_radii(radii, radii);
-
   UpdateState();
 }
 
@@ -307,6 +302,15 @@
   DoShowContextMenu(source_type);
 }
 
+void ToolbarActionView::Layout() {
+  const int size = GetLayoutConstant(LOCATION_BAR_HEIGHT);
+  const int radii = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
+      views::EMPHASIS_MAXIMUM, gfx::Size(size, size));
+  set_ink_drop_corner_radii(radii, radii);
+
+  views::MenuButton::Layout();
+}
+
 void ToolbarActionView::DoShowContextMenu(
     ui::MenuSourceType source_type) {
   ui::MenuModel* context_menu_model = view_controller_->GetContextMenu();
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
index 8743adb..ded64a2 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -120,6 +120,9 @@
                               const gfx::Point& point,
                               ui::MenuSourceType source_type) override;
 
+  // views::View:
+  void Layout() override;
+
   // Shows the context menu (if one exists) for the toolbar action.
   void DoShowContextMenu(ui::MenuSourceType source_type);
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index 91b751444..e306b0b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -50,11 +50,6 @@
 
   set_ink_drop_visible_opacity(kToolbarInkDropVisibleOpacity);
 
-  const int size = GetLayoutConstant(LOCATION_BAR_HEIGHT);
-  const int radii = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
-      views::EMPHASIS_MAXIMUM, gfx::Size(size, size));
-  set_ink_drop_corner_radii(radii, radii);
-
   SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
       DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
   SetHorizontalAlignment(gfx::ALIGN_RIGHT);
@@ -192,8 +187,7 @@
     show_menu_factory_.InvalidateWeakPtrs();
 }
 
-void ToolbarButton::OnMouseCaptureLost() {
-}
+void ToolbarButton::OnMouseCaptureLost() {}
 
 void ToolbarButton::OnMouseExited(const ui::MouseEvent& event) {
   // Starting a drag results in a MouseExited, we need to ignore it.
@@ -338,6 +332,15 @@
   menu_model_adapter_.reset();
 }
 
+void ToolbarButton::Layout() {
+  const int size = GetLayoutConstant(LOCATION_BAR_HEIGHT);
+  const int radii = ChromeLayoutProvider::Get()->GetCornerRadiusMetric(
+      views::EMPHASIS_MAXIMUM, gfx::Size(size, size));
+  set_ink_drop_corner_radii(radii, radii);
+
+  views::LabelButton::Layout();
+}
+
 const char* ToolbarButton::GetClassName() const {
   return "ToolbarButton";
 }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.h b/chrome/browser/ui/views/toolbar/toolbar_button.h
index 1075824..17975fe8 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.h
@@ -109,6 +109,9 @@
   // Callback for MenuModelAdapter.
   void OnMenuClosed();
 
+  // views::View:
+  void Layout() override;
+
   // views::ImageButton:
   const char* GetClassName() const override;
 
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc
index adb4279..bc6b01b9 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -151,9 +151,16 @@
                           base::Unretained(this)));
 
   web_ui()->RegisterMessageCallback(
-      syncer::sync_ui_util::kRequestStop,
-      base::BindRepeating(&SyncInternalsMessageHandler::HandleRequestStop,
-                          base::Unretained(this)));
+      syncer::sync_ui_util::kRequestStopKeepData,
+      base::BindRepeating(
+          &SyncInternalsMessageHandler::HandleRequestStopKeepData,
+          base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback(
+      syncer::sync_ui_util::kRequestStopClearData,
+      base::BindRepeating(
+          &SyncInternalsMessageHandler::HandleRequestStopClearData,
+          base::Unretained(this)));
 
   web_ui()->RegisterMessageCallback(
       syncer::sync_ui_util::kTriggerRefresh,
@@ -308,9 +315,24 @@
     return;
 
   service->RequestStart();
+  // If the service was previously stopped with CLEAR_DATA, then the
+  // "first-setup-complete" bit was also cleared, and now the service wouldn't
+  // fully start up. So set that too.
+  service->SetFirstSetupComplete();
 }
 
-void SyncInternalsMessageHandler::HandleRequestStop(
+void SyncInternalsMessageHandler::HandleRequestStopKeepData(
+    const base::ListValue* args) {
+  DCHECK_EQ(0U, args->GetSize());
+
+  SyncService* service = GetSyncService();
+  if (!service)
+    return;
+
+  service->RequestStop(SyncService::KEEP_DATA);
+}
+
+void SyncInternalsMessageHandler::HandleRequestStopClearData(
     const base::ListValue* args) {
   DCHECK_EQ(0U, args->GetSize());
 
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.h b/chrome/browser/ui/webui/sync_internals_message_handler.h
index 1ba4fc3..3f94dce4 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.h
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.h
@@ -74,8 +74,11 @@
   // Handler for requestStart message.
   void HandleRequestStart(const base::ListValue* args);
 
-  // Handler for requestStop message.
-  void HandleRequestStop(const base::ListValue* args);
+  // Handler for requestStopKeepData message.
+  void HandleRequestStopKeepData(const base::ListValue* args);
+
+  // Handler for requestStopClearData message.
+  void HandleRequestStopClearData(const base::ListValue* args);
 
   // Handler for triggerRefresh message.
   void HandleTriggerRefresh(const base::ListValue* args);
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 821f504f..355496c 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -649,7 +649,7 @@
 
 // Enable running shill in a minijail sandbox on Chrome OS.
 const base::Feature kShillSandboxing{"ShillSandboxing",
-                                     base::FEATURE_ENABLED_BY_DEFAULT};
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
 // Enable showing a tab-modal dialog while a Web Authentication API request is
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 826469f3c..d4f9778 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1907,6 +1907,9 @@
 
 // Whether camera-produced media files have been consolidated to one place.
 const char kCameraMediaConsolidated[] = "camera_media_consolidated";
+
+// Whether the user is allowed to disconnect and configure VPN connections.
+const char kVpnConfigAllowed[] = "vpn_config_allowed";
 #endif  // defined(OS_CHROMEOS)
 
 // Whether there is a Flash version installed that supports clearing LSO data.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index ad0e63f..89c4a33 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -638,6 +638,7 @@
 extern const char kArcAppInstallEventLoggingEnabled[];
 extern const char kRemoveUsersRemoteCommand[];
 extern const char kCameraMediaConsolidated[];
+extern const char kVpnConfigAllowed[];
 #endif  // defined(OS_CHROMEOS)
 
 extern const char kClearPluginLSODataEnabled[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b192d5e..88b6cbf 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2064,6 +2064,7 @@
     if (enable_app_list) {
       sources += [
         "../browser/ui/app_list/app_list_client_impl_browsertest.cc",
+        "../browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc",
         "../browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc",
       ]
     }
@@ -2804,6 +2805,7 @@
     # platforms.
     sources += [
       "../browser/component_updater/crl_set_component_installer_unittest.cc",
+      "../browser/ui/hats/hats_unittest.cc",
     ]
   }
 
@@ -5035,11 +5037,7 @@
     }
 
     if (is_mac) {
-      sources += [
-        "../browser/ui/find_bar/find_bar_platform_helper_mac_interactive_uitest.mm",
-        "base/interactive_test_utils_cocoa.h",
-        "base/interactive_test_utils_cocoa.mm",
-      ]
+      sources += [ "../browser/ui/find_bar/find_bar_platform_helper_mac_interactive_uitest.mm" ]
 
       data_deps += [
         "//chrome",
diff --git a/chrome/test/base/interactive_test_utils_cocoa.h b/chrome/test/base/interactive_test_utils_cocoa.h
deleted file mode 100644
index 9bd2407..0000000
--- a/chrome/test/base/interactive_test_utils_cocoa.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 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_TEST_BASE_INTERACTIVE_TEST_UTILS_COCOA_H_
-#define CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_COCOA_H_
-
-#include "chrome/browser/ui/view_ids.h"
-
-class Browser;
-
-namespace ui_test_utils {
-namespace internal {
-
-// Returns true of |vid| in |browser| is focused.
-bool IsViewFocusedCocoa(const Browser* browser, ViewID vid);
-
-// Simulates a mouse click on |vid| in |browser|.
-void ClickOnViewCocoa(const Browser* browser, ViewID vid);
-
-// Moves focus to |vid| in |browser|
-void FocusViewCocoa(const Browser* browser, ViewID vid);
-
-}  // namespace internal
-}  // namespace ui_test_utils
-
-#endif  // CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_COCOA_H_
diff --git a/chrome/test/base/interactive_test_utils_cocoa.mm b/chrome/test/base/interactive_test_utils_cocoa.mm
deleted file mode 100644
index 9a5bb98..0000000
--- a/chrome/test/base/interactive_test_utils_cocoa.mm
+++ /dev/null
@@ -1,116 +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 "chrome/test/base/interactive_test_utils_cocoa.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "build/buildflag.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "ui/base/cocoa/cocoa_base_utils.h"
-#include "ui/base/ui_features.h"
-
-namespace ui_test_utils {
-
-namespace internal {
-
-namespace {
-
-void MoveMouseToNSViewCenterAndPress(NSView* view,
-                                     ui_controls::MouseButton button,
-                                     int button_state,
-                                     const base::RepeatingClosure& task) {
-  NSWindow* window = [view window];
-  NSScreen* screen = [window screen];
-  DCHECK(screen);
-
-  // Converts the center position of the view into the coordinates accepted
-  // by SendMouseMoveNotifyWhenDone() method.
-  NSRect bounds = [view bounds];
-  NSPoint center = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
-  center = [view convertPoint:center toView:nil];
-  center = ui::ConvertPointFromWindowToScreen(window, center);
-  center = NSMakePoint(center.x, [screen frame].size.height - center.y);
-
-  ui_controls::SendMouseMoveNotifyWhenDone(
-      center.x, center.y,
-      base::BindOnce(&internal::ClickTask, button, button_state, task,
-                     ui_controls::kNoAccelerator));
-}
-
-}  // namespace
-
-bool IsViewFocusedCocoa(const Browser* browser, ViewID vid) {
-  NSWindow* window = browser->window()->GetNativeWindow();
-  DCHECK(window);
-  NSView* view = view_id_util::GetView(window, vid);
-  if (!view)
-    return false;
-
-  NSResponder* firstResponder = [window firstResponder];
-  if (firstResponder == static_cast<NSResponder*>(view))
-    return true;
-
-  // Handle special case for VIEW_ID_TAB_CONTAINER.  The tab container NSView
-  // always transfers first responder status to its subview, so test whether
-  // |firstResponder| is a descendant.
-  if (vid == VIEW_ID_TAB_CONTAINER &&
-      [firstResponder isKindOfClass:[NSView class]])
-    return [static_cast<NSView*>(firstResponder) isDescendantOf:view];
-
-  // Handle the special case of focusing a TextField.
-  if ([firstResponder isKindOfClass:[NSTextView class]]) {
-    NSView* delegate = static_cast<NSView*>([(NSTextView*)firstResponder
-                                                          delegate]);
-    if (delegate == view)
-      return true;
-  }
-
-  return false;
-}
-
-void ClickOnViewCocoa(const Browser* browser, ViewID vid) {
-  NSWindow* window = browser->window()->GetNativeWindow();
-  DCHECK(window);
-  NSView* view = view_id_util::GetView(window, vid);
-  DCHECK(view);
-  MoveMouseToNSViewCenterAndPress(
-      view, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
-      base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
-  content::RunMessageLoop();
-}
-
-void FocusViewCocoa(const Browser* browser, ViewID vid) {
-  NSWindow* window = browser->window()->GetNativeWindow();
-  DCHECK(window);
-  NSView* view = view_id_util::GetView(window, vid);
-  DCHECK(view);
-  [window makeFirstResponder:view];
-}
-
-}  // namespace internal
-
-#if !BUILDFLAG(MAC_VIEWS_BROWSER)
-bool IsViewFocused(const Browser* browser, ViewID vid) {
-  return internal::IsViewFocusedCocoa(browser, vid);
-}
-
-void ClickOnView(const Browser* browser, ViewID vid) {
-  internal::ClickOnViewCocoa(browser, vid);
-}
-
-void FocusView(const Browser* browser, ViewID vid) {
-  internal::FocusViewCocoa(browser, vid);
-}
-#endif  // !BUILDFLAG(MAC_VIEWS_BROWSER)
-
-}  // namespace ui_test_utils
diff --git a/chrome/test/base/interactive_test_utils_views.cc b/chrome/test/base/interactive_test_utils_views.cc
index 83cf211..46cbac5 100644
--- a/chrome/test/base/interactive_test_utils_views.cc
+++ b/chrome/test/base/interactive_test_utils_views.cc
@@ -9,22 +9,12 @@
 #include "build/buildflag.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views_mode_controller.h"
 #include "ui/base/ui_features.h"
 #include "ui/views/focus/focus_manager.h"
 
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-#include "chrome/test/base/interactive_test_utils_cocoa.h"
-#endif
-
 namespace ui_test_utils {
 
 bool IsViewFocused(const Browser* browser, ViewID vid) {
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-  if (views_mode_controller::IsViewsBrowserCocoa())
-    return internal::IsViewFocusedCocoa(browser, vid);
-#endif
-
   BrowserWindow* browser_window = browser->window();
   DCHECK(browser_window);
   gfx::NativeWindow window = browser_window->GetNativeWindow();
@@ -38,11 +28,6 @@
 }
 
 void ClickOnView(const Browser* browser, ViewID vid) {
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-  if (views_mode_controller::IsViewsBrowserCocoa())
-    return internal::ClickOnViewCocoa(browser, vid);
-#endif
-
   views::View* view =
       BrowserView::GetBrowserViewForBrowser(browser)->GetViewByID(vid);
   DCHECK(view);
@@ -53,11 +38,6 @@
 }
 
 void FocusView(const Browser* browser, ViewID vid) {
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-  if (views_mode_controller::IsViewsBrowserCocoa())
-    return internal::FocusViewCocoa(browser, vid);
-#endif
-
   views::View* view =
       BrowserView::GetBrowserViewForBrowser(browser)->GetViewByID(vid);
   DCHECK(view);
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py
index ee97535..93edbb92 100644
--- a/chrome/test/chromedriver/client/command_executor.py
+++ b/chrome/test/chromedriver/client/command_executor.py
@@ -4,7 +4,7 @@
 
 import httplib
 import json
-
+from urlparse import urlparse
 
 class _Method(object):
   GET = 'GET'
@@ -182,8 +182,9 @@
 class CommandExecutor(object):
   def __init__(self, server_url):
     self._server_url = server_url
-    port = int(server_url.split(':')[2].split('/')[0])
-    self._http_client = httplib.HTTPConnection('127.0.0.1', port, timeout=30)
+    parsed_url = urlparse(server_url)
+    self._http_client = httplib.HTTPConnection(
+        parsed_url.hostname, parsed_url.port, timeout=30)
 
   def Execute(self, command, params):
     url_parts = command[1].split('/')
diff --git a/chrome/test/chromedriver/net/websocket.cc b/chrome/test/chromedriver/net/websocket.cc
index aa168bb..c8f01bd 100644
--- a/chrome/test/chromedriver/net/websocket.cc
+++ b/chrome/test/chromedriver/net/websocket.cc
@@ -205,15 +205,20 @@
 }
 
 void WebSocket::Read() {
-  int code =
-      socket_->Read(read_buffer_.get(),
-                    read_buffer_->size(),
-                    base::Bind(&WebSocket::OnRead, base::Unretained(this)));
-  if (code != net::ERR_IO_PENDING)
-    OnRead(code);
+  while (true) {
+    int code = socket_->Read(
+        read_buffer_.get(), read_buffer_->size(),
+        base::Bind(&WebSocket::OnRead, base::Unretained(this), true));
+    if (code == net::ERR_IO_PENDING)
+      break;
+
+    OnRead(false, code);
+    if (state_ == CLOSED)
+      break;
+  }
 }
 
-void WebSocket::OnRead(int code) {
+void WebSocket::OnRead(bool read_again, int code) {
   if (code <= 0) {
     VLOG(4) << "WebSocket::OnRead error " << net::ErrorToShortString(code);
     Close(code ? code : net::ERR_FAILED);
@@ -225,7 +230,13 @@
   else if (state_ == OPEN)
     OnReadDuringOpen(read_buffer_->data(), code);
 
-  if (state_ != CLOSED)
+  // If we were called by the event loop due to arrival of data, call Read()
+  // again to read more data. If we were called by Read(), however, simply
+  // return to Read() and let it call socket_->Read() to read more data, and
+  // potentially call OnRead() again. This is necessary to avoid mutual
+  // recursion between Read and OnRead, which can cause stack overflow (e.g.,
+  // see https://crbug.com/877105).
+  if (read_again && state_ != CLOSED)
     Read();
 }
 
diff --git a/chrome/test/chromedriver/net/websocket.h b/chrome/test/chromedriver/net/websocket.h
index 3efa0fd1..afbc9932 100644
--- a/chrome/test/chromedriver/net/websocket.h
+++ b/chrome/test/chromedriver/net/websocket.h
@@ -53,7 +53,7 @@
   void ContinueWritingIfNecessary();
 
   void Read();
-  void OnRead(int code);
+  void OnRead(bool read_again, int code);
   void OnReadDuringHandshake(const char* data, int len);
   void OnReadDuringOpen(const char* data, int len);
 
diff --git a/chrome/test/chromedriver/server/chromedriver_server.cc b/chrome/test/chromedriver/server/chromedriver_server.cc
index 13363ee..d3dff93 100644
--- a/chrome/test/chromedriver/server/chromedriver_server.cc
+++ b/chrome/test/chromedriver/server/chromedriver_server.cc
@@ -50,7 +50,10 @@
 
 namespace {
 
-const int kBufferSize = 100 * 1024 * 1024;  // 100 MB
+// Maximum message size between app and ChromeDriver. Data larger than 150 MB
+// or so can cause crashes in Chrome (https://crbug.com/890854), so there is no
+// need to support messages that are too large.
+const int kBufferSize = 256 * 1024 * 1024;  // 256 MB
 
 typedef base::Callback<
     void(const net::HttpServerRequestInfo&, const HttpResponseSenderFunc&)>
diff --git a/chrome/test/chromedriver/server/server.py b/chrome/test/chromedriver/server/server.py
index e765890..164fc76 100644
--- a/chrome/test/chromedriver/server/server.py
+++ b/chrome/test/chromedriver/server/server.py
@@ -44,6 +44,7 @@
 
     self._process = subprocess.Popen(chromedriver_args)
     self._url = 'http://127.0.0.1:%d' % port
+    self._port = port
     if self._process is None:
       raise RuntimeError('ChromeDriver server cannot be started')
 
@@ -67,6 +68,9 @@
   def GetUrl(self):
     return self._url
 
+  def GetPort(self):
+    return self._port
+
   def IsRunning(self):
     """Returns whether the server is up and running."""
     try:
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index e02ea9c..1d914c7 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -18,6 +18,7 @@
 import os
 import re
 import shutil
+import socket
 import subprocess
 import sys
 import tempfile
@@ -28,6 +29,7 @@
 import urllib2
 import uuid
 
+
 _THIS_DIR = os.path.abspath(os.path.dirname(__file__))
 _PARENT_DIR = os.path.join(_THIS_DIR, os.pardir)
 _CLIENT_DIR = os.path.join(_PARENT_DIR, "client")
@@ -2964,6 +2966,22 @@
     self._driver.FindElement('id', 'link')
 
 
+class SupportIPv4AndIPv6(ChromeDriverBaseTest):
+  def testSupportIPv4AndIPv6(self):
+    has_ipv4 = False
+    has_ipv6 = False
+    for info in socket.getaddrinfo('localhost', 0):
+      if info[0] == socket.AF_INET:
+        has_ipv4 = True
+      if info[0] == socket.AF_INET6:
+        has_ipv6 = True
+    if has_ipv4:
+      self.CreateDriver("http://127.0.0.1:" +
+                                 str(chromedriver_server.GetPort()))
+    if has_ipv6:
+      self.CreateDriver('http://[::1]:' +
+                                 str(chromedriver_server.GetPort()))
+
 if __name__ == '__main__':
   parser = optparse.OptionParser()
   parser.add_option(
@@ -3024,6 +3042,7 @@
       options.android_package not in _ANDROID_NEGATIVE_FILTER):
     parser.error('Invalid --android-package')
 
+  global chromedriver_server
   chromedriver_server = server.Server(_CHROMEDRIVER_BINARY, options.log_path,
                                       replayable=options.replayable)
   global _CHROMEDRIVER_SERVER_URL
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 07bcfc7..6044739 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -62,7 +62,27 @@
     # Tests require multiple sessions, not supported on Android'
     'CorrectEventFiringTest.testShouldFireFocusEventInNonTopmostWindow',
     'PerformanceLoggingTest.testLogsSingleHttpCommand',
+    'PerformanceLogTypeTest.shouldBeAbleToEnablePerformanceLog',
+    'PerformanceLogTypeTest.pageLoadShouldProducePerformanceLogEntries',
     'ProxySettingTest.*',
+    'CorrectEventFiringTest.testSendingKeysToAnotherElementShouldCauseTheBlurEventToFireInNonTopmostWindow',
+    'ReferrerTest.navigationWhenProxyInterceptsASpecificUrl',
+    'ReferrerTest.crossDomainHistoryNavigationWhenProxyInterceptsHostRequests',
+    'ReferrerTest.crossDomainHistoryNavigationWithAProxiedHost',
+
+    # Tests require proxy server can't be run on Android
+    'ReferrerTest.crossDomainHistoryNavigationWithADirectProxy',
+    'ReferrerTest.basicHistoryNavigationWithADirectProxy',
+    'ReferrerTest.crossDomainHistoryNavigationWithoutAProxy',
+    'ReferrerTest.basicHistoryNavigationWithoutAProxy',
+
+    # Test with file upload not supported on Android
+    'UploadTest.testUploadingWithHiddenFileInput',
+
+    # This tests are failing because of Keys.CONTROL/SHIFT/.. are not being supported for drop down items.
+    'CombinedInputActionsTest.testControlClickingOnMultiSelectionList',
+    'CombinedInputActionsTest.testShiftClickingOnMultiSelectionList',
+    'CombinedInputActionsTest.testPlainClickingOnMultiSelectionList',
 
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2376
     'ImplicitWaitTest.testShouldImplicitlyWaitForASingleElement',
@@ -140,28 +160,14 @@
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2376
     'ImplicitWaitTest.testShouldRetainImplicitlyWaitFromTheReturnedWebDriverOfFrameSwitchTo',
 
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2480
-    'CorrectEventFiringTest.testSendingKeysToAnotherElementShouldCauseTheBlurEventToFireInNonTopmostWindow',
-    'CorrectEventFiringTest.testClickAnElementThatDisappear',
-    'ImplicitWaitTest.testShouldImplicitlyWaitForASingleElement',
-    'ReferrerTest.crossDomainHistoryNavigationWithADirectProxy',
-    'ReferrerTest.navigationWhenProxyInterceptsASpecificUrl',
-    'ReferrerTest.crossDomainHistoryNavigationWithoutAProxy',
-    'ReferrerTest.basicHistoryNavigationWithoutAProxy',
-    'ReferrerTest.basicHistoryNavigationWithADirectProxy',
-    'ReferrerTest.crossDomainHistoryNavigationWhenProxyInterceptsHostRequests',
-    'ReferrerTest.crossDomainHistoryNavigationWithAProxiedHost',
-    'UploadTest.testUploadingWithHiddenFileInput',
-    'CombinedInputActionsTest.testControlClickingOnMultiSelectionList',
-    'CombinedInputActionsTest.testShiftClickingOnMultiSelectionList',
-    'CombinedInputActionsTest.testPlainClickingOnMultiSelectionList',
-    'CorrectEventFiringTest.testClickingAnUnfocusableChildShouldNotBlurTheParent',
-
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2594
     'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePage',
     'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePageAfterSwitching',
     'TakesScreenshotTest.testShouldCaptureScreenshotAtIFramePageAfterSwitching',
     'TakesScreenshotTest.testShouldCaptureScreenshotOfCurrentViewport',
+
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2601
+    'BasicKeyboardInterfaceTest.testSelectionSelectBySymbol',
 ]
 
 _OS_NEGATIVE_FILTER['android:chrome_stable'] = (
diff --git a/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/icon_128.png b/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/icon_128.png
new file mode 100644
index 0000000..d62e688
--- /dev/null
+++ b/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/icon_128.png
Binary files differ
diff --git a/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html b/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html
new file mode 100644
index 0000000..18ecdcb
--- /dev/null
+++ b/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/main.html
@@ -0,0 +1 @@
+<html></html>
diff --git a/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json b/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json
new file mode 100644
index 0000000..9aa3db597
--- /dev/null
+++ b/chrome/test/data/extensions/app_list_oem/Extensions/emfkafnhnpcmabnnkckkchdilgeoekbo/1.0/manifest.json
@@ -0,0 +1,14 @@
+{
+  "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCxUatX2sx1yjeTAnu8ydtVhdD/JPn2wrmK7rX1Qko7FY4BRA733YPuY7JTWdKDbNU4OKaJOjexkz3klsj0vvTwRJgNghSgYePTPHZfWtRzy7WVG3KOQX2IgNMuOMWE/r5Eyg84Zi+0vLIcTzaqdAOcFwGYhp0/jRvDWDRpoQLKld6p58c/kORJ4sZrZMnp22OSz0rrLZseDEH+4ZJt0GWPUwzlKKLAsC8WthW5ntNjzkjxJSpRrM+WF7nr/dmYUX3791rRia7rtJFNx66AZroZ3PT7H1uOkr7f5vQyZbQrtMfmoxUtuu0yGGJS3JPw9i+0Pg7iHUQkRYUG/dNVYh//",
+  "version": "1.0",
+  "name": "Packaged App 1",
+  "manifest_version": 2,
+  "icons": {
+    "128": "icon_128.png"
+  },
+  "app": {
+    "launch": {
+      "local_path": "main.html"
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/app_list_oem/Preferences b/chrome/test/data/extensions/app_list_oem/Preferences
new file mode 100644
index 0000000..9a49574a
--- /dev/null
+++ b/chrome/test/data/extensions/app_list_oem/Preferences
@@ -0,0 +1,28 @@
+{
+   "extensions": {
+      "settings": {
+         "emfkafnhnpcmabnnkckkchdilgeoekbo": {
+            "location": 1,
+            "path": "emfkafnhnpcmabnnkckkchdilgeoekbo/1.0",
+            "app_launcher_ordinal": "n",
+            "page_ordinal": "n",
+            "state": 1,
+            "install_time": "12968795380420751",
+            "creation_flags": 1032,
+            "manifest": {
+              "key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQCxUatX2sx1yjeTAnu8ydtVhdD/JPn2wrmK7rX1Qko7FY4BRA733YPuY7JTWdKDbNU4OKaJOjexkz3klsj0vvTwRJgNghSgYePTPHZfWtRzy7WVG3KOQX2IgNMuOMWE/r5Eyg84Zi+0vLIcTzaqdAOcFwGYhp0/jRvDWDRpoQLKld6p58c/kORJ4sZrZMnp22OSz0rrLZseDEH+4ZJt0GWPUwzlKKLAsC8WthW5ntNjzkjxJSpRrM+WF7nr/dmYUX3791rRia7rtJFNx66AZroZ3PT7H1uOkr7f5vQyZbQrtMfmoxUtuu0yGGJS3JPw9i+0Pg7iHUQkRYUG/dNVYh//",
+              "version": "1.0",
+              "name": "Packaged App 1",
+              "icons": {
+                "128": "icon_128.png"
+              },
+              "app": {
+                "launch": {
+                  "local_path": "main.html"
+                }
+              }
+            }
+         }
+      }
+   }
+}
diff --git a/chrome/test/data/extensions/theme/Cached Theme.pak b/chrome/test/data/extensions/theme/Cached Theme.pak
index 0fd05fbd..0f8374e 100644
--- a/chrome/test/data/extensions/theme/Cached Theme.pak
+++ b/chrome/test/data/extensions/theme/Cached Theme.pak
Binary files differ
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 5fe83e0..202c069b 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -4044,5 +4044,14 @@
     "pref_mappings": [
       { "pref": "enterprise_reporting.report_user_id_data" }
     ]
+  },
+
+  "VpnConfigAllowed": {
+    "os": ["chromeos"],
+    "can_be_recommended": false,
+    "test_policy": { "VpnConfigAllowed": false },
+    "pref_mappings": [
+      { "pref": "vpn_config_allowed" }
+    ]
   }
 }
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
index d5e6f8c..a809586 100644
--- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
+++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
@@ -39,37 +39,64 @@
 std::unique_ptr<AndroidSmsAppInstallingStatusObserver>
 AndroidSmsAppInstallingStatusObserver::Factory::BuildInstance(
     HostStatusProvider* host_status_provider,
+    FeatureStateManager* feature_state_manager,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate) {
   return base::WrapUnique(new AndroidSmsAppInstallingStatusObserver(
-      host_status_provider, std::move(android_sms_app_helper_delegate)));
+      host_status_provider, feature_state_manager,
+      std::move(android_sms_app_helper_delegate)));
 }
 
 AndroidSmsAppInstallingStatusObserver::
     ~AndroidSmsAppInstallingStatusObserver() {
   host_status_provider_->RemoveObserver(this);
+  feature_state_manager_->RemoveObserver(this);
 }
 
 AndroidSmsAppInstallingStatusObserver::AndroidSmsAppInstallingStatusObserver(
     HostStatusProvider* host_status_provider,
+    FeatureStateManager* feature_state_manager,
     std::unique_ptr<AndroidSmsAppHelperDelegate>
         android_sms_app_helper_delegate)
     : host_status_provider_(host_status_provider),
+      feature_state_manager_(feature_state_manager),
       android_sms_app_helper_delegate_(
           std::move(android_sms_app_helper_delegate)) {
   host_status_provider_->AddObserver(this);
+  feature_state_manager_->AddObserver(this);
+  InstallPwaIfNeeded();
+}
+
+void AndroidSmsAppInstallingStatusObserver::InstallPwaIfNeeded() {
+  mojom::FeatureState feature_state =
+      feature_state_manager_->GetFeatureStates()[mojom::Feature::kMessages];
+  if (feature_state == mojom::FeatureState::kProhibitedByPolicy ||
+      feature_state == mojom::FeatureState::kNotSupportedByChromebook ||
+      feature_state == mojom::FeatureState::kNotSupportedByPhone) {
+    return;
+  }
+
+  mojom::HostStatus status(
+      host_status_provider_->GetHostWithStatus().host_status());
+  if (status !=
+          mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation &&
+      status != mojom::HostStatus::kHostVerified) {
+    return;
+  }
+
+  // This call is re-entrant. If the app is already installed, it will just
+  // fail silently, which is fine.
+  android_sms_app_helper_delegate_->InstallAndroidSmsApp();
 }
 
 void AndroidSmsAppInstallingStatusObserver::OnHostStatusChange(
     const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
-  mojom::HostStatus status(host_status_with_device.host_status());
-  if (status ==
-          mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation ||
-      status == mojom::HostStatus::kHostVerified) {
-    // This call is re-entrant. If the app is already installed, it will just
-    // fail silently, which is fine.
-    android_sms_app_helper_delegate_->InstallAndroidSmsApp();
-  }
+  InstallPwaIfNeeded();
+}
+
+void AndroidSmsAppInstallingStatusObserver::OnFeatureStatesChange(
+    const FeatureStateManager::FeatureStatesMap& feature_states_map) {
+  InstallPwaIfNeeded();
 }
 
 }  // namespace multidevice_setup
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h
index b0f35e6..6b3953b 100644
--- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h
+++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "chromeos/services/multidevice_setup/feature_state_manager.h"
 #include "chromeos/services/multidevice_setup/host_status_provider.h"
 
 namespace chromeos {
@@ -17,11 +18,9 @@
 
 // Listens for status changes in multidevice state and installs the Android
 // Messages PWA if needed.
-//
-// TODO(crbug.com/884290): Also observe FeatureStateManager to make sure
-// Messages is supported.
 class AndroidSmsAppInstallingStatusObserver
-    : public HostStatusProvider::Observer {
+    : public HostStatusProvider::Observer,
+      public FeatureStateManager::Observer {
  public:
   class Factory {
    public:
@@ -30,6 +29,7 @@
     virtual ~Factory();
     virtual std::unique_ptr<AndroidSmsAppInstallingStatusObserver>
     BuildInstance(HostStatusProvider* host_status_provider,
+                  FeatureStateManager* feature_state_manager,
                   std::unique_ptr<AndroidSmsAppHelperDelegate>
                       android_sms_app_helper_delegate);
 
@@ -42,6 +42,7 @@
  private:
   AndroidSmsAppInstallingStatusObserver(
       HostStatusProvider* host_status_provider,
+      FeatureStateManager* feature_state_manager,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate);
 
@@ -49,7 +50,14 @@
   void OnHostStatusChange(const HostStatusProvider::HostStatusWithDevice&
                               host_status_with_device) override;
 
+  // FeatureStateManager:;Observer:
+  void OnFeatureStatesChange(
+      const FeatureStateManager::FeatureStatesMap& feature_states_map) override;
+
+  void InstallPwaIfNeeded();
+
   HostStatusProvider* host_status_provider_;
+  FeatureStateManager* feature_state_manager_;
   std::unique_ptr<AndroidSmsAppHelperDelegate> android_sms_app_helper_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AndroidSmsAppInstallingStatusObserver);
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc
index a443f31c..fbf4593 100644
--- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc
+++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "chromeos/services/multidevice_setup/fake_feature_state_manager.h"
 #include "chromeos/services/multidevice_setup/fake_host_status_provider.h"
 #include "chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.h"
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
@@ -37,11 +38,15 @@
     fake_android_sms_app_helper_delegate_ =
         fake_android_sms_app_helper_delegate.get();
     fake_host_status_provider_ = std::make_unique<FakeHostStatusProvider>();
+    fake_feature_state_manager_ = std::make_unique<FakeFeatureStateManager>();
     android_sms_app_installing_status_observer_ =
         AndroidSmsAppInstallingStatusObserver::Factory::Get()->BuildInstance(
-            fake_host_status_provider_.get(),
+            fake_host_status_provider_.get(), fake_feature_state_manager_.get(),
             std::move(fake_android_sms_app_helper_delegate));
 
+    SetMessagesFeatureState(mojom::FeatureState::kEnabledByUser);
+    SetHostWithStatus(mojom::HostStatus::kHostVerified, GetFakePhone());
+    fake_app_helper_delegate()->Reset();
     EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
   }
 
@@ -62,8 +67,14 @@
         .Build();
   }
 
+  void SetMessagesFeatureState(mojom::FeatureState feature_state) {
+    fake_feature_state_manager_->SetFeatureState(mojom::Feature::kMessages,
+                                                 feature_state);
+  }
+
  private:
   std::unique_ptr<FakeHostStatusProvider> fake_host_status_provider_;
+  std::unique_ptr<FakeFeatureStateManager> fake_feature_state_manager_;
   FakeAndroidSmsAppHelperDelegate* fake_android_sms_app_helper_delegate_;
 
   std::unique_ptr<AndroidSmsAppInstallingStatusObserver>
@@ -75,6 +86,10 @@
 
 TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
        InstallsAfterHostPending) {
+  SetMessagesFeatureState(mojom::FeatureState::kUnavailableNoVerifiedHost);
+  fake_app_helper_delegate()->Reset();
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
   SetHostWithStatus(mojom::HostStatus::kEligibleHostExistsButNoHostSet,
                     base::nullopt /* host_device */);
   EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
@@ -94,6 +109,73 @@
   SetHostWithStatus(mojom::HostStatus::kHostVerified, GetFakePhone());
   EXPECT_TRUE(fake_app_helper_delegate()->HasInstalledApp());
 }
+
+TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
+       DoesNotInstallsAfterHostVerifiedIfNotAllowed) {
+  SetMessagesFeatureState(mojom::FeatureState::kProhibitedByPolicy);
+  fake_app_helper_delegate()->Reset();
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
+  SetHostWithStatus(mojom::HostStatus::kNoEligibleHosts,
+                    base::nullopt /* host_device */);
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, GetFakePhone());
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+}
+
+TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
+       DoesNotInstallsAfterHostVerifiedIfNotSupportedByPhone) {
+  SetMessagesFeatureState(mojom::FeatureState::kNotSupportedByPhone);
+  fake_app_helper_delegate()->Reset();
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
+  SetHostWithStatus(mojom::HostStatus::kNoEligibleHosts,
+                    base::nullopt /* host_device */);
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, GetFakePhone());
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+}
+
+TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
+       DoesNotInstallsAfterHostVerifiedIfNotSupportedByChromebook) {
+  SetMessagesFeatureState(mojom::FeatureState::kNotSupportedByChromebook);
+  fake_app_helper_delegate()->Reset();
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
+  SetHostWithStatus(mojom::HostStatus::kNoEligibleHosts,
+                    base::nullopt /* host_device */);
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+
+  SetHostWithStatus(mojom::HostStatus::kHostVerified, GetFakePhone());
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+}
+
+TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
+       InstallsWhenFeatureBecomesEnabled) {
+  SetMessagesFeatureState(mojom::FeatureState::kNotSupportedByChromebook);
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+  SetMessagesFeatureState(mojom::FeatureState::kEnabledByUser);
+  EXPECT_TRUE(fake_app_helper_delegate()->HasInstalledApp());
+}
+
+TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
+       InstallsEvenIfFeatureIsDisabledByUser) {
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+  SetMessagesFeatureState(mojom::FeatureState::kDisabledByUser);
+  EXPECT_TRUE(fake_app_helper_delegate()->HasInstalledApp());
+}
+
+TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest,
+       DoesNotInstallIfNotVerified) {
+  SetHostWithStatus(mojom::HostStatus::kNoEligibleHosts,
+                    base::nullopt /* host_device */);
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+  SetMessagesFeatureState(mojom::FeatureState::kUnavailableNoVerifiedHost);
+  EXPECT_FALSE(fake_app_helper_delegate()->HasInstalledApp());
+}
+
 }  // namespace multidevice_setup
 
 }  // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
index 4cb15e5f..5ae1536 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl.cc
@@ -115,6 +115,7 @@
       android_sms_app_installing_host_observer_(
           AndroidSmsAppInstallingStatusObserver::Factory::Get()->BuildInstance(
               host_status_provider_.get(),
+              feature_state_manager_.get(),
               std::move(android_sms_app_helper_delegate))),
       auth_token_validator_(auth_token_validator) {
   host_status_provider_->AddObserver(this);
diff --git a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
index f6efaff..0ed77072 100644
--- a/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
+++ b/chromeos/services/multidevice_setup/multidevice_setup_impl_unittest.cc
@@ -398,8 +398,10 @@
  public:
   FakeAndroidSmsAppInstallingStatusObserverFactory(
       FakeHostStatusProviderFactory* fake_host_status_provider_factory,
+      FakeFeatureStateManagerFactory* fake_feature_state_manager_factory,
       AndroidSmsAppHelperDelegate* expected_android_sms_app_helper_delegate)
       : fake_host_status_provider_factory_(fake_host_status_provider_factory),
+        fake_feature_state_manager_factory_(fake_feature_state_manager_factory),
         expected_android_sms_app_helper_delegate_(
             expected_android_sms_app_helper_delegate) {}
 
@@ -409,10 +411,13 @@
   // AndroidSmsAppInstallingStatusObserver::Factory:
   std::unique_ptr<AndroidSmsAppInstallingStatusObserver> BuildInstance(
       HostStatusProvider* host_status_provider,
+      FeatureStateManager* feature_state_manager,
       std::unique_ptr<AndroidSmsAppHelperDelegate>
           android_sms_app_helper_delegate) override {
     EXPECT_EQ(fake_host_status_provider_factory_->instance(),
               host_status_provider);
+    EXPECT_EQ(fake_feature_state_manager_factory_->instance(),
+              feature_state_manager);
     EXPECT_EQ(expected_android_sms_app_helper_delegate_,
               android_sms_app_helper_delegate.get());
     // Only check inputs and return nullptr. We do not want to trigger the
@@ -421,6 +426,7 @@
   }
 
   FakeHostStatusProviderFactory* fake_host_status_provider_factory_;
+  FakeFeatureStateManagerFactory* fake_feature_state_manager_factory_;
   AndroidSmsAppHelperDelegate* expected_android_sms_app_helper_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAndroidSmsAppInstallingStatusObserverFactory);
@@ -514,6 +520,7 @@
     fake_android_sms_app_installing_status_observer_factory_ =
         std::make_unique<FakeAndroidSmsAppInstallingStatusObserverFactory>(
             fake_host_status_provider_factory_.get(),
+            fake_feature_state_manager_factory_.get(),
             fake_android_sms_app_helper_delegate.get());
     AndroidSmsAppInstallingStatusObserver::Factory::SetFactoryForTesting(
         fake_android_sms_app_installing_status_observer_factory_.get());
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 205bc9d2..714b7a0 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -128,7 +128,6 @@
     "//components/os_crypt:unit_tests",
     "//components/password_manager/core/browser:unit_tests",
     "//components/password_manager/core/common:unit_tests",
-    "//components/password_manager/sync/browser:unit_tests",
     "//components/payments/core:unit_tests",
     "//components/prefs:unit_tests",
     "//components/previews/core:unit_tests",
diff --git a/components/arc/DEPS b/components/arc/DEPS
index 3839f7c..6d3d233 100644
--- a/components/arc/DEPS
+++ b/components/arc/DEPS
@@ -17,6 +17,7 @@
   "+storage/browser/fileapi",
   "+third_party/re2",
   "+third_party/skia",
+  "+ui/base/ime",
   "+ui/gfx/geometry",
   "+ui/gfx/range/range.h",
 ]
diff --git a/components/arc/common/BUILD.gn b/components/arc/common/BUILD.gn
index 50fb833..ed76eb0 100644
--- a/components/arc/common/BUILD.gn
+++ b/components/arc/common/BUILD.gn
@@ -100,4 +100,15 @@
       "//ui/gfx/geometry/mojo",
     ]
   }
+
+  source_set("struct_traits") {
+    sources = [
+      "ime_struct_traits.h",
+    ]
+
+    deps = [
+      ":common",
+      "//ui/base/ime:text_input_types",
+    ]
+  }
 }
diff --git a/components/arc/common/ime.typemap b/components/arc/common/ime.typemap
new file mode 100644
index 0000000..ba967cf
--- /dev/null
+++ b/components/arc/common/ime.typemap
@@ -0,0 +1,4 @@
+mojom = "//components/arc/common/ime.mojom"
+public_headers = [ "//ui/base/ime/text_input_type.h" ]
+traits_headers = [ "//components/arc/common/ime_struct_traits.h" ]
+type_mappings = [ "arc.mojom.TextInputType=ui::TextInputType" ]
diff --git a/components/arc/common/ime_struct_traits.h b/components/arc/common/ime_struct_traits.h
new file mode 100644
index 0000000..c366cff
--- /dev/null
+++ b/components/arc/common/ime_struct_traits.h
@@ -0,0 +1,110 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ARC_COMMON_IME_STRUCT_TRAITS_H_
+#define COMPONENTS_ARC_COMMON_IME_STRUCT_TRAITS_H_
+
+#include "components/arc/common/ime.mojom-shared.h"
+#include "ui/base/ime/text_input_type.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<arc::mojom::TextInputType, ui::TextInputType> {
+  using MojoType = arc::mojom::TextInputType;
+
+  // The two enum types are similar, but intentionally made not identical.
+  // We cannot force them to be in sync. If we do, updates in ui::TextInputType
+  // must always be propagated to the mojom::TextInputType mojo definition in
+  // ARC container side, which is in a different repository than Chromium.
+  // We don't want such dependency.
+  //
+  // That's why we need a lengthy switch statement instead of static_cast
+  // guarded by a static assert on the two enums to be in sync.
+
+  static MojoType ToMojom(ui::TextInputType input) {
+    switch (input) {
+      case ui::TEXT_INPUT_TYPE_NONE:
+        return MojoType::NONE;
+      case ui::TEXT_INPUT_TYPE_TEXT:
+        return MojoType::TEXT;
+      case ui::TEXT_INPUT_TYPE_PASSWORD:
+        return MojoType::PASSWORD;
+      case ui::TEXT_INPUT_TYPE_SEARCH:
+        return MojoType::SEARCH;
+      case ui::TEXT_INPUT_TYPE_EMAIL:
+        return MojoType::EMAIL;
+      case ui::TEXT_INPUT_TYPE_NUMBER:
+        return MojoType::NUMBER;
+      case ui::TEXT_INPUT_TYPE_TELEPHONE:
+        return MojoType::TELEPHONE;
+      case ui::TEXT_INPUT_TYPE_URL:
+        return MojoType::URL;
+      case ui::TEXT_INPUT_TYPE_DATE:
+        return MojoType::DATE;
+      case ui::TEXT_INPUT_TYPE_DATE_TIME:
+        return MojoType::DATETIME;
+      case ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL:
+        return MojoType::DATETIME;
+      case ui::TEXT_INPUT_TYPE_MONTH:
+        return MojoType::DATE;
+      case ui::TEXT_INPUT_TYPE_TIME:
+        return MojoType::TIME;
+      case ui::TEXT_INPUT_TYPE_WEEK:
+        return MojoType::DATE;
+      case ui::TEXT_INPUT_TYPE_TEXT_AREA:
+        return MojoType::TEXT;
+      case ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE:
+        return MojoType::TEXT;
+      case ui::TEXT_INPUT_TYPE_DATE_TIME_FIELD:
+        return MojoType::DATETIME;
+    }
+    NOTREACHED();
+    return MojoType::TEXT;
+  }
+
+  static bool FromMojom(MojoType input, ui::TextInputType* out) {
+    switch (input) {
+      case MojoType::NONE:
+        *out = ui::TEXT_INPUT_TYPE_NONE;
+        return true;
+      case MojoType::TEXT:
+        *out = ui::TEXT_INPUT_TYPE_TEXT;
+        return true;
+      case MojoType::PASSWORD:
+        *out = ui::TEXT_INPUT_TYPE_PASSWORD;
+        return true;
+      case MojoType::SEARCH:
+        *out = ui::TEXT_INPUT_TYPE_SEARCH;
+        return true;
+      case MojoType::EMAIL:
+        *out = ui::TEXT_INPUT_TYPE_EMAIL;
+        return true;
+      case MojoType::NUMBER:
+        *out = ui::TEXT_INPUT_TYPE_NUMBER;
+        return true;
+      case MojoType::TELEPHONE:
+        *out = ui::TEXT_INPUT_TYPE_TELEPHONE;
+        return true;
+      case MojoType::URL:
+        *out = ui::TEXT_INPUT_TYPE_URL;
+        return true;
+      case MojoType::DATE:
+        *out = ui::TEXT_INPUT_TYPE_DATE;
+        return true;
+      case MojoType::TIME:
+        *out = ui::TEXT_INPUT_TYPE_TIME;
+        return true;
+      case MojoType::DATETIME:
+        *out = ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL;
+        return true;
+    }
+    NOTREACHED();
+    return false;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // COMPONENTS_ARC_COMMON_IME_STRUCT_TRAITS_H_
diff --git a/components/arc/common/input_method_manager.mojom b/components/arc/common/input_method_manager.mojom
index f9afe1d..9ad57e58 100644
--- a/components/arc/common/input_method_manager.mojom
+++ b/components/arc/common/input_method_manager.mojom
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 2
+// Next MinVersion: 3
 
 module arc.mojom;
 
+import "mojo/public/mojom/base/string16.mojom";
+import "components/arc/common/gfx.mojom";
+import "components/arc/common/ime.mojom";
+
 // Represents the information of an Android IME.
 struct ImeInfo {
   // The unique ID for the Android IME. Corresponds to InputMethodInfo.getId().
@@ -20,6 +24,63 @@
   string settings_url;
 };
 
+// Represents the information of the text field.
+[MinVersion=2]
+struct TextInputState {
+  // The current cursor position in 16-bit code units in the overall text
+  // of the text field.
+  int32 cursor_pos;
+  // A part of the text in the text field. The text is in UTF-8,
+  // but should be converted to UTF-16 in both ends of mojo call.
+  mojo_base.mojom.String16 text;
+  // The range of |text| in 16-bit code units index in the overall text
+  // of the text field.
+  Range text_range;
+  // The range of the selected text in 16-bit code units index
+  // in the overall text of the text field.
+  Range selection_range;
+  // The type of the text field.
+  TextInputType type;
+  // Indicates that IMEs should do personalized learning based on the contents.
+  bool should_do_learning;
+  // The other text input flags. For example auto-capitalization flag
+  // and auto-correction flag are included in this flag.
+  // These values are from ui::TextInputFlags in ui/base/ime/text_input_flags.h
+  uint32 flags;
+  // Whether this state update is sent as a first update after an operation
+  // by Android IMEs.
+  // Android IMEs need this flag to know the latest state after their operation
+  // becomes effective.
+  bool first_update_after_operation;
+};
+
+// This interface provides methods to control a text field.
+// It is generated for each focused text field and passed to Android.
+// This interface will be closed when the focus moves to another text field.
+//
+// Next method ID: 5
+[MinVersion=2]
+interface InputConnection {
+  // Commits text to the focused text field and set the new cursor position.
+  CommitText@0(mojo_base.mojom.String16 text, int32 new_cursor_pos);
+
+  // Deletes |before| characters of text before the cursor position,
+  // and deletes |after| characters of text after the cursor position.
+  DeleteSurroundingText@1(int32 before, int32 after);
+
+  // Has the text field finish the ongoing composition.
+  FinishComposingText@2();
+
+  // Requests to send the latest TextInputState of the active text field.
+  // For example, this is called when the IME calls getTextBeforeCursor()
+  // and getTextAfterCursor().
+  RequestTextInputState@3() => (TextInputState state);
+
+  // Replaces the currently composing text with the given text,
+  // and sets the cursor position.
+  SetComposingText@4(mojo_base.mojom.String16 text, int32 new_cursor_pos);
+};
+
 // This interface is called by container when Android's InputMethodManager state
 // is changed.
 // In Android container, ArcInputMethodService IME is pre-installed to bridge
@@ -41,7 +102,7 @@
 
 // This interface provides methods to control Android's InputMethodManager.
 //
-// Next method ID: 3
+// Next method ID: 5
 interface InputMethodManagerInstance {
   // Establishes full-duplex communication with the host.
   Init@0(InputMethodManagerHost host_ptr) => ();
@@ -52,4 +113,12 @@
 
   // Switches active IME in Android.
   SwitchImeTo@2(string ime_id) => (bool success);
+
+  // Notifies Android's ArcInputMethodManagerService that
+  // a text field is focused.
+  [MinVersion=2] Focus@3(InputConnection connection,
+                         TextInputState initial_state);
+
+  // Sends the latest TextInputState of the active text field.
+  [MinVersion=2] UpdateTextInputState@4(TextInputState state);
 };
diff --git a/components/arc/common/typemaps.gni b/components/arc/common/typemaps.gni
index 5dd1b81f..7756be68 100644
--- a/components/arc/common/typemaps.gni
+++ b/components/arc/common/typemaps.gni
@@ -8,6 +8,7 @@
   "//components/arc/common/bluetooth.typemap",
   "//components/arc/common/file_system.typemap",
   "//components/arc/common/gfx.typemap",
+  "//components/arc/common/ime.typemap",
   "//components/arc/common/intent_helper.typemap",
   "//components/arc/common/print.typemap",
   "//components/arc/common/timer.typemap",
diff --git a/components/arc/disk_quota/OWNERS b/components/arc/disk_quota/OWNERS
new file mode 100644
index 0000000..e1627725
--- /dev/null
+++ b/components/arc/disk_quota/OWNERS
@@ -0,0 +1 @@
+hashimoto@chromium.org
diff --git a/components/arc/ime/arc_ime_bridge_impl.cc b/components/arc/ime/arc_ime_bridge_impl.cc
index 626d17332..212e341 100644
--- a/components/arc/ime/arc_ime_bridge_impl.cc
+++ b/components/arc/ime/arc_ime_bridge_impl.cc
@@ -19,43 +19,6 @@
 namespace arc {
 namespace {
 
-ui::TextInputType ConvertTextInputType(mojom::TextInputType ipc_type) {
-  // The two enum types are similar, but intentionally made not identical.
-  // We cannot force them to be in sync. If we do, updates in ui::TextInputType
-  // must always be propagated to the mojom::TextInputType mojo definition in
-  // ARC container side, which is in a different repository than Chromium.
-  // We don't want such dependency.
-  //
-  // That's why we need a lengthy switch statement instead of static_cast
-  // guarded by a static assert on the two enums to be in sync.
-  switch (ipc_type) {
-    case mojom::TextInputType::NONE:
-      return ui::TEXT_INPUT_TYPE_NONE;
-    case mojom::TextInputType::TEXT:
-      return ui::TEXT_INPUT_TYPE_TEXT;
-    case mojom::TextInputType::PASSWORD:
-      return ui::TEXT_INPUT_TYPE_PASSWORD;
-    case mojom::TextInputType::SEARCH:
-      return ui::TEXT_INPUT_TYPE_SEARCH;
-    case mojom::TextInputType::EMAIL:
-      return ui::TEXT_INPUT_TYPE_EMAIL;
-    case mojom::TextInputType::NUMBER:
-      return ui::TEXT_INPUT_TYPE_NUMBER;
-    case mojom::TextInputType::TELEPHONE:
-      return ui::TEXT_INPUT_TYPE_TELEPHONE;
-    case mojom::TextInputType::URL:
-      return ui::TEXT_INPUT_TYPE_URL;
-    case mojom::TextInputType::DATE:
-      return ui::TEXT_INPUT_TYPE_DATE;
-    case mojom::TextInputType::TIME:
-      return ui::TEXT_INPUT_TYPE_TIME;
-    case mojom::TextInputType::DATETIME:
-      return ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL;
-    default:
-      return ui::TEXT_INPUT_TYPE_TEXT;
-  }
-}
-
 std::vector<mojom::CompositionSegmentPtr> ConvertSegments(
     const ui::CompositionText& composition) {
   std::vector<mojom::CompositionSegmentPtr> segments;
@@ -135,10 +98,9 @@
 }
 
 void ArcImeBridgeImpl::OnTextInputTypeChanged(
-    mojom::TextInputType type,
+    ui::TextInputType type,
     bool is_personalized_learning_allowed) {
-  delegate_->OnTextInputTypeChanged(ConvertTextInputType(type),
-                                    is_personalized_learning_allowed);
+  delegate_->OnTextInputTypeChanged(type, is_personalized_learning_allowed);
 }
 
 void ArcImeBridgeImpl::OnCursorRectChanged(const gfx::Rect& rect,
diff --git a/components/arc/ime/arc_ime_bridge_impl.h b/components/arc/ime/arc_ime_bridge_impl.h
index 48904d312..b2670fcf 100644
--- a/components/arc/ime/arc_ime_bridge_impl.h
+++ b/components/arc/ime/arc_ime_bridge_impl.h
@@ -38,7 +38,7 @@
                                         bool is_available) override;
 
   // mojom::ImeHost overrides:
-  void OnTextInputTypeChanged(mojom::TextInputType type,
+  void OnTextInputTypeChanged(ui::TextInputType type,
                               bool is_personalized_learning_allowed) override;
   void OnCursorRectChanged(const gfx::Rect& rect,
                            bool screen_coordinates) override;
diff --git a/components/arc/obb_mounter/OWNERS b/components/arc/obb_mounter/OWNERS
new file mode 100644
index 0000000..e1627725
--- /dev/null
+++ b/components/arc/obb_mounter/OWNERS
@@ -0,0 +1 @@
+hashimoto@chromium.org
diff --git a/components/arc/storage_manager/OWNERS b/components/arc/storage_manager/OWNERS
new file mode 100644
index 0000000..e1627725
--- /dev/null
+++ b/components/arc/storage_manager/OWNERS
@@ -0,0 +1 @@
+hashimoto@chromium.org
diff --git a/components/arc/volume_mounter/OWNERS b/components/arc/volume_mounter/OWNERS
index ef5cf84..be9c82a 100644
--- a/components/arc/volume_mounter/OWNERS
+++ b/components/arc/volume_mounter/OWNERS
@@ -1,3 +1,5 @@
+hashimoto@chromium.org
+
 per-file *_struct_traits*.*=set noparent
 per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
 per-file *_struct_traits*.*=file://components/arc/common/ARC_SECURITY_OWNERS
diff --git a/components/autofill_assistant/browser/client.h b/components/autofill_assistant/browser/client.h
index 3d68e14..6e1ab50e 100644
--- a/components/autofill_assistant/browser/client.h
+++ b/components/autofill_assistant/browser/client.h
@@ -19,6 +19,9 @@
   // Returns the API key to be used for requests to the backend.
   virtual std::string GetApiKey() = 0;
 
+  // Returns the server URL to be used for requests to the backend.
+  virtual std::string GetServerUrl() = 0;
+
   // Returns a UiController.
   virtual UiController* GetUiController() = 0;
 
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index c7432cc..1e554b0c 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -10,6 +10,7 @@
 #include "components/autofill_assistant/browser/ui_controller.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "url/gurl.h"
 
 namespace autofill_assistant {
 // static
@@ -19,11 +20,13 @@
     std::unique_ptr<std::map<std::string, std::string>> parameters) {
   // Get the key early since |client| will be invalidated when moved below.
   const std::string api_key = client->GetApiKey();
-  new Controller(
-      web_contents, std::move(client),
-      WebController::CreateForWebContents(web_contents),
-      std::make_unique<Service>(api_key, web_contents->GetBrowserContext()),
-      std::move(parameters));
+  GURL server_url(client->GetServerUrl());
+  DCHECK(server_url.is_valid());
+  new Controller(web_contents, std::move(client),
+                 WebController::CreateForWebContents(web_contents),
+                 std::make_unique<Service>(api_key, server_url,
+                                           web_contents->GetBrowserContext()),
+                 std::move(parameters));
 }
 
 Service* Controller::GetService() {
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index b6e0b1f..77359f4f 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -40,7 +40,7 @@
 
   // Implements Client
   std::string GetApiKey() override { return ""; }
-
+  std::string GetServerUrl() override { return ""; }
   UiController* GetUiController() override { return ui_controller_.get(); }
 
  private:
diff --git a/components/autofill_assistant/browser/mock_service.cc b/components/autofill_assistant/browser/mock_service.cc
index f5daf325..9684c1b 100644
--- a/components/autofill_assistant/browser/mock_service.cc
+++ b/components/autofill_assistant/browser/mock_service.cc
@@ -4,9 +4,11 @@
 
 #include "components/autofill_assistant/browser/mock_service.h"
 
+#include "url/gurl.h"
+
 namespace autofill_assistant {
 
-MockService::MockService() : Service("api_key", nullptr) {}
+MockService::MockService() : Service("api_key", GURL("http://fake"), nullptr) {}
 MockService::~MockService() {}
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.cc b/components/autofill_assistant/browser/service.cc
index f723c13e4..573f270 100644
--- a/components/autofill_assistant/browser/service.cc
+++ b/components/autofill_assistant/browser/service.cc
@@ -8,7 +8,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/command_line.h"
 #include "base/strings/strcat.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "content/public/browser/browser_context.h"
@@ -20,7 +19,6 @@
 
 namespace {
 // TODO(crbug.com/806868): Provide correct server and endpoint.
-const char* const kAutofillAssistantServer = "";
 const char* const kScriptEndpoint = "/v1/supportsSite2";
 const char* const kActionEndpoint = "/v1/actions2";
 
@@ -46,37 +44,22 @@
 
 namespace autofill_assistant {
 
-namespace switches {
-const char* const kAutofillAssistantServerURL = "autofill-assistant-url";
-}  // namespace switches
-
-Service::Service(const std::string& api_key, content::BrowserContext* context)
+Service::Service(const std::string& api_key,
+                 const GURL& server_url,
+                 content::BrowserContext* context)
     : context_(context) {
-  const auto* command_line = base::CommandLine::ForCurrentProcess();
-  GURL service_url(kAutofillAssistantServer);
-  if (command_line->HasSwitch(switches::kAutofillAssistantServerURL)) {
-    GURL custom_url(command_line->GetSwitchValueASCII(
-        switches::kAutofillAssistantServerURL));
-    if (custom_url.is_valid()) {
-      service_url = custom_url;
-    } else {
-      LOG(WARNING) << "The following autofill assisstant URL specified in "
-                      "the command line is invalid: "
-                   << custom_url;
-    }
-  }
+  DCHECK(server_url.is_valid());
 
   std::string api_key_query = base::StrCat({"key=", api_key});
   url::StringPieceReplacements<std::string> script_replacements;
   script_replacements.SetPathStr(kScriptEndpoint);
   script_replacements.SetQueryStr(api_key_query);
-  script_server_url_ = service_url.ReplaceComponents(script_replacements);
+  script_server_url_ = server_url.ReplaceComponents(script_replacements);
 
   url::StringPieceReplacements<std::string> action_replacements;
   action_replacements.SetPathStr(kActionEndpoint);
   action_replacements.SetQueryStr(api_key_query);
-  script_action_server_url_ =
-      service_url.ReplaceComponents(action_replacements);
+  script_action_server_url_ = server_url.ReplaceComponents(action_replacements);
 }
 
 Service::~Service() {}
diff --git a/components/autofill_assistant/browser/service.h b/components/autofill_assistant/browser/service.h
index e2a12f2..a52d9e5 100644
--- a/components/autofill_assistant/browser/service.h
+++ b/components/autofill_assistant/browser/service.h
@@ -24,8 +24,9 @@
 // client actions.
 class Service {
  public:
-  explicit Service(const std::string& api_key,
-                   content::BrowserContext* context);
+  Service(const std::string& api_key,
+          const GURL& server_url,
+          content::BrowserContext* context);
   virtual ~Service();
 
   using ResponseCallback =
diff --git a/components/browser_sync/BUILD.gn b/components/browser_sync/BUILD.gn
index da5c5e3b..fa0d494 100644
--- a/components/browser_sync/BUILD.gn
+++ b/components/browser_sync/BUILD.gn
@@ -32,7 +32,6 @@
     "//components/invalidation/public",
     "//components/keyed_service/core",
     "//components/password_manager/core/browser",
-    "//components/password_manager/sync/browser",
     "//components/pref_registry",
     "//components/prefs",
     "//components/reading_list/features:flags",
diff --git a/components/browser_sync/DEPS b/components/browser_sync/DEPS
index dbb0380..796a490 100644
--- a/components/browser_sync/DEPS
+++ b/components/browser_sync/DEPS
@@ -8,7 +8,6 @@
   "+components/invalidation",
   "+components/keyed_service/core",
   "+components/password_manager/core/browser",
-  "+components/password_manager/sync/browser",
   "+components/pref_registry",
   "+components/prefs",
   "+components/reading_list/features",
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 5ed2abe..556e256d 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -22,8 +22,8 @@
 #include "components/dom_distiller/core/dom_distiller_features.h"
 #include "components/history/core/browser/history_delete_directives_data_type_controller.h"
 #include "components/history/core/browser/typed_url_model_type_controller.h"
+#include "components/password_manager/core/browser/password_data_type_controller.h"
 #include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/sync/browser/password_data_type_controller.h"
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/features/reading_list_switches.h"
 #include "components/sync/base/report_unrecoverable_error.h"
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index def6ed2..8f0bab6 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/jumbo.gni")
 import("//testing/test.gni")
 
-static_library("metrics") {
+jumbo_static_library("metrics") {
   sources = [
     "call_stack_profile_metrics_provider.cc",
     "call_stack_profile_metrics_provider.h",
@@ -181,7 +182,7 @@
   }
 }
 
-static_library("net") {
+jumbo_static_library("net") {
   sources = [
     "net/cellular_logic_helper.cc",
     "net/cellular_logic_helper.h",
@@ -321,7 +322,7 @@
   ]
 }
 
-static_library("test_support") {
+jumbo_static_library("test_support") {
   testonly = true
   sources = [
     "test_enabled_state_provider.cc",
diff --git a/components/password_manager/DEPS b/components/password_manager/DEPS
index 174fecf5..33b8431 100644
--- a/components/password_manager/DEPS
+++ b/components/password_manager/DEPS
@@ -19,5 +19,4 @@
   # PasswordManager is a layered component; subdirectories must explicitly
   # introduce the ability to use non-core layers as appropriate.
   "-components/password_manager/content",
-  "-components/password_manager/sync",
 ]
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 71101d0..2d7ff566 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -13,6 +13,12 @@
 # TODO(crbug.com/706392): Fix password reuse detection for Android.
 password_reuse_detection_support = !is_android && !is_ios
 
+config("password_reuse_detection_config") {
+  if (password_reuse_detection_support) {
+    defines = [ "SYNC_PASSWORD_REUSE_DETECTION_ENABLED" ]
+  }
+}
+
 jumbo_static_library("browser") {
   sources = [
     "android_affiliation/affiliated_match_helper.cc",
@@ -97,6 +103,8 @@
     "password_autofill_manager.h",
     "password_bubble_experiment.cc",
     "password_bubble_experiment.h",
+    "password_data_type_controller.cc",
+    "password_data_type_controller.h",
     "password_form_filling.cc",
     "password_form_filling.h",
     "password_form_manager.cc",
@@ -126,9 +134,10 @@
     "password_manager_metrics_util.h",
     "password_manager_util.cc",
     "password_manager_util.h",
+    "password_model_worker.cc",
+    "password_model_worker.h",
     "password_requirements_service.cc",
     "password_requirements_service.h",
-    "password_reuse_defines.h",
     "password_store.cc",
     "password_store.h",
     "password_store_change.cc",
@@ -141,6 +150,8 @@
     "password_store_factory_util.h",
     "password_store_sync.cc",
     "password_store_sync.h",
+    "password_sync_util.cc",
+    "password_sync_util.h",
     "password_syncable_service.cc",
     "password_syncable_service.h",
     "password_ui_utils.cc",
@@ -153,8 +164,12 @@
     "sql_table_builder.h",
     "statistics_table.cc",
     "statistics_table.h",
+    "store_metrics_reporter.cc",
+    "store_metrics_reporter.h",
     "suppressed_form_fetcher.cc",
     "suppressed_form_fetcher.h",
+    "sync_credentials_filter.cc",
+    "sync_credentials_filter.h",
     "ui/credential_provider_interface.h",
     "ui/export_flow.h",
     "ui/export_progress_status.h",
@@ -163,6 +178,8 @@
     "votes_uploader.h",
   ]
 
+  all_dependent_configs = [ ":password_reuse_detection_config" ]
+
   if (password_reuse_detection_support) {
     sources += [
       "password_reuse_detection_manager.cc",
@@ -201,8 +218,10 @@
     "//components/pref_registry",
     "//components/prefs",
     "//components/security_state/core",
+    "//components/signin/core/browser",
     "//components/strings",
     "//components/sync",
+    "//components/sync_preferences",
     "//components/url_formatter",
     "//components/variations",
     "//components/webdata/common",
@@ -406,13 +425,18 @@
     "password_store_default_unittest.cc",
     "password_store_origin_unittest.h",
     "password_store_unittest.cc",
+    "password_sync_util_unittest.cc",
     "password_syncable_service_unittest.cc",
     "password_ui_utils_unittest.cc",
     "psl_matching_helper_unittest.cc",
     "site_affiliation/asset_link_data_unittest.cc",
     "sql_table_builder_unittest.cc",
     "statistics_table_unittest.cc",
+    "store_metrics_reporter_unittest.cc",
     "suppressed_form_fetcher_unittest.cc",
+    "sync_credentials_filter_unittest.cc",
+    "sync_username_test_base.cc",
+    "sync_username_test_base.h",
     "vote_uploads_test_matchers.h",
     "votes_uploader_unittest.cc",
   ]
@@ -456,9 +480,11 @@
     "//components/password_manager/core/common",
     "//components/prefs:test_support",
     "//components/security_state/core",
+    "//components/signin/core/browser:test_support",
     "//components/strings",
     "//components/sync:test_support_driver",
     "//components/sync:test_support_model",
+    "//components/sync_preferences:test_support",
     "//components/ukm:test_support",
     "//components/variations",
     "//google_apis:google_apis",
@@ -482,11 +508,6 @@
       "//components/safe_browsing/common:safe_browsing_prefs",
     ]
   }
-
-  if (is_ios) {
-    deps +=
-        [ "//components/password_manager/core/browser/form_parsing:unit_tests" ]
-  }
 }
 
 fuzzer_test("csv_reader_fuzzer") {
diff --git a/components/password_manager/core/browser/DEPS b/components/password_manager/core/browser/DEPS
index 11e54a3..52061acf 100644
--- a/components/password_manager/core/browser/DEPS
+++ b/components/password_manager/core/browser/DEPS
@@ -6,8 +6,11 @@
   "+components/security_state",
   "+components/safe_browsing/common/safe_browsing_prefs.h",
   "+components/safe_browsing/features.h",
+  "+components/signin/core/browser",
   "+components/sync/base",
   "+components/sync/driver",
+  "+components/sync/engine",
+  "+components/sync_preferences",
   "+components/url_formatter",
   "+components/variations",
   "+components/webdata/common",
diff --git a/components/password_manager/sync/browser/password_data_type_controller.cc b/components/password_manager/core/browser/password_data_type_controller.cc
similarity index 89%
rename from components/password_manager/sync/browser/password_data_type_controller.cc
rename to components/password_manager/core/browser/password_data_type_controller.cc
index eff4f69..8e0c650 100644
--- a/components/password_manager/sync/browser/password_data_type_controller.cc
+++ b/components/password_manager/core/browser/password_data_type_controller.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/sync/browser/password_data_type_controller.h"
+#include "components/password_manager/core/browser/password_data_type_controller.h"
 
 #include "base/bind.h"
 #include "base/metrics/histogram.h"
@@ -13,9 +13,9 @@
 namespace browser_sync {
 
 PasswordDataTypeController::PasswordDataTypeController(
-    const base::Closure& dump_stack,
+    const base::RepeatingClosure& dump_stack,
     syncer::SyncClient* sync_client,
-    const base::Closure& state_changed_callback,
+    const base::RepeatingClosure& state_changed_callback,
     const scoped_refptr<password_manager::PasswordStore>& password_store)
     : AsyncDirectoryTypeController(syncer::PASSWORDS,
                                    dump_stack,
@@ -30,7 +30,7 @@
 
 bool PasswordDataTypeController::PostTaskOnModelThread(
     const base::Location& from_here,
-    const base::Closure& task) {
+    const base::RepeatingClosure& task) {
   DCHECK(CalledOnValidThread());
   if (!password_store_)
     return false;
diff --git a/components/password_manager/sync/browser/password_data_type_controller.h b/components/password_manager/core/browser/password_data_type_controller.h
similarity index 74%
rename from components/password_manager/sync/browser/password_data_type_controller.h
rename to components/password_manager/core/browser/password_data_type_controller.h
index 10f8cef..b663c80 100644
--- a/components/password_manager/sync/browser/password_data_type_controller.h
+++ b/components/password_manager/core/browser/password_data_type_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_DATA_TYPE_CONTROLLER_H__
-#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_DATA_TYPE_CONTROLLER_H__
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_DATA_TYPE_CONTROLLER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_DATA_TYPE_CONTROLLER_H_
 
 #include <string>
 
@@ -27,16 +27,16 @@
  public:
   // |dump_stack| is called when an unrecoverable error occurs.
   PasswordDataTypeController(
-      const base::Closure& dump_stack,
+      const base::RepeatingClosure& dump_stack,
       syncer::SyncClient* sync_client,
-      const base::Closure& state_changed_callback,
+      const base::RepeatingClosure& state_changed_callback,
       const scoped_refptr<password_manager::PasswordStore>& password_store);
   ~PasswordDataTypeController() override;
 
  protected:
   // AsyncDirectoryTypeController interface.
   bool PostTaskOnModelThread(const base::Location& from_here,
-                             const base::Closure& task) override;
+                             const base::RepeatingClosure& task) override;
   bool StartModels() override;
   void StopModels() override;
 
@@ -45,7 +45,7 @@
 
  private:
   syncer::SyncClient* const sync_client_;
-  const base::Closure state_changed_callback_;
+  const base::RepeatingClosure state_changed_callback_;
   scoped_refptr<password_manager::PasswordStore> password_store_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordDataTypeController);
@@ -53,4 +53,4 @@
 
 }  // namespace browser_sync
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_DATA_TYPE_CONTROLLER_H__
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_DATA_TYPE_CONTROLLER_H_
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index f5d3717f2..10a81cc 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -32,7 +32,6 @@
 #include "components/password_manager/core/browser/password_manager_driver.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index ab5eea3e..fa64db9f 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -12,6 +12,7 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/credentials_filter.h"
 #include "components/password_manager/core/browser/hsts_query.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "net/cert/cert_status_flags.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 99341ff..f34263c0 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 
 namespace password_manager {
diff --git a/components/password_manager/core/browser/password_manager_test_utils.cc b/components/password_manager/core/browser/password_manager_test_utils.cc
index 0a48ae2..9557530e 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -106,8 +106,7 @@
 
 MockPasswordStoreObserver::~MockPasswordStoreObserver() {}
 
-// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
 MockPasswordReuseDetectorConsumer::MockPasswordReuseDetectorConsumer() {}
 
 MockPasswordReuseDetectorConsumer::~MockPasswordReuseDetectorConsumer() {}
diff --git a/components/password_manager/core/browser/password_manager_test_utils.h b/components/password_manager/core/browser/password_manager_test_utils.h
index 3e8edd72..889d835 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/components/password_manager/core/browser/password_manager_test_utils.h
@@ -14,6 +14,11 @@
 #include "components/password_manager/core/browser/password_store.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+#include "components/password_manager/core/browser/password_hash_data.h"  // nogncheck
+#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"  // nogncheck
+#endif
+
 namespace password_manager {
 
 // This template allows creating methods with signature conforming to
@@ -80,8 +85,7 @@
   MOCK_METHOD1(OnLoginsChanged, void(const PasswordStoreChangeList& changes));
 };
 
-// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
 class MockPasswordReuseDetectorConsumer : public PasswordReuseDetectorConsumer {
  public:
   MockPasswordReuseDetectorConsumer();
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 1fc6d84..b4c6fa1 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -26,7 +26,6 @@
 #include "components/password_manager/core/browser/new_password_form_manager.h"
 #include "components/password_manager/core/browser/password_autofill_manager.h"
 #include "components/password_manager/core/browser/password_manager_driver.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/statistics_table.h"
 #include "components/password_manager/core/browser/stub_credentials_filter.h"
diff --git a/components/password_manager/sync/browser/password_model_worker.cc b/components/password_manager/core/browser/password_model_worker.cc
similarity index 86%
rename from components/password_manager/sync/browser/password_model_worker.cc
rename to components/password_manager/core/browser/password_model_worker.cc
index cdb261f..51f796f 100644
--- a/components/password_manager/sync/browser/password_model_worker.cc
+++ b/components/password_manager/core/browser/password_model_worker.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/sync/browser/password_model_worker.h"
+#include "components/password_manager/core/browser/password_model_worker.h"
 
 #include <utility>
 
@@ -33,8 +33,8 @@
   base::AutoLock lock(password_store_lock_);
   if (password_store_) {
     password_store_->ScheduleTask(
-        base::Bind([](base::OnceClosure work) { std::move(work).Run(); },
-                   base::Passed(std::move(work))));
+        base::BindOnce([](base::OnceClosure work) { std::move(work).Run(); },
+                       base::Passed(std::move(work))));
   }
 }
 
diff --git a/components/password_manager/sync/browser/password_model_worker.h b/components/password_manager/core/browser/password_model_worker.h
similarity index 87%
rename from components/password_manager/sync/browser/password_model_worker.h
rename to components/password_manager/core/browser/password_model_worker.h
index 40a422b..b3569ff3 100644
--- a/components/password_manager/sync/browser/password_model_worker.h
+++ b/components/password_manager/core/browser/password_model_worker.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_MODEL_WORKER_H_
-#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_MODEL_WORKER_H_
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MODEL_WORKER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MODEL_WORKER_H_
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -42,4 +42,4 @@
 
 }  // namespace browser_sync
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_MODEL_WORKER_H_
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MODEL_WORKER_H_
diff --git a/components/password_manager/core/browser/password_reuse_defines.h b/components/password_manager/core/browser/password_reuse_defines.h
deleted file mode 100644
index a45e9ff..0000000
--- a/components/password_manager/core/browser/password_reuse_defines.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DEFINES_H_
-#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DEFINES_H_
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
-    defined(OS_LINUX) || defined(OS_CHROMEOS)
-// Enable the detection when the sync password is typed not on the sync domain.
-#define SYNC_PASSWORD_REUSE_DETECTION_ENABLED
-#endif
-
-#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_REUSE_DEFINES_H_
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 69d3a8c..2030ea6f 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -23,7 +23,6 @@
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/password_manager/core/browser/password_syncable_service.h"
 #include "components/password_manager/core/browser/statistics_table.h"
@@ -151,22 +150,22 @@
 }
 
 void PasswordStore::AddLogin(const PasswordForm& form) {
-  ScheduleTask(base::Bind(&PasswordStore::AddLoginInternal, this, form));
+  ScheduleTask(base::BindOnce(&PasswordStore::AddLoginInternal, this, form));
 }
 
 void PasswordStore::UpdateLogin(const PasswordForm& form) {
-  ScheduleTask(base::Bind(&PasswordStore::UpdateLoginInternal, this, form));
+  ScheduleTask(base::BindOnce(&PasswordStore::UpdateLoginInternal, this, form));
 }
 
 void PasswordStore::UpdateLoginWithPrimaryKey(
     const autofill::PasswordForm& new_form,
     const autofill::PasswordForm& old_primary_key) {
-  ScheduleTask(base::Bind(&PasswordStore::UpdateLoginWithPrimaryKeyInternal,
-                          this, new_form, old_primary_key));
+  ScheduleTask(base::BindOnce(&PasswordStore::UpdateLoginWithPrimaryKeyInternal,
+                              this, new_form, old_primary_key));
 }
 
 void PasswordStore::RemoveLogin(const PasswordForm& form) {
-  ScheduleTask(base::Bind(&PasswordStore::RemoveLoginInternal, this, form));
+  ScheduleTask(base::BindOnce(&PasswordStore::RemoveLoginInternal, this, form));
 }
 
 void PasswordStore::RemoveLoginsByURLAndTime(
@@ -174,23 +173,24 @@
     base::Time delete_begin,
     base::Time delete_end,
     const base::Closure& completion) {
-  ScheduleTask(base::Bind(&PasswordStore::RemoveLoginsByURLAndTimeInternal,
-                          this, url_filter, delete_begin, delete_end,
-                          completion));
+  ScheduleTask(base::BindOnce(&PasswordStore::RemoveLoginsByURLAndTimeInternal,
+                              this, url_filter, delete_begin, delete_end,
+                              completion));
 }
 
 void PasswordStore::RemoveLoginsCreatedBetween(
     base::Time delete_begin,
     base::Time delete_end,
     const base::Closure& completion) {
-  ScheduleTask(base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenInternal,
-                          this, delete_begin, delete_end, completion));
+  ScheduleTask(
+      base::BindOnce(&PasswordStore::RemoveLoginsCreatedBetweenInternal, this,
+                     delete_begin, delete_end, completion));
 }
 
 void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
                                               base::Time delete_end) {
-  ScheduleTask(base::Bind(&PasswordStore::RemoveLoginsSyncedBetweenInternal,
-                          this, delete_begin, delete_end));
+  ScheduleTask(base::BindOnce(&PasswordStore::RemoveLoginsSyncedBetweenInternal,
+                              this, delete_begin, delete_end));
 }
 
 void PasswordStore::RemoveStatisticsByOriginAndTime(
@@ -198,17 +198,17 @@
     base::Time delete_begin,
     base::Time delete_end,
     const base::Closure& completion) {
-  ScheduleTask(
-      base::Bind(&PasswordStore::RemoveStatisticsByOriginAndTimeInternal, this,
-                 origin_filter, delete_begin, delete_end, completion));
+  ScheduleTask(base::BindOnce(
+      &PasswordStore::RemoveStatisticsByOriginAndTimeInternal, this,
+      origin_filter, delete_begin, delete_end, completion));
 }
 
 void PasswordStore::DisableAutoSignInForOrigins(
     const base::Callback<bool(const GURL&)>& origin_filter,
     const base::Closure& completion) {
-  ScheduleTask(
-      base::Bind(&PasswordStore::DisableAutoSignInForOriginsInternal, this,
-                 base::Callback<bool(const GURL&)>(origin_filter), completion));
+  ScheduleTask(base::BindOnce(
+      &PasswordStore::DisableAutoSignInForOriginsInternal, this,
+      base::RepeatingCallback<bool(const GURL&)>(origin_filter), completion));
 }
 
 void PasswordStore::GetLogins(const FormDigest& form,
@@ -242,8 +242,8 @@
         form, base::Bind(&PasswordStore::ScheduleGetLoginsWithAffiliations,
                          this, form, base::Passed(&request)));
   } else {
-    ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl, this, form,
-                            base::Passed(&request)));
+    ScheduleTask(base::BindOnce(&PasswordStore::GetLoginsImpl, this, form,
+                                base::Passed(&request)));
   }
 }
 
@@ -251,8 +251,9 @@
     const std::string& signon_realm,
     PasswordStoreConsumer* consumer) {
   std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
-  ScheduleTask(base::Bind(&PasswordStore::GetLoginsForSameOrganizationNameImpl,
-                          this, signon_realm, base::Passed(&request)));
+  ScheduleTask(
+      base::BindOnce(&PasswordStore::GetLoginsForSameOrganizationNameImpl, this,
+                     signon_realm, base::Passed(&request)));
 }
 
 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
@@ -302,25 +303,25 @@
 }
 
 void PasswordStore::AddSiteStats(const InteractionsStats& stats) {
-  ScheduleTask(base::Bind(&PasswordStore::AddSiteStatsImpl, this, stats));
+  ScheduleTask(base::BindOnce(&PasswordStore::AddSiteStatsImpl, this, stats));
 }
 
 void PasswordStore::RemoveSiteStats(const GURL& origin_domain) {
   ScheduleTask(
-      base::Bind(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain));
+      base::BindOnce(&PasswordStore::RemoveSiteStatsImpl, this, origin_domain));
 }
 
 void PasswordStore::GetAllSiteStats(PasswordStoreConsumer* consumer) {
   std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
-  ScheduleTask(base::Bind(&PasswordStore::NotifyAllSiteStats, this,
-                          base::Passed(&request)));
+  ScheduleTask(base::BindOnce(&PasswordStore::NotifyAllSiteStats, this,
+                              base::Passed(&request)));
 }
 
 void PasswordStore::GetSiteStats(const GURL& origin_domain,
                                  PasswordStoreConsumer* consumer) {
   std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
-  ScheduleTask(base::Bind(&PasswordStore::NotifySiteStats, this, origin_domain,
-                          base::Passed(&request)));
+  ScheduleTask(base::BindOnce(&PasswordStore::NotifySiteStats, this,
+                              origin_domain, base::Passed(&request)));
 }
 
 void PasswordStore::AddObserver(Observer* observer) {
@@ -331,9 +332,9 @@
   observers_->RemoveObserver(observer);
 }
 
-bool PasswordStore::ScheduleTask(const base::Closure& task) {
+bool PasswordStore::ScheduleTask(base::OnceClosure task) {
   if (background_task_runner_)
-    return background_task_runner_->PostTask(FROM_HERE, task);
+    return background_task_runner_->PostTask(FROM_HERE, std::move(task));
   return false;
 }
 
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index f91e40d..8fbbbb5d 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -18,7 +18,6 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/keyed_service/core/refcounted_keyed_service.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "components/password_manager/core/browser/password_store_change.h"
 #include "components/password_manager/core/browser/password_store_sync.h"
 #include "components/sync/model/syncable_service.h"
@@ -250,7 +249,7 @@
   void RemoveObserver(Observer* observer);
 
   // Schedules the given |task| to be run on the PasswordStore's TaskRunner.
-  bool ScheduleTask(const base::Closure& task);
+  bool ScheduleTask(base::OnceClosure task);
 
   // Returns true iff initialization was successful.
   bool IsAbleToSavePasswords() const;
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index a3be1aa2..ca152af1 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -25,7 +25,7 @@
 
 void PasswordStoreDefault::ShutdownOnUIThread() {
   PasswordStore::ShutdownOnUIThread();
-  ScheduleTask(base::Bind(&PasswordStoreDefault::ResetLoginDB, this));
+  ScheduleTask(base::BindOnce(&PasswordStoreDefault::ResetLoginDB, this));
 }
 
 bool PasswordStoreDefault::InitOnBackgroundSequence(
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 016d8ef..3c4ca37 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -16,7 +16,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
-#include "build/build_config.h"
 #include "components/os_crypt/os_crypt_mocker.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
@@ -718,15 +717,15 @@
       }
       if (test_remove_and_add_login) {
         store->ScheduleTask(
-            base::Bind(IgnoreResult(&PasswordStore::RemoveLoginSync), store,
-                       *all_credentials[0]));
+            base::BindOnce(IgnoreResult(&PasswordStore::RemoveLoginSync), store,
+                           *all_credentials[0]));
         store->ScheduleTask(
-            base::Bind(IgnoreResult(&PasswordStore::AddLoginSync), store,
-                       *expected_credentials_after_update[0]));
+            base::BindOnce(IgnoreResult(&PasswordStore::AddLoginSync), store,
+                           *expected_credentials_after_update[0]));
       } else {
         store->ScheduleTask(
-            base::Bind(IgnoreResult(&PasswordStore::UpdateLoginSync), store,
-                       *expected_credentials_after_update[0]));
+            base::BindOnce(IgnoreResult(&PasswordStore::UpdateLoginSync), store,
+                           *expected_credentials_after_update[0]));
       }
       WaitForPasswordStore();
       store->RemoveObserver(&mock_observer);
@@ -871,8 +870,7 @@
   store->ShutdownOnUIThread();
 }
 
-// TODO(crbug.com/706392): Fix password reuse detection for Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
 TEST_F(PasswordStoreTest, CheckPasswordReuse) {
   static constexpr PasswordFormData kTestCredentials[] = {
       {PasswordForm::SCHEME_HTML, "https://www.google.com",
@@ -918,9 +916,7 @@
 
   store->ShutdownOnUIThread();
 }
-#endif
 
-#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
 TEST_F(PasswordStoreTest, SavingClearingProtectedPassword) {
   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
       std::make_unique<LoginDatabase>(test_login_db_file_path())));
diff --git a/components/password_manager/sync/browser/password_sync_util.cc b/components/password_manager/core/browser/password_sync_util.cc
similarity index 96%
rename from components/password_manager/sync/browser/password_sync_util.cc
rename to components/password_manager/core/browser/password_sync_util.cc
index b41a87f..86e59ff 100644
--- a/components/password_manager/sync/browser/password_sync_util.cc
+++ b/components/password_manager/core/browser/password_sync_util.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/password_manager/sync/browser/password_sync_util.h"
+#include "components/password_manager/core/browser/password_sync_util.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "url/origin.h"
diff --git a/components/password_manager/sync/browser/password_sync_util.h b/components/password_manager/core/browser/password_sync_util.h
similarity index 91%
rename from components/password_manager/sync/browser/password_sync_util.h
rename to components/password_manager/core/browser/password_sync_util.h
index c595c093..00cd4cf 100644
--- a/components/password_manager/sync/browser/password_sync_util.h
+++ b/components/password_manager/core/browser/password_sync_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_SYNC_UTIL_H_
-#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_SYNC_UTIL_H_
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_SYNC_UTIL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_SYNC_UTIL_H_
 
 #include <string>
 
@@ -52,4 +52,4 @@
 }  // namespace sync_util
 }  // namespace password_manager
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_PASSWORD_SYNC_UTIL_H_
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_SYNC_UTIL_H_
diff --git a/components/password_manager/sync/browser/password_sync_util_unittest.cc b/components/password_manager/core/browser/password_sync_util_unittest.cc
similarity index 93%
rename from components/password_manager/sync/browser/password_sync_util_unittest.cc
rename to components/password_manager/core/browser/password_sync_util_unittest.cc
index 92e92e3d..ec35e131f 100644
--- a/components/password_manager/sync/browser/password_sync_util_unittest.cc
+++ b/components/password_manager/core/browser/password_sync_util_unittest.cc
@@ -2,29 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/password_manager/sync/browser/password_sync_util.h"
+#include "components/password_manager/core/browser/password_sync_util.h"
 
 #include <stddef.h>
 
-#include "base/macros.h"
+#include "base/stl_util.h"
 #include "build/build_config.h"
 #include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/core/browser/password_reuse_defines.h"
-#include "components/password_manager/sync/browser/sync_username_test_base.h"
+#include "components/password_manager/core/browser/sync_username_test_base.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if !defined(OS_IOS)
-#include "components/safe_browsing/common/safe_browsing_prefs.h"
-#endif  // !OS_IOS
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+#include "components/safe_browsing/common/safe_browsing_prefs.h"  // nogncheck
+#endif  // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
 
 using autofill::PasswordForm;
 
 namespace password_manager {
 namespace sync_util {
 
-typedef SyncUsernameTestBase PasswordSyncUtilTest;
+using PasswordSyncUtilTest = SyncUsernameTestBase;
 
 PasswordForm SimpleGAIAChangePasswordForm() {
   PasswordForm form;
@@ -58,7 +57,7 @@
        nullptr},
   };
 
-  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+  for (size_t i = 0; i < base::size(kTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "i=" << i);
     SetSyncingPasswords(kTestCases[i].password_sync ==
                         TestCase::SYNCING_PASSWORDS);
@@ -85,7 +84,7 @@
       {SimpleGAIAChangePasswordForm(), "sync_user@example.org", true},
   };
 
-  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+  for (size_t i = 0; i < base::size(kTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "i=" << i);
     SetSyncingPasswords(true);
     FakeSigninAs(kTestCases[i].fake_sync_username);
@@ -179,7 +178,7 @@
   };
 
   for (bool syncing_passwords : {false, true}) {
-    for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    for (size_t i = 0; i < base::size(kTestCases); ++i) {
       SCOPED_TRACE(testing::Message() << "i=" << i);
       SetSyncingPasswords(syncing_passwords);
       FakeSigninAs(kTestCases[i].fake_sync_username);
diff --git a/components/password_manager/core/browser/store_metrics_reporter.cc b/components/password_manager/core/browser/store_metrics_reporter.cc
new file mode 100644
index 0000000..37f726f
--- /dev/null
+++ b/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -0,0 +1,39 @@
+// Copyright 2018 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/password_manager/core/browser/store_metrics_reporter.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "components/password_manager/core/browser/password_bubble_experiment.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/browser/password_sync_util.h"
+
+namespace password_manager {
+
+StoreMetricsReporter::StoreMetricsReporter(
+    bool password_manager_enabled,
+    PasswordManagerClient* client,
+    const syncer::SyncService* sync_service,
+    const SigninManagerBase* signin_manager,
+    PrefService* prefs) {
+  password_manager::PasswordStore* store = client->GetPasswordStore();
+  // May be null in tests.
+  if (store) {
+    store->ReportMetrics(
+        password_manager::sync_util::GetSyncUsernameIfSyncingPasswords(
+            sync_service, signin_manager),
+        client->GetPasswordSyncState() ==
+            password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE);
+  }
+  UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled);
+  UMA_HISTOGRAM_BOOLEAN(
+      "PasswordManager.ShouldShowAutoSignInFirstRunExperience",
+      password_bubble_experiment::ShouldShowAutoSignInPromptFirstRunExperience(
+          prefs));
+}
+
+StoreMetricsReporter::~StoreMetricsReporter() = default;
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/store_metrics_reporter.h b/components/password_manager/core/browser/store_metrics_reporter.h
new file mode 100644
index 0000000..717f23f1
--- /dev/null
+++ b/components/password_manager/core/browser/store_metrics_reporter.h
@@ -0,0 +1,49 @@
+// Copyright 2018 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_PASSWORD_MANAGER_CORE_BROWSER_STORE_METRICS_REPORTER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STORE_METRICS_REPORTER_H_
+
+#include "base/macros.h"
+
+class PrefService;
+class SigninManagerBase;
+
+namespace syncer {
+class SyncService;
+}  //  namespace syncer
+
+namespace password_manager {
+
+class PasswordManagerClient;
+
+// Instantiate this object to report metrics about the contents of the password
+// store. Create a static base::NoDestructor<StoreMetricsReporter> to ensure
+// that metrics are reported only once per process. This is thread-safe, because
+// C++11 guarantees that: "If control enters the declaration concurrently while
+// the variable is being initialized, the concurrent execution shall wait for
+// completion of the initialization." So the reporter is only initialised (and
+// hence reports) once.
+class StoreMetricsReporter {
+ public:
+  // Reports various metrics based on whether password manager is enabled. Uses
+  // |client| to obtain the password store and password syncing state. Uses
+  // |sync_service| and |signin_manager| to obtain the sync username to report
+  // about its presence among saved credentials. Uses the |prefs| to obtain the
+  // state of the first-run-experience bubble.
+  StoreMetricsReporter(bool password_manager_enabled,
+                       PasswordManagerClient* client,
+                       const syncer::SyncService* sync_service,
+                       const SigninManagerBase* signin_manager,
+                       PrefService* prefs);
+
+  ~StoreMetricsReporter();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StoreMetricsReporter);
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STORE_METRICS_REPORTER_H_
diff --git a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
new file mode 100644
index 0000000..ed25769
--- /dev/null
+++ b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright 2018 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/password_manager/core/browser/store_metrics_reporter.h"
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/browser/sync_username_test_base.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Return;
+
+namespace password_manager {
+namespace {
+
+class MockPasswordManagerClient : public StubPasswordManagerClient {
+ public:
+  MOCK_CONST_METHOD0(GetPasswordStore, PasswordStore*());
+  MOCK_CONST_METHOD0(GetPasswordSyncState, SyncState());
+};
+
+class StoreMetricsReporterTest : public SyncUsernameTestBase {
+ public:
+  StoreMetricsReporterTest() {
+    prefs_.registry()->RegisterBooleanPref(
+        password_manager::prefs::kWasAutoSignInFirstRunExperienceShown, false,
+        PrefRegistry::NO_REGISTRATION_FLAGS);
+  }
+
+  ~StoreMetricsReporterTest() override = default;
+
+ protected:
+  MockPasswordManagerClient client_;
+  TestingPrefServiceSimple prefs_;
+  DISALLOW_COPY_AND_ASSIGN(StoreMetricsReporterTest);
+};
+
+// Test that store-independent metrics are reported correctly.
+TEST_F(StoreMetricsReporterTest, StoreIndependentMetrics) {
+  for (const bool password_manager_enabled : {true, false}) {
+    for (const bool first_run_ui_shown : {true, false}) {
+      SCOPED_TRACE(testing::Message()
+                   << "password_manager_enabled=" << password_manager_enabled
+                   << ", first_run_ui_shown=" << first_run_ui_shown);
+
+      prefs_.SetBoolean(
+          password_manager::prefs::kWasAutoSignInFirstRunExperienceShown,
+          first_run_ui_shown);
+      base::HistogramTester histogram_tester;
+      EXPECT_CALL(client_, GetPasswordStore()).WillOnce(Return(nullptr));
+
+      StoreMetricsReporter reporter(password_manager_enabled, &client_,
+                                    sync_service(), signin_manager(), &prefs_);
+
+      histogram_tester.ExpectBucketCount("PasswordManager.Enabled",
+                                         password_manager_enabled, 1);
+      histogram_tester.ExpectBucketCount(
+          "PasswordManager.ShouldShowAutoSignInFirstRunExperience",
+          !first_run_ui_shown, 1);
+    }
+  }
+}
+
+// Test that sync username and syncing state are passed correctly to the
+// PasswordStore.
+TEST_F(StoreMetricsReporterTest, PasswordStore) {
+  for (const bool syncing_with_passphrase : {true, false}) {
+    SCOPED_TRACE(testing::Message()
+                 << "syncing_with_passphrase=" << syncing_with_passphrase);
+
+    auto store = base::MakeRefCounted<MockPasswordStore>();
+    const auto sync_state =
+        syncing_with_passphrase
+            ? password_manager::SYNCING_WITH_CUSTOM_PASSPHRASE
+            : password_manager::SYNCING_NORMAL_ENCRYPTION;
+    EXPECT_CALL(client_, GetPasswordSyncState()).WillOnce(Return(sync_state));
+    EXPECT_CALL(client_, GetPasswordStore()).WillOnce(Return(store.get()));
+    EXPECT_CALL(*store,
+                ReportMetrics("some.user@gmail.com", syncing_with_passphrase));
+    FakeSigninAs("some.user@gmail.com");
+
+    StoreMetricsReporter reporter(true, &client_, sync_service(),
+                                  signin_manager(), &prefs_);
+    store->ShutdownOnUIThread();
+  }
+}
+
+}  // namespace
+}  // namespace password_manager
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.cc b/components/password_manager/core/browser/sync_credentials_filter.cc
similarity index 97%
rename from components/password_manager/sync/browser/sync_credentials_filter.cc
rename to components/password_manager/core/browser/sync_credentials_filter.cc
index 9238f54..64d4371 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter.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/sync/browser/sync_credentials_filter.h"
+#include "components/password_manager/core/browser/sync_credentials_filter.h"
 
 #include <algorithm>
 
@@ -12,8 +12,8 @@
 #include "base/metrics/user_metrics.h"
 #include "components/password_manager/core/browser/password_form_manager.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/browser/password_sync_util.h"
 #include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/sync/browser/password_sync_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/base/url_util.h"
 
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.h b/components/password_manager/core/browser/sync_credentials_filter.h
similarity index 86%
rename from components/password_manager/sync/browser/sync_credentials_filter.h
rename to components/password_manager/core/browser/sync_credentials_filter.h
index d254307..5b1ab563 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter.h
+++ b/components/password_manager/core/browser/sync_credentials_filter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_CREDENTIALS_FILTER_H_
-#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_CREDENTIALS_FILTER_H_
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_CREDENTIALS_FILTER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_CREDENTIALS_FILTER_H_
 
 #include <memory>
 #include <string>
@@ -22,10 +22,10 @@
 // The sync- and GAIA- aware implementation of the filter.
 class SyncCredentialsFilter : public CredentialsFilter {
  public:
-  typedef base::Callback<const syncer::SyncService*(void)>
-      SyncServiceFactoryFunction;
-  typedef base::Callback<const SigninManagerBase*(void)>
-      SigninManagerFactoryFunction;
+  using SyncServiceFactoryFunction =
+      base::RepeatingCallback<const syncer::SyncService*(void)>;
+  using SigninManagerFactoryFunction =
+      base::RepeatingCallback<const SigninManagerBase*(void)>;
 
   // Implements protection of sync credentials. Uses |client| to get the last
   // commited entry URL for a check against GAIA reauth site. Uses the factory
@@ -73,4 +73,4 @@
 
 }  // namespace password_manager
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_CREDENTIALS_FILTER_H_
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_CREDENTIALS_FILTER_H_
diff --git a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
similarity index 95%
rename from components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
rename to components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index db0c732..1b5fed6 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/password_manager/sync/browser/sync_credentials_filter.h"
+#include "components/password_manager/core/browser/sync_credentials_filter.h"
 
 #include <stddef.h>
 
@@ -14,6 +14,7 @@
 #include "base/bind_helpers.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/metrics/user_action_tester.h"
@@ -26,15 +27,17 @@
 #include "components/password_manager/core/browser/stub_form_saver.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
+#include "components/password_manager/core/browser/sync_username_test_base.h"
 #include "components/password_manager/core/common/password_manager_features.h"
-#include "components/password_manager/sync/browser/sync_username_test_base.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/safe_browsing/common/safe_browsing_prefs.h"
-#include "components/safe_browsing/features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+#include "components/safe_browsing/common/safe_browsing_prefs.h"  // nogncheck
+#endif  // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
+
 using autofill::PasswordForm;
 
 namespace password_manager {
@@ -139,10 +142,10 @@
                       std::make_unique<StubFormSaver>(),
                       &fetcher_),
         filter_(&client_,
-                base::Bind(&SyncUsernameTestBase::sync_service,
-                           base::Unretained(this)),
-                base::Bind(&SyncUsernameTestBase::signin_manager,
-                           base::Unretained(this))) {
+                base::BindRepeating(&SyncUsernameTestBase::sync_service,
+                                    base::Unretained(this)),
+                base::BindRepeating(&SyncUsernameTestBase::signin_manager,
+                                    base::Unretained(this))) {
     form_manager_.Init(nullptr);
     fetcher_.Fetch();
   }
@@ -224,7 +227,7 @@
        TestCase::NO_HISTOGRAM},
   };
 
-  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+  for (size_t i = 0; i < base::size(kTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "i=" << i);
     CheckFilterResultsTestCase(kTestCases[i]);
   }
@@ -276,7 +279,7 @@
        TestCase::NO_HISTOGRAM},
   };
 
-  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+  for (size_t i = 0; i < base::size(kTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "i=" << i);
     CheckFilterResultsTestCase(kTestCases[i]);
   }
@@ -326,7 +329,7 @@
        TestCase::HISTOGRAM_REPORTED},
   };
 
-  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+  for (size_t i = 0; i < base::size(kTestCases); ++i) {
     SCOPED_TRACE(testing::Message() << "i=" << i);
     CheckFilterResultsTestCase(kTestCases[i]);
   }
diff --git a/components/password_manager/sync/browser/sync_username_test_base.cc b/components/password_manager/core/browser/sync_username_test_base.cc
similarity index 97%
rename from components/password_manager/sync/browser/sync_username_test_base.cc
rename to components/password_manager/core/browser/sync_username_test_base.cc
index 877d828..8aee275 100644
--- a/components/password_manager/sync/browser/sync_username_test_base.cc
+++ b/components/password_manager/core/browser/sync_username_test_base.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/sync/browser/sync_username_test_base.h"
+#include "components/password_manager/core/browser/sync_username_test_base.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "components/signin/core/browser/signin_pref_names.h"
diff --git a/components/password_manager/sync/browser/sync_username_test_base.h b/components/password_manager/core/browser/sync_username_test_base.h
similarity index 92%
rename from components/password_manager/sync/browser/sync_username_test_base.h
rename to components/password_manager/core/browser/sync_username_test_base.h
index d1af98a..31b155a 100644
--- a/components/password_manager/sync/browser/sync_username_test_base.h
+++ b/components/password_manager/core/browser/sync_username_test_base.h
@@ -5,8 +5,8 @@
 // A base test fixture for mocking sync and signin infrastructure. Used for
 // testing sync-related code.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_USERNAME_TEST_BASE_H_
-#define COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_USERNAME_TEST_BASE_H_
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_USERNAME_TEST_BASE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_USERNAME_TEST_BASE_H_
 
 #include <string>
 
@@ -78,4 +78,4 @@
 
 }  // namespace password_manager
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_SYNC_BROWSER_SYNC_USERNAME_TEST_BASE_H_
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SYNC_USERNAME_TEST_BASE_H_
diff --git a/components/password_manager/sync/browser/BUILD.gn b/components/password_manager/sync/browser/BUILD.gn
deleted file mode 100644
index 8778b598..0000000
--- a/components/password_manager/sync/browser/BUILD.gn
+++ /dev/null
@@ -1,71 +0,0 @@
-# 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.
-
-import("//build/config/jumbo.gni")
-
-jumbo_static_library("browser") {
-  sources = [
-    "password_data_type_controller.cc",
-    "password_data_type_controller.h",
-    "password_model_worker.cc",
-    "password_model_worker.h",
-    "password_sync_util.cc",
-    "password_sync_util.h",
-    "sync_credentials_filter.cc",
-    "sync_credentials_filter.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/autofill/core/common",
-    "//components/keyed_service/core",
-    "//components/password_manager/core/browser",
-    "//components/password_manager/core/common",
-    "//components/prefs",
-    "//components/signin/core/browser",
-    "//components/sync",
-    "//components/sync_preferences",
-    "//google_apis",
-    "//net",
-    "//url",
-  ]
-
-  if (!is_ios) {
-    deps += [ "//components/safe_browsing/common:safe_browsing_prefs" ]
-  }
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "password_sync_util_unittest.cc",
-    "sync_credentials_filter_unittest.cc",
-    "sync_username_test_base.cc",
-    "sync_username_test_base.h",
-  ]
-  deps = [
-    ":browser",
-    "//base",
-    "//base/test:test_support",
-    "//components/autofill/core/common",
-    "//components/password_manager/core/browser:test_support",
-    "//components/password_manager/core/common",
-    "//components/prefs",
-    "//components/signin/core/browser",
-    "//components/signin/core/browser:test_support",
-    "//components/sync:test_support_driver",
-    "//components/sync:test_support_model",
-    "//components/sync_preferences",
-    "//components/sync_preferences:test_support",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-
-  if (!is_ios) {
-    deps += [
-      "//components/safe_browsing:features",
-      "//components/safe_browsing/common:safe_browsing_prefs",
-    ]
-  }
-}
diff --git a/components/password_manager/sync/browser/DEPS b/components/password_manager/sync/browser/DEPS
deleted file mode 100644
index 5af63c96..0000000
--- a/components/password_manager/sync/browser/DEPS
+++ /dev/null
@@ -1,12 +0,0 @@
-include_rules = [
-  "+components/keyed_service/core",
-  "+components/pref_registry",
-  "+components/safe_browsing/common",
-  "+components/safe_browsing/features.h",
-  "+components/signin/core/browser",
-  "+components/sync/base",
-  "+components/sync/driver",
-  "+components/sync/engine",
-  "+components/sync_preferences",
-  "+google_apis/gaia",
-]
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 095e1bd..22a0c9d 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -1393,6 +1393,9 @@
 
     // Start Chrome Remote Desktop session (limited to Kiosk sessions only).
     DEVICE_START_CRD_SESSION = 6;
+
+    // Wipe the device (perform a powerwash).
+    DEVICE_REMOTE_POWERWASH = 7;
   }
 
   // The command type.
@@ -1987,9 +1990,14 @@
 // 200 OK: valid response is returned to client.
 // 400 Bad Request: invalid argument.
 // 401 Unauthorized: invalid auth cookie or DM token.
+// 402 Missing licenses.
 // 403 Forbidden: device management is not allowed.
 // 404 Not Found: the request URL is invalid.
+// 405 Invalid serial number.
+// 409 Device id conflict.
 // 410 Device Not Found: the device id is not found.
+// 412 Pending approval.
+// 417 Consumer account with packaged license.
 // 491 Request Pending: the request is pending approval.
 // 500 Internal Server Error: most likely a bug in DM server.
 // 503 Service Unavailable: most likely a backend error.
@@ -1997,36 +2005,7 @@
 // 903 Deprovisioned: the device has been deprovisioned.
 // 904 Arc Disabled: ARC is not enabled on the domain.
 message DeviceManagementResponse {
-  reserved 24;
-
-  // TODO(hong): move error handling to HTTP level.
-  // Error code to client.
-  enum ErrorCode {
-    SUCCESS = 0;
-    // Returned for register request when device management is not supported
-    // for the domain.
-    DEVICE_MANAGEMENT_NOT_SUPPORTED = 1;
-    // Returned when the device is not found.
-    DEVICE_NOT_FOUND  = 2;
-    // Returned when passed in device management token doesn't match the token
-    // on server side.
-    DEVICE_MANAGEMENT_TOKEN_INVALID  = 3;
-    // Returned when device registration is pending approval (if required).
-    ACTIVATION_PENDING = 4;
-    // Returned when the policy is not found.
-    POLICY_NOT_FOUND  = 5;
-  }
-
-  // Error code for this response.
-  //
-  // For responses to TT clients, this field MUST be set, since it WAS
-  // a required field.  For special error code listed above, we return
-  // 200 in HTTP Status Code and set the real error code here.
-  //
-  // For release clients, we plan to move all error code to HTTP
-  // Status Code, so it is much easier for log analysis.  If possible,
-  // we plan to remove this field once Chrome OS TT phase is over.
-  optional ErrorCode error = 1 [default = SUCCESS];
+  reserved 1, 24;
 
   // Error message.
   optional string error_message = 2;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 0cb6c79c..d3ce79a 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -13308,6 +13308,29 @@
       When this policy is set to disabled or not set, no extensions are allowed to use the Enterprise Hardware Platform API.
       This policy also applies to component extensions such as the Hangout Services extension.''',
     },
+    {
+      'name': 'VpnConfigAllowed',
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:71-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': False,
+      },
+      'example_value': False,
+      'id': 485,
+      'caption': '''Allow the user to manage VPN connections''',
+      'tags': [],
+      'desc': '''Allow the user to manage VPN connections.
+
+      If this policy is set to false, all <ph name="PRODUCT_NAME">$2<ex>Google Chrome OS</ex></ph> user interfaces that would allow the user to disconnect or modify VPN connections are disabled.
+
+      If this policy is unset or set to true, users can disconnect or modify VPN connections as usual.
+
+      If the VPN connection is created via a VPN app, the UI inside the app remains unaffected by this policy. Therefore, the user might still be able to use the app to modify the VPN connection.
+
+      This policy is meant to be used together with the "Always on VPN" feature, that lets the admin decide to establish a VPN connection on boot.''',
+    },
   ],
 
   'messages': {
@@ -13449,5 +13472,5 @@
   },
   'placeholders': [],
   'deleted_policy_ids': [412],
-  'highest_id_currently_used': 484
+  'highest_id_currently_used': 485
 }
diff --git a/components/safe_browsing/proto/csd.proto b/components/safe_browsing/proto/csd.proto
index b02dbf21..0809ed7 100644
--- a/components/safe_browsing/proto/csd.proto
+++ b/components/safe_browsing/proto/csd.proto
@@ -483,7 +483,7 @@
     INVALID_ZIP = 7;
     // A .dmg, .pkg, etc, that Chrome failed to unpack to the point of finding
     // Mach O's.
-    INVALID_MAC_ARCHIVE = 8;
+    MAC_ARCHIVE_FAILED_PARSING = 8;
     // A download request initiated via PPAPI. Typically the requestor is
     // a Flash applet.
     PPAPI_SAVE_REQUEST = 9;
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc
index 84dd184..07d27b4 100644
--- a/components/sync/driver/about_sync_util.cc
+++ b/components/sync/driver/about_sync_util.cc
@@ -54,7 +54,8 @@
     "requestIncludeSpecificsInitialState";
 const char kRequestListOfTypes[] = "requestListOfTypes";
 const char kRequestStart[] = "requestStart";
-const char kRequestStop[] = "requestStop";
+const char kRequestStopKeepData[] = "requestStopKeepData";
+const char kRequestStopClearData[] = "requestStopClearData";
 const char kRequestUpdatedAboutInfo[] = "requestUpdatedAboutInfo";
 const char kRequestUserEventsVisibility[] = "requestUserEventsVisibility";
 const char kSetIncludeSpecifics[] = "setIncludeSpecifics";
diff --git a/components/sync/driver/about_sync_util.h b/components/sync/driver/about_sync_util.h
index f14264d6..20bdae58 100644
--- a/components/sync/driver/about_sync_util.h
+++ b/components/sync/driver/about_sync_util.h
@@ -50,7 +50,8 @@
 extern const char kRequestIncludeSpecificsInitialState[];
 extern const char kRequestListOfTypes[];
 extern const char kRequestStart[];
-extern const char kRequestStop[];
+extern const char kRequestStopKeepData[];
+extern const char kRequestStopClearData[];
 extern const char kRequestUpdatedAboutInfo[];
 extern const char kRequestUserEventsVisibility[];
 extern const char kSetIncludeSpecifics[];
diff --git a/components/sync/driver/resources/about.html b/components/sync/driver/resources/about.html
index 44e469f..8779ed3 100644
--- a/components/sync/driver/resources/about.html
+++ b/components/sync/driver/resources/about.html
@@ -27,7 +27,8 @@
 
   <div id="request-start-stop-wrapper" jsskip="true">
     <button id="request-start">Request Start</button>
-    <button id="request-stop">Request Stop</button>
+    <button id="request-stop-keep-data">Stop Sync (Keep Data)</button>
+    <button id="request-stop-clear-data">Disable Sync (Clear Data)</button>
   </div>
 
   <div id="traffic-event-container-wrapper" jsskip="true">
diff --git a/components/sync/driver/resources/about.js b/components/sync/driver/resources/about.js
index 6551e6fd..98634d1 100644
--- a/components/sync/driver/resources/about.js
+++ b/components/sync/driver/resources/about.js
@@ -226,8 +226,11 @@
     $('request-start').addEventListener('click', function(event) {
       chrome.sync.requestStart();
     });
-    $('request-stop').addEventListener('click', function(event) {
-      chrome.sync.requestStop();
+    $('request-stop-keep-data').addEventListener('click', function(event) {
+      chrome.sync.requestStopKeepData();
+    });
+    $('request-stop-clear-data').addEventListener('click', function(event) {
+      chrome.sync.requestStopClearData();
     });
 
     // Register to receive a stream of event notifications.
diff --git a/components/sync/driver/resources/chrome_sync.js b/components/sync/driver/resources/chrome_sync.js
index 14985101..7057b7d 100644
--- a/components/sync/driver/resources/chrome_sync.js
+++ b/components/sync/driver/resources/chrome_sync.js
@@ -121,10 +121,17 @@
   };
 
   /**
-   * Triggers a RequestStop call on the SyncService.
+   * Triggers a RequestStop(KEEP_DATA) call on the SyncService.
    */
-  var requestStop = function() {
-    chrome.send('requestStop');
+  var requestStopKeepData = function() {
+    chrome.send('requestStopKeepData');
+  };
+
+  /**
+   * Triggers a RequestStop(CLEAR_DATA) call on the SyncService.
+   */
+  var requestStopClearData = function() {
+    chrome.send('requestStopClearData');
   };
 
   /**
@@ -185,7 +192,8 @@
     setIncludeSpecifics: setIncludeSpecifics,
     writeUserEvent: writeUserEvent,
     requestStart: requestStart,
-    requestStop: requestStop,
+    requestStopKeepData: requestStopKeepData,
+    requestStopClearData: requestStopClearData,
     triggerRefresh: triggerRefresh,
   };
 });
diff --git a/content/browser/loader/cors_origin_access_list_browsertest.cc b/content/browser/loader/cors_origin_access_list_browsertest.cc
new file mode 100644
index 0000000..b832ca4
--- /dev/null
+++ b/content/browser/loader/cors_origin_access_list_browsertest.cc
@@ -0,0 +1,282 @@
+// Copyright 2018 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 <memory>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/base/host_port_pair.h"
+#include "net/dns/mock_host_resolver.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+namespace {
+
+const char kTestPath[] = "/loader/cors_origin_access_list_test.html";
+
+const char kTestHost[] = "crossorigin.example.com";
+const char kTestHostInDifferentCase[] = "CrossOrigin.example.com";
+const char kTestSubdomainHost[] = "subdomain.crossorigin.example.com";
+
+enum class TestMode {
+  kOutOfBlinkCorsWithServicification,
+  kOutOfBlinkCorsWithoutServicification,
+};
+
+// Tests end to end functionality of CORS access origin allow lists.
+class CorsOriginAccessListBrowserTest
+    : public ContentBrowserTest,
+      public testing::WithParamInterface<TestMode> {
+ public:
+  CorsOriginAccessListBrowserTest() {
+    switch (GetParam()) {
+      case TestMode::kOutOfBlinkCorsWithServicification:
+        scoped_feature_list_.InitWithFeatures(
+            // Enabled features
+            {network::features::kOutOfBlinkCORS,
+             network::features::kNetworkService,
+             blink::features::kServiceWorkerServicification},
+            // Disabled features
+            {});
+        break;
+      case TestMode::kOutOfBlinkCorsWithoutServicification:
+        scoped_feature_list_.InitWithFeatures(
+            // Enabled features
+            {network::features::kOutOfBlinkCORS},
+            // Disabled features
+            {network::features::kNetworkService,
+             blink::features::kServiceWorkerServicification});
+        break;
+    }
+  }
+
+ protected:
+  std::unique_ptr<TitleWatcher> CreateWatcher() {
+    // Register all possible result strings here.
+    std::unique_ptr<TitleWatcher> watcher =
+        std::make_unique<TitleWatcher>(shell()->web_contents(), pass_string());
+    watcher->AlsoWaitForTitle(fail_string());
+    return watcher;
+  }
+
+  std::string GetReason() {
+    bool executing = true;
+    std::string reason;
+    shell()->web_contents()->GetMainFrame()->ExecuteJavaScriptForTests(
+        script_,
+        base::BindRepeating(
+            [](bool* flag, std::string* reason, const base::Value* value) {
+              *flag = false;
+              DCHECK(value);
+              DCHECK(value->is_string());
+              *reason = value->GetString();
+            },
+            base::Unretained(&executing), base::Unretained(&reason)));
+    while (executing) {
+      base::RunLoop loop;
+      loop.RunUntilIdle();
+    }
+    return reason;
+  }
+
+  void SetAllowList(const std::string& scheme,
+                    const std::string& host,
+                    bool allow_subdomains) {
+    std::vector<network::mojom::CorsOriginPatternPtr> list1;
+    list1.push_back(
+        network::mojom::CorsOriginPattern::New(scheme, host, allow_subdomains));
+    bool first_list_done = false;
+    BrowserContext::SetCorsOriginAccessListsForOrigin(
+        shell()->web_contents()->GetBrowserContext(),
+        url::Origin::Create(embedded_test_server()->base_url().GetOrigin()),
+        std::move(list1), std::vector<network::mojom::CorsOriginPatternPtr>(),
+        base::BindOnce([](bool* flag) { *flag = true; },
+                       base::Unretained(&first_list_done)));
+
+    std::vector<network::mojom::CorsOriginPatternPtr> list2;
+    list2.push_back(
+        network::mojom::CorsOriginPattern::New(scheme, host, allow_subdomains));
+    bool second_list_done = false;
+    BrowserContext::SetCorsOriginAccessListsForOrigin(
+        shell()->web_contents()->GetBrowserContext(),
+        url::Origin::Create(
+            embedded_test_server()->GetURL(kTestHost, "/").GetOrigin()),
+        std::move(list2), std::vector<network::mojom::CorsOriginPatternPtr>(),
+        base::BindOnce([](bool* flag) { *flag = true; },
+                       base::Unretained(&second_list_done)));
+    while (!first_list_done || !second_list_done) {
+      base::RunLoop run_loop;
+      run_loop.RunUntilIdle();
+    }
+  }
+
+  std::string host_ip() { return embedded_test_server()->base_url().host(); }
+
+  const base::string16& pass_string() const { return pass_string_; }
+  const base::string16& fail_string() const { return fail_string_; }
+
+ private:
+  void SetUpOnMainThread() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    // Setup to resolve kTestHost, kTestHostInDifferentCase and
+    // kTestSubdomainHost to the 127.0.0.1 that the test server serves.
+    host_resolver()->AddRule(kTestHost,
+                             embedded_test_server()->host_port_pair().host());
+    host_resolver()->AddRule(kTestHostInDifferentCase,
+                             embedded_test_server()->host_port_pair().host());
+    host_resolver()->AddRule(kTestSubdomainHost,
+                             embedded_test_server()->host_port_pair().host());
+  }
+
+  const base::string16 pass_string_ = base::ASCIIToUTF16("PASS");
+  const base::string16 fail_string_ = base::ASCIIToUTF16("FAIL");
+  const base::string16 script_ = base::ASCIIToUTF16("reason");
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(CorsOriginAccessListBrowserTest);
+};
+
+// Tests if specifying only protocol allows all hosts to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest, AllowAll) {
+  SetAllowList("http", "", true);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                                 "%s?target=%s", kTestPath, kTestHost))));
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if specifying only protocol allows all IP address based hosts to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest, AllowAllForIp) {
+  SetAllowList("http", "", true);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   kTestHost, base::StringPrintf("%s?target=%s", kTestPath,
+                                                 host_ip().c_str()))));
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if complete allow list set allows only exactly matched host to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest, AllowExactHost) {
+  SetAllowList("http", kTestHost, false);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                                 "%s?target=%s", kTestPath, kTestHost))));
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if complete allow list set allows host that matches exactly, but in
+// case insensitive way to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest,
+                       AllowExactHostInCaseInsensitive) {
+  SetAllowList("http", kTestHost, false);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?target=%s", kTestPath, kTestHostInDifferentCase))));
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if complete allow list set does not allow a host with a different port
+// to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest, BlockDifferentPort) {
+  SetAllowList("http", kTestHost, false);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?target=%s&port_diff=1", kTestPath, kTestHost))));
+  EXPECT_EQ(fail_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if complete allow list set allows a subdomain to pass if it is allowed.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest, AllowSubdomain) {
+  SetAllowList("http", kTestHost, true);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?target=%s", kTestPath, kTestSubdomainHost))));
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if complete allow list set does not allow a subdomain to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest, BlockSubdomain) {
+  SetAllowList("http", kTestHost, false);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                   "%s?target=%s", kTestPath, kTestSubdomainHost))));
+  EXPECT_EQ(fail_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if complete allow list set does not allow a host with a different
+// protocol to pass.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest,
+                       BlockDifferentProtocol) {
+  SetAllowList("https", kTestHost, false);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL(base::StringPrintf(
+                                 "%s?target=%s", kTestPath, kTestHost))));
+  EXPECT_EQ(fail_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+// Tests if IP address based hosts should not follow subdomain match rules.
+IN_PROC_BROWSER_TEST_P(CorsOriginAccessListBrowserTest,
+                       SubdomainMatchShouldNotBeAppliedForIPAddress) {
+  SetAllowList("http", "*.0.0.1", true);
+
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL(
+                   kTestHost, base::StringPrintf("%s?target=%s", kTestPath,
+                                                 host_ip().c_str()))));
+  EXPECT_EQ(fail_string(), watcher->WaitAndGetTitle()) << GetReason();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    OutOfBlinkCorsWithServicification,
+    CorsOriginAccessListBrowserTest,
+    ::testing::Values(TestMode::kOutOfBlinkCorsWithServicification));
+
+INSTANTIATE_TEST_CASE_P(
+    OutOfBlinkCorsWithoutServicification,
+    CorsOriginAccessListBrowserTest,
+    ::testing::Values(TestMode::kOutOfBlinkCorsWithoutServicification));
+
+// TODO(toyoshim): Instantiates tests for the case kOutOfBlinkCORS is disabled
+// and remove relevant LayoutTests if it's possible.
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index 8a43939a..8796ec1 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -78,12 +78,14 @@
 #include "net/url_request/url_request_simple_job.h"
 #include "net/url_request/url_request_test_job.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/resource_scheduler.h"
 #include "services/network/resource_scheduler_params_manager.h"
 #include "services/network/test/test_url_loader_client.h"
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h"
 
 // TODO(eroman): Write unit tests for SafeBrowsing that exercise
@@ -632,9 +634,8 @@
 };
 
 enum class TestMode {
-  kOutOfBlinkCorsWithServicification,
-  kOutOfBlinkCorsWithoutServicification,
-  kWithoutOutOfBlinkCorsAndServicification,
+  kWithoutOutOfBlinkCors,
+  kWithOutOfBlinkCors,
 };
 
 class ResourceDispatcherHostTest : public testing::TestWithParam<TestMode> {
@@ -651,6 +652,23 @@
         use_test_ssl_certificate_(false),
         send_data_received_acks_(false),
         auto_advance_(false) {
+    switch (GetParam()) {
+      case TestMode::kWithoutOutOfBlinkCors:
+        scoped_feature_list_.InitWithFeatures(
+            // Enabled features
+            {},
+            // Disabled features
+            {network::features::kOutOfBlinkCORS});
+        break;
+      case TestMode::kWithOutOfBlinkCors:
+        scoped_feature_list_.InitWithFeatures(
+            // Enabled features
+            {network::features::kOutOfBlinkCORS,
+             blink::features::kServiceWorkerServicification},
+            // Disabled features
+            {});
+        break;
+    }
     host_.SetLoaderDelegate(&loader_delegate_);
     browser_context_.reset(new TestBrowserContext());
     BrowserContext::EnsureResourceContextInitialized(browser_context_.get());
@@ -890,6 +908,7 @@
   RenderViewHostTestEnabler render_view_host_test_enabler_;
   bool auto_advance_;
   scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 void ResourceDispatcherHostTest::MakeTestRequest(
@@ -1074,6 +1093,7 @@
   loader = nullptr;
 
   // From the renderer's perspective, the request was cancelled.
+  content::RunAllTasksUntilIdle();
   client.RunUntilComplete();
   EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
 
@@ -1118,8 +1138,8 @@
   DCHECK_EQ(filter_.get(), info_prefetch->requester_info()->filter());
   filter_->OnChannelClosing();
 
-  client1.RunUntilComplete();
-  EXPECT_EQ(net::ERR_ABORTED, client1.completion_status().error_code);
+  content::RunAllTasksUntilIdle();
+  DCHECK(IsAborted(client1));
 
   // But it continues detached.
   EXPECT_EQ(1, host_.pending_requests());
@@ -1167,8 +1187,8 @@
   EXPECT_EQ(1u, url_request->url_chain().size());
 
   // From the renderer's perspective, the request was cancelled.
-  client.RunUntilComplete();
-  EXPECT_EQ(net::ERR_ABORTED, client.completion_status().error_code);
+  content::RunAllTasksUntilIdle();
+  DCHECK(IsAborted(client));
 
   content::RunAllTasksUntilIdle();
   // Verify that a redirect was followed.
@@ -2524,19 +2544,12 @@
   return nullptr;
 }
 
-INSTANTIATE_TEST_CASE_P(
-    OutOfBlinkCorsWithServicification,
-    ResourceDispatcherHostTest,
-    ::testing::Values(TestMode::kOutOfBlinkCorsWithServicification));
+INSTANTIATE_TEST_CASE_P(WithoutOutOfBlinkCors,
+                        ResourceDispatcherHostTest,
+                        ::testing::Values(TestMode::kWithoutOutOfBlinkCors));
 
-INSTANTIATE_TEST_CASE_P(
-    OutOfBlinkCorsWithoutServicification,
-    ResourceDispatcherHostTest,
-    ::testing::Values(TestMode::kOutOfBlinkCorsWithoutServicification));
-
-INSTANTIATE_TEST_CASE_P(
-    WithoutOutOfBlinkCorsAndServicification,
-    ResourceDispatcherHostTest,
-    ::testing::Values(TestMode::kWithoutOutOfBlinkCorsAndServicification));
+INSTANTIATE_TEST_CASE_P(WithOutOfBlinkCors,
+                        ResourceDispatcherHostTest,
+                        ::testing::Values(TestMode::kWithOutOfBlinkCors));
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index f96311d..b5617e2 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -1232,11 +1232,6 @@
     const blink::WebGestureEvent& gesture_event,
     const ui::LatencyInfo& latency,
     const base::Optional<gfx::PointF>& target_location) {
-  // Temporary logging for https://crbug.com/824774.
-  static auto* target_source_key = base::debug::AllocateCrashKeyString(
-      "touchscreen-gesture-target-source", base::debug::CrashKeySize::Size32);
-  base::debug::SetCrashKeyString(target_source_key, "input");
-
   if (gesture_event.GetType() == blink::WebInputEvent::kGesturePinchBegin) {
     in_touchscreen_gesture_pinch_ = true;
     // If the root view wasn't already receiving the gesture stream, then we
@@ -1323,7 +1318,6 @@
     // unique_touch_event_id of 0.
     touchscreen_gesture_target_.target = target;
     touchscreen_gesture_target_in_map_ = IsViewInMap(target);
-    base::debug::SetCrashKeyString(target_source_key, "touch_id=0");
     touchscreen_gesture_target_.delta =
         target_location.has_value()
             ? target_location.value() - gesture_event.PositionInWidget()
@@ -1350,7 +1344,6 @@
     // this is the best we can do until we fix https://crbug.com/595422.
     touchscreen_gesture_target_.target = result.view;
     touchscreen_gesture_target_in_map_ = IsViewInMap(result.view);
-    base::debug::SetCrashKeyString(target_source_key, "no_matching_id");
     touchscreen_gesture_target_.delta = transformed_point - original_point;
   } else if (is_gesture_start) {
     touchscreen_gesture_target_ = gesture_target_it->second;
@@ -1382,26 +1375,6 @@
   blink::WebGestureEvent event(gesture_event);
   event.SetPositionInWidget(event.PositionInWidget() +
                             touchscreen_gesture_target_.delta);
-  // Temporary logging for https://crbug.com/824774.
-  static auto* target_ptr_key = base::debug::AllocateCrashKeyString(
-      "touchscreen-gesture-target-ptr", base::debug::CrashKeySize::Size64);
-  base::debug::SetCrashKeyString(
-      target_ptr_key,
-      base::StringPrintf("%p", touchscreen_gesture_target_.target));
-  static auto* root_ptr_key = base::debug::AllocateCrashKeyString(
-      "touchscreen-gesture-root-ptr", base::debug::CrashKeySize::Size64);
-  base::debug::SetCrashKeyString(root_ptr_key,
-                                 base::StringPrintf("%p", root_view));
-  static auto* target_ptr_in_map_key = base::debug::AllocateCrashKeyString(
-      "touchscreen-gesture-target-in-map", base::debug::CrashKeySize::Size32);
-  base::debug::SetCrashKeyString(
-      target_ptr_in_map_key,
-      touchscreen_gesture_target_in_map_ ? "true" : "false");
-  static auto* map_size_key = base::debug::AllocateCrashKeyString(
-      "touchscreen-gesture-map-size", base::debug::CrashKeySize::Size32);
-  base::debug::SetCrashKeyString(
-      map_size_key,
-      base::StringPrintf("%u", static_cast<int>(owner_map_.size())));
 
   if (events_being_flushed_) {
     touchscreen_gesture_target_.target->host()
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc
index 473bd8d..8b0dd73 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -15,8 +15,6 @@
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
-#include "content/public/common/content_features.h"
-#include "content/public/common/content_switches.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
 
@@ -45,42 +43,8 @@
   return true;
 }
 
-const char* ResponseTypeString(ServiceWorkerResponseType response_type) {
-  switch (response_type) {
-    case ServiceWorkerResponseType::NOT_DETERMINED:
-      return "NOT_DETERMINED";
-    case ServiceWorkerResponseType::FAIL_DUE_TO_LOST_CONTROLLER:
-      return "FAIL_DUE_TO_LOST_CONTROLLER";
-    case ServiceWorkerResponseType::FALLBACK_TO_NETWORK:
-      return "FALLBACK_TO_NETWORK";
-    case ServiceWorkerResponseType::FALLBACK_TO_RENDERER:
-      return "FALLBACK_TO_RENDERER";
-    case ServiceWorkerResponseType::FORWARD_TO_SERVICE_WORKER:
-      return "FORWARD_TO_SERVICE_WORKER";
-  }
-  NOTREACHED();
-  return "";
-}
-
 }  // namespace
 
-// static
-const char* ServiceWorkerNavigationLoader::StatusString(
-    ServiceWorkerNavigationLoader::Status status) {
-  switch (status) {
-    case ServiceWorkerNavigationLoader::Status::kNotStarted:
-      return "NotStarted";
-    case ServiceWorkerNavigationLoader::Status::kStarted:
-      return "Started";
-    case ServiceWorkerNavigationLoader::Status::kSentHeader:
-      return "SentHeader";
-    case ServiceWorkerNavigationLoader::Status::kCompleted:
-      return "Completed";
-  }
-  NOTREACHED();
-  return "";
-}
-
 // This class waits for completion of a stream response from the service worker.
 // It calls ServiceWorkerNavigationLoader::CommitCompleted() upon completion of
 // the response.
@@ -130,10 +94,6 @@
       url_loader_factory_getter_(std::move(url_loader_factory_getter)),
       binding_(this),
       weak_factory_(this) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    debug_log_ = base::make_optional<std::vector<std::string>>();
-  }
-
   TRACE_EVENT_WITH_FLOW1(
       "ServiceWorker",
       "ServiceWorkerNavigationLoader::ServiceWorkerNavigationloader", this,
@@ -169,23 +129,6 @@
   DCHECK_EQ(status_, Status::kNotStarted);
   DCHECK_EQ(response_type_, ResponseType::NOT_DETERMINED);
 
-  // https://crbug.com/887033
-  if (debug_log_) {
-    debug_log_->emplace_back(base::StringPrintf(
-        "FallbackToNW:%s->%s", ResponseTypeString(response_type_),
-        ResponseTypeString(ResponseType::FALLBACK_TO_NETWORK)));
-
-    if (!loader_callback_) {
-      std::string log;
-      for (const auto& entry : *debug_log_) {
-        log += entry + " ";
-      }
-      DEBUG_ALIAS_FOR_GURL(debug_url, resource_request_.url);
-      DEBUG_ALIAS_FOR_CSTR(debug_log, log.c_str(), 1024);
-      CHECK(false);
-    }
-  }
-
   response_type_ = ResponseType::FALLBACK_TO_NETWORK;
   TransitionToStatus(Status::kCompleted);
   std::move(loader_callback_).Run({});
@@ -198,25 +141,8 @@
   DCHECK_EQ(status_, Status::kNotStarted);
   DCHECK_EQ(response_type_, ResponseType::NOT_DETERMINED);
 
-  if (debug_log_) {
-    debug_log_->emplace_back(base::StringPrintf(
-        "ForwardToSW:%s->%s", ResponseTypeString(response_type_),
-        ResponseTypeString(ResponseType::FORWARD_TO_SERVICE_WORKER)));
-  }
-
   response_type_ = ResponseType::FORWARD_TO_SERVICE_WORKER;
 
-  // https://crbug.com/881826
-  if (!loader_callback_ && debug_log_) {
-    std::string log;
-    for (const auto& entry : *debug_log_) {
-      log += entry + " ";
-    }
-    DEBUG_ALIAS_FOR_GURL(debug_url, resource_request_.url);
-    DEBUG_ALIAS_FOR_CSTR(debug_log, log.c_str(), 1024);
-    CHECK(false);
-  }
-
   std::move(loader_callback_)
       .Run(base::BindOnce(&ServiceWorkerNavigationLoader::StartRequest,
                           weak_factory_.GetWeakPtr()));
@@ -231,9 +157,6 @@
 }
 
 void ServiceWorkerNavigationLoader::DetachedFromRequest() {
-  if (debug_log_)
-    debug_log_->emplace_back("DetachedFromRequest");
-
   delegate_ = nullptr;
   DeleteIfNeeded();
 }
@@ -564,9 +487,6 @@
       "ServiceWorker", "ServiceWorkerNavigationLoader::OnConnectionClosed",
       this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
 
-  if (debug_log_)
-    debug_log_->emplace_back("ConnectionClosed");
-
   // The fetch dispatcher or stream waiter may still be running. Don't let them
   // do callbacks back to this loader, since it is now done with the request.
   // TODO(falken): Try to move this to CommitCompleted(), since the same
@@ -613,11 +533,6 @@
   }
 #endif  // DCHECK_IS_ON()
 
-  if (debug_log_) {
-    debug_log_->emplace_back(base::StringPrintf(
-        "Status:%s->%s", StatusString(status_), StatusString(new_status)));
-  }
-
   status_ = new_status;
 }
 
diff --git a/content/browser/service_worker/service_worker_navigation_loader.h b/content/browser/service_worker/service_worker_navigation_loader.h
index dac4eda..b839fe3 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.h
+++ b/content/browser/service_worker/service_worker_navigation_loader.h
@@ -114,8 +114,6 @@
     kCompleted,
   };
 
-  static const char* StatusString(Status status);
-
   // For FORWARD_TO_SERVICE_WORKER case.
   void StartRequest(const network::ResourceRequest& resource_request,
                     network::mojom::URLLoaderRequest request,
@@ -188,9 +186,6 @@
 
   Status status_ = Status::kNotStarted;
 
-  // https://crbug.com/881826
-  base::Optional<std::vector<std::string>> debug_log_;
-
   base::WeakPtrFactory<ServiceWorkerNavigationLoader> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerNavigationLoader);
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc
index a1990c56..59cfcaf 100644
--- a/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -673,7 +673,7 @@
       return TraceConfig("blink.console,v8", record_mode);
     case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_NAVIGATION: {
       auto config = TraceConfig(
-          "benchmark,toplevel,ipc,base,browser,navigation,omnibox,"
+          "benchmark,toplevel,ipc,base,browser,navigation,omnibox,ui,"
           "safe_browsing,task_scheduler,"
           "disabled-by-default-task_scheduler_diagnostics,"
           "disabled-by-default-system_stats,disabled-by-default-cpu_profiler",
diff --git a/content/renderer/gpu/layer_tree_view.cc b/content/renderer/gpu/layer_tree_view.cc
index a26b36d..8f103f1 100644
--- a/content/renderer/gpu/layer_tree_view.cc
+++ b/content/renderer/gpu/layer_tree_view.cc
@@ -669,10 +669,6 @@
   delegate_->DidCommitAndDrawCompositorFrame();
 }
 
-void LayerTreeView::DidReceiveCompositorFrameAck() {
-  delegate_->DidReceiveCompositorFrameAck();
-}
-
 void LayerTreeView::DidCompletePageScaleAnimation() {
   delegate_->DidCompletePageScaleAnimation();
 }
diff --git a/content/renderer/gpu/layer_tree_view.h b/content/renderer/gpu/layer_tree_view.h
index 820d1a2..efe85bf 100644
--- a/content/renderer/gpu/layer_tree_view.h
+++ b/content/renderer/gpu/layer_tree_view.h
@@ -192,7 +192,7 @@
   void WillCommit() override;
   void DidCommit() override;
   void DidCommitAndDrawFrame() override;
-  void DidReceiveCompositorFrameAck() override;
+  void DidReceiveCompositorFrameAck() override {}
   void DidCompletePageScaleAnimation() override;
   void DidPresentCompositorFrame(
       uint32_t frame_token,
diff --git a/content/renderer/gpu/layer_tree_view_delegate.h b/content/renderer/gpu/layer_tree_view_delegate.h
index d28c056..2ef7d29 100644
--- a/content/renderer/gpu/layer_tree_view_delegate.h
+++ b/content/renderer/gpu/layer_tree_view_delegate.h
@@ -65,10 +65,6 @@
   // Called by the compositor when page scale animation completed.
   virtual void DidCompletePageScaleAnimation() = 0;
 
-  // Notifies that the last submitted CompositorFrame has been processed and
-  // will be displayed.
-  virtual void DidReceiveCompositorFrameAck() = 0;
-
   // Requests that a UMA and UKM metric be recorded for the total frame time.
   // Call this as soon as the total frame time becomes known for a given frame.
   // For example, ProxyMain::BeginMainFrame calls it immediately before aborting
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 6c47cf9..055afd0 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1013,9 +1013,6 @@
     owner_delegate_->DidCompletePageScaleAnimationForWidget();
 }
 
-void RenderWidget::DidReceiveCompositorFrameAck() {
-}
-
 bool RenderWidget::IsClosing() const {
   // TODO(ajwong): There is oddly 2 closing states. This API is used by
   // LayerTreeView only as part of the LayerTreeViewDelegate interface and
@@ -2782,6 +2779,9 @@
 
   settings.always_request_presentation_time =
       cmd.HasSwitch(cc::switches::kAlwaysRequestPresentationTime);
+
+  settings.send_compositor_frame_ack = false;
+
   return settings;
 }
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index bf86407..a4e2bd18 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -270,7 +270,6 @@
   void DidCommitAndDrawCompositorFrame() override;
   void DidCommitCompositorFrame() override;
   void DidCompletePageScaleAnimation() override;
-  void DidReceiveCompositorFrameAck() override;
   void RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time) override;
   bool IsClosing() const override;
   void RequestScheduleAnimation() override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 33be50bfa..2e6242e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -781,6 +781,7 @@
     "../browser/keyboard_lock_browsertest.h",
     "../browser/keyboard_lock_browsertest_mac.mm",
     "../browser/loader/cors_file_origin_browsertest.cc",
+    "../browser/loader/cors_origin_access_list_browsertest.cc",
     "../browser/loader/cross_site_document_blocking_browsertest.cc",
     "../browser/loader/loader_browsertest.cc",
     "../browser/loader/prefetch_browsertest.cc",
diff --git a/content/test/data/loader/cors_origin_access_list_test.html b/content/test/data/loader/cors_origin_access_list_test.html
new file mode 100644
index 0000000..7195158
--- /dev/null
+++ b/content/test/data/loader/cors_origin_access_list_test.html
@@ -0,0 +1,66 @@
+<html>
+<head>
+<title>CorsOriginAccessListBrowserTest</title>
+</head>
+<body>
+<script>
+window.reason = 'Probably failed to parse JavaScript';
+
+const queryMap = {};
+for (const item of location.search.substr(1).split('&')) {
+  const [key, value] = item.split('=');
+  queryMap[key] = value;
+}
+
+function log(message) {
+  window.reason += '\n' + message;
+}
+
+function pass(message) {
+  log(message);
+  document.title = "PASS";
+}
+
+function fail(message) {
+  log(message);
+  document.title = "FAIL";
+}
+
+function test(target) {
+  const url = [
+    location.protocol,
+    '//',
+    target,
+    ':',
+    Number(location.port) + Number(queryMap.port_diff || 0),
+    '/loader/get.txt'
+  ].join('');
+
+  log('Testing: ' + url + ' (sync)');
+  let req = new XMLHttpRequest();
+  req.open('GET', url, false);
+  try {
+    req.send(null);
+    log('PASS: ' + req.responseText);
+  } catch (e) {
+    fail('FAIL: ' + e);
+    return;
+  }
+
+  log('Testing: ' + url + ' (async)');
+  req = new XMLHttpRequest();
+  req.open('GET', url, true);
+  req.onload = function() {
+    pass('PASS: ' + req.responseText);
+  };
+  req.onerror = function() {
+    fail('FAIL: ' + req.status);
+  };
+  req.send(null);
+}
+
+window.reason = '';
+test(queryMap.target);
+</script>
+</body>
+</html>
diff --git a/content/test/data/loader/get.txt b/content/test/data/loader/get.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/content/test/data/loader/get.txt
diff --git a/content/test/stub_layer_tree_view_delegate.h b/content/test/stub_layer_tree_view_delegate.h
index 83bba53..a2545a6 100644
--- a/content/test/stub_layer_tree_view_delegate.h
+++ b/content/test/stub_layer_tree_view_delegate.h
@@ -26,7 +26,6 @@
   void DidCommitAndDrawCompositorFrame() override {}
   void DidCommitCompositorFrame() override {}
   void DidCompletePageScaleAnimation() override {}
-  void DidReceiveCompositorFrameAck() override {}
   bool IsClosing() const override;
   void RequestScheduleAnimation() override {}
   void UpdateVisualState() override {}
diff --git a/docs/clang_tidy.md b/docs/clang_tidy.md
index 1a881d85..10f5fc3b 100644
--- a/docs/clang_tidy.md
+++ b/docs/clang_tidy.md
@@ -47,7 +47,8 @@
 ## Running clang-tidy
 
 Running clang-tidy is (hopefully) simple.
-1.  Build chrome normally.\*
+1.  Build chrome normally.\* Note that [Jumbo builds](jumbo.md) are not
+    supported.
 ```
 ninja -C out/Release chrome
 ```
@@ -87,9 +88,9 @@
     chrome/browser
 ```
 
-\*It's not clear which, if any, `gn` flags may cause issues for `clang-tidy`.
-I've had no problems building a component release build, both with and without
-goma. if you run into issues, let us know!
+\*It's not clear which, if any, `gn` flags outside of `use_jumbo_build` may
+cause issues for `clang-tidy`. I've had no problems building a component release
+build, both with and without goma. if you run into issues, let us know!
 
 ## Questions
 
diff --git a/docs/updating_clang.md b/docs/updating_clang.md
index 3acf13c2..0e8d6b9 100644
--- a/docs/updating_clang.md
+++ b/docs/updating_clang.md
@@ -52,7 +52,8 @@
     git cl try -B luci.chromium.try -b ios-device -b mac_chromium_asan_rel_ng \
       -b linux_chromium_cfi_rel_ng \
       -b linux_chromium_chromeos_asan_rel_ng -b linux_chromium_msan_rel_ng \
-      -b linux_chromium_chromeos_msan_rel_ng -b linux-chromeos-dbg
+      -b linux_chromium_chromeos_msan_rel_ng -b linux-chromeos-dbg \
+      -b win-asan
     ```
 
 1.  Optional: Start Pinpoint perf tryjobs. These are generally too noisy to
diff --git a/extensions/browser/api/alarms/alarms_api_unittest.cc b/extensions/browser/api/alarms/alarms_api_unittest.cc
index efe47f5..74517e8 100644
--- a/extensions/browser/api/alarms/alarms_api_unittest.cc
+++ b/extensions/browser/api/alarms/alarms_api_unittest.cc
@@ -15,8 +15,8 @@
 #include "extensions/browser/api/alarms/alarm_manager.h"
 #include "extensions/browser/api/alarms/alarms_api.h"
 #include "extensions/browser/api/alarms/alarms_api_constants.h"
-#include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/api_unittest.h"
+#include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_messages.h"
 #include "ipc/ipc_test_sink.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -26,8 +26,6 @@
 
 namespace extensions {
 
-namespace utils = api_test_utils;
-
 namespace {
 
 // Test delegate which quits the message loop when an alarm fires.
@@ -582,7 +580,7 @@
 
 TEST_F(ExtensionAlarmsSchedulingTest, ReleasedExtensionPollsInfrequently) {
   set_extension(
-      utils::CreateEmptyExtensionWithLocation(extensions::Manifest::INTERNAL));
+      ExtensionBuilder("Test").SetLocation(Manifest::INTERNAL).Build());
   test_clock_.SetNow(base::Time::FromJsTime(300000));
   CreateAlarm("[\"a\", {\"when\": 300010}]");
   CreateAlarm("[\"b\", {\"when\": 340000}]");
@@ -616,7 +614,7 @@
 
 TEST_F(ExtensionAlarmsSchedulingTest, MinimumGranularity) {
   set_extension(
-      utils::CreateEmptyExtensionWithLocation(extensions::Manifest::INTERNAL));
+      ExtensionBuilder("Test").SetLocation(Manifest::INTERNAL).Build());
   test_clock_.SetNow(base::Time::FromJsTime(0));
   CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
   test_clock_.Advance(base::TimeDelta::FromSeconds(1));
@@ -644,7 +642,7 @@
   // repopulate extension_.
   scoped_refptr<const Extension> extension2(extension_ref());
   set_extension(
-      utils::CreateEmptyExtensionWithLocation(extensions::Manifest::INTERNAL));
+      ExtensionBuilder("Test").SetLocation(Manifest::INTERNAL).Build());
 
   CreateAlarm("[\"b\", {\"periodInMinutes\": 2}]");
 
diff --git a/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc b/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc
index e24d8b3..a963b45 100644
--- a/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc
+++ b/extensions/browser/api/runtime/restart_after_delay_api_unittest.cc
@@ -14,6 +14,7 @@
 #include "extensions/browser/api_unittest.h"
 #include "extensions/browser/test_extensions_browser_client.h"
 #include "extensions/browser/test_runtime_api_delegate.h"
+#include "extensions/common/extension_builder.h"
 #include "extensions/common/manifest.h"
 
 namespace extensions {
@@ -199,18 +200,10 @@
 
   // Create another extension and make it attempt to use the api, and expect a
   // failure.
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary("{\n"
-                                      "  \"name\": \"Test\",\n"
-                                      "  \"version\": \"2.0\",\n"
-                                      "  \"app\": {\n"
-                                      "    \"background\": {\n"
-                                      "      \"scripts\": [\"background.js\"]\n"
-                                      "    }\n"
-                                      "  }\n"
-                                      "}"));
-  scoped_refptr<Extension> test_extension(api_test_utils::CreateExtension(
-      Manifest::INTERNAL, test_extension_value.get(), "id2"));
+  scoped_refptr<const Extension> test_extension =
+      ExtensionBuilder("Another App", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetLocation(Manifest::INTERNAL)
+          .Build();
   RunRestartAfterDelayFunctionForExtention(
       "[5]", test_extension.get(), "Not the first extension to call this API.");
 
diff --git a/extensions/browser/api/system_display/system_display_apitest.cc b/extensions/browser/api/system_display/system_display_apitest.cc
index 455341ea..911a594ca 100644
--- a/extensions/browser/api/system_display/system_display_apitest.cc
+++ b/extensions/browser/api/system_display/system_display_apitest.cc
@@ -17,6 +17,7 @@
 #include "extensions/browser/api/system_display/system_display_api.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/common/api/system_display.h"
+#include "extensions/common/extension_builder.h"
 #include "extensions/shell/test/shell_apitest.h"
 #include "extensions/test/result_catcher.h"
 #include "ui/display/display.h"
@@ -262,37 +263,12 @@
 
 #else  // !defined(OS_CHROMEOS)
 
-constexpr char kTestManifest[] =
-    "{\n"
-    "  \"name\": \"Test\",\n"
-    "  \"version\": \"1.0\",\n"
-    "  \"app\": {\n"
-    "    \"background\": {\n"
-    "      \"scripts\": [\"background.js\"]\n"
-    "    }\n"
-    "  }\n"
-    "}";
-
-constexpr char kTestManifestKiosk[] =
-    "{\n"
-    "  \"name\": \"Test\",\n"
-    "  \"version\": \"1.0\",\n"
-    "  \"app\": {\n"
-    "    \"background\": {\n"
-    "      \"scripts\": [\"background.js\"]\n"
-    "    }\n"
-    "  },\n"
-    "  \"kiosk_enabled\": true\n"
-    "}";
-
 // TODO(stevenjb): Add API tests for {GS}etDisplayLayout. That code currently
 // lives in src/chrome but should be getting moved soon.
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplayNotKioskEnabled) {
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifest));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP).Build();
 
   scoped_refptr<SystemDisplaySetDisplayPropertiesFunction> set_info_function(
       new SystemDisplaySetDisplayPropertiesFunction());
@@ -311,10 +287,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplayKioskEnabled) {
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifestKiosk));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetManifestKey("kiosk_enabled", true)
+          .Build();
 
   scoped_refptr<SystemDisplaySetDisplayPropertiesFunction> set_info_function(
       new SystemDisplaySetDisplayPropertiesFunction());
@@ -354,10 +330,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, EnableUnifiedDesktop) {
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifestKiosk));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetManifestKey("kiosk_enabled", true)
+          .Build();
   {
     scoped_refptr<SystemDisplayEnableUnifiedDesktopFunction>
         enable_unified_function(
@@ -387,10 +363,10 @@
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, OverscanCalibrationStart) {
   const std::string id = "display0";
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifestKiosk));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetManifestKey("kiosk_enabled", true)
+          .Build();
 
   // Setup MockDisplayInfoProvider.
   api::system_display::DisplayProperties params;
@@ -451,10 +427,10 @@
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, ShowNativeTouchCalibrationFail) {
   const std::string id = "display0";
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifestKiosk));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetManifestKey("kiosk_enabled", true)
+          .Build();
 
   scoped_refptr<SystemDisplayShowNativeTouchCalibrationFunction>
       show_native_calibration(
@@ -473,10 +449,10 @@
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, ShowNativeTouchCalibration) {
   const std::string id = "display0";
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifestKiosk));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetManifestKey("kiosk_enabled", true)
+          .Build();
 
   scoped_refptr<SystemDisplayShowNativeTouchCalibrationFunction>
       show_native_calibration(
@@ -498,10 +474,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetMirrorMode) {
-  std::unique_ptr<base::DictionaryValue> test_extension_value(
-      api_test_utils::ParseDictionary(kTestManifestKiosk));
-  scoped_refptr<Extension> test_extension(
-      api_test_utils::CreateExtension(test_extension_value.get()));
+  scoped_refptr<Extension> test_extension =
+      ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
+          .SetManifestKey("kiosk_enabled", true)
+          .Build();
   {
     auto set_mirror_mode_function =
         base::MakeRefCounted<SystemDisplaySetMirrorModeFunction>();
diff --git a/extensions/browser/api_test_utils.cc b/extensions/browser/api_test_utils.cc
index 1dcf8236..ef60fd5 100644
--- a/extensions/browser/api_test_utils.cc
+++ b/extensions/browser/api_test_utils.cc
@@ -15,7 +15,6 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_function_dispatcher.h"
-#include "extensions/common/extension_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::ExtensionFunctionDispatcher;
@@ -89,40 +88,6 @@
   return result;
 }
 
-scoped_refptr<Extension> CreateExtension(
-    Manifest::Location location,
-    base::DictionaryValue* test_extension_value,
-    const std::string& id_input) {
-  std::string error;
-  const base::FilePath test_extension_path;
-  std::string id;
-  if (!id_input.empty())
-    id = crx_file::id_util::GenerateId(id_input);
-  scoped_refptr<Extension> extension(
-      Extension::Create(test_extension_path, location, *test_extension_value,
-                        Extension::NO_FLAGS, id, &error));
-  EXPECT_TRUE(error.empty()) << "Could not parse test extension " << error;
-  return extension;
-}
-
-scoped_refptr<Extension> CreateExtension(
-    base::DictionaryValue* test_extension_value) {
-  return CreateExtension(Manifest::INTERNAL, test_extension_value,
-                         std::string());
-}
-
-scoped_refptr<Extension> CreateEmptyExtensionWithLocation(
-    Manifest::Location location) {
-  std::unique_ptr<base::DictionaryValue> test_extension_value =
-      ParseDictionary(R"(
-          {
-            "name": "Test",
-            "version": "1.0",
-            "manifest_version": 2
-          })");
-  return CreateExtension(location, test_extension_value.get(), std::string());
-}
-
 std::unique_ptr<base::Value> RunFunctionWithDelegateAndReturnSingleResult(
     scoped_refptr<UIThreadExtensionFunction> function,
     const std::string& args,
diff --git a/extensions/browser/api_test_utils.h b/extensions/browser/api_test_utils.h
index c1501b47..90957e1 100644
--- a/extensions/browser/api_test_utils.h
+++ b/extensions/browser/api_test_utils.h
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "extensions/browser/extension_function.h"
-#include "extensions/common/manifest.h"
 
 namespace base {
 class DictionaryValue;
@@ -24,7 +23,6 @@
 }
 
 namespace extensions {
-class Extension;
 class ExtensionFunctionDispatcher;
 
 // TODO(yoz): crbug.com/394840: Remove duplicate functionality in
@@ -74,21 +72,6 @@
 int GetInteger(const base::DictionaryValue* val, const std::string& key);
 std::string GetString(const base::DictionaryValue* val, const std::string& key);
 
-// Creates an extension instance with a specified extension value that can be
-// attached to an ExtensionFunction before running.
-scoped_refptr<extensions::Extension> CreateExtension(
-    base::DictionaryValue* test_extension_value);
-
-scoped_refptr<extensions::Extension> CreateExtension(
-    extensions::Manifest::Location location,
-    base::DictionaryValue* test_extension_value,
-    const std::string& id_input);
-
-// Creates an extension instance with a specified location that can be attached
-// to an ExtensionFunction before running.
-scoped_refptr<extensions::Extension> CreateEmptyExtensionWithLocation(
-    extensions::Manifest::Location location);
-
 // Run |function| with |args| and return the result. Adds an error to the
 // current test if |function| returns an error. Takes ownership of
 // |function|. The caller takes ownership of the result.
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc
index e08d757..1446bb3 100644
--- a/headless/lib/headless_content_main_delegate.cc
+++ b/headless/lib/headless_content_main_delegate.cc
@@ -282,8 +282,8 @@
 
   browser_->RunOnStartCallback();
   browser_runner->Run();
-  browser_.reset();
   browser_runner->Shutdown();
+  browser_.reset();
 
   // Return value >=0 here to disable calling content::BrowserMain.
   return 0;
diff --git a/infra/config/branch/cq.cfg b/infra/config/branch/cq.cfg
index 5d5b052..7b7db9c5 100644
--- a/infra/config/branch/cq.cfg
+++ b/infra/config/branch/cq.cfg
@@ -31,11 +31,7 @@
     buckets {
       name: "luci.chromium.try"
       builders { name: "android_arm64_dbg_recipe" }
-      # https://crbug.com/702625
-      builders {
-        name: "android-binary-size"
-        experiment_percentage: 100
-      }
+      builders { name: "android-binary-size" }
       builders { name: "android_clang_dbg_recipe" }
       builders { name: "android_compile_dbg" }
       builders { name: "android_cronet" }
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 416aedb3..7516b4bf 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -3337,11 +3337,31 @@
 
     # Win
 
-    builders { mixins: "win"  name: "WebRTC Chromium FYI Win Builder" }
-    builders { mixins: "win"  name: "WebRTC Chromium FYI Win Builder (dbg)" }
-    builders { mixins: "win"  name: "WebRTC Chromium FYI Win10 Tester" }
-    builders { mixins: "win"  name: "WebRTC Chromium FYI Win7 Tester" }
-    builders { mixins: "win"  name: "WebRTC Chromium FYI Win8 Tester" }
+    builders {
+      mixins: "win"
+      name: "WebRTC Chromium FYI Win Builder"
+      dimensions: "os:Windows-10"
+    }
+    builders {
+      mixins: "win"
+      name: "WebRTC Chromium FYI Win Builder (dbg)"
+      dimensions: "os:Windows-10"
+    }
+    builders {
+      mixins: "win"
+      name: "WebRTC Chromium FYI Win10 Tester"
+      dimensions: "os:Windows-10"
+    }
+    builders {
+      mixins: "win"
+      name: "WebRTC Chromium FYI Win7 Tester"
+      dimensions: "os:Windows-7"
+    }
+    builders {
+      mixins: "win"
+      name: "WebRTC Chromium FYI Win8 Tester"
+      dimensions: "os:Windows-8.1"
+    }
   }
 }
 
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index fe7f78e7..d4fe5e5d 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -286,7 +286,16 @@
 
   bundle_deps = [ "//ios/chrome/app/resources" ]
   if (!is_chrome_branded || ios_chrome_app_variants == []) {
+    assert(ios_application_icons_target != "",
+           "ios_application_icons_target must be defined.")
     bundle_deps += [ ios_application_icons_target ]
+
+    if (ios_enable_firebase_sdk) {
+      assert(ios_firebase_resources_target != "",
+             "ios_firebase_resources_target must be defined if Firebase SDK " +
+                 "is enabled.")
+      bundle_deps += [ ios_firebase_resources_target ]
+    }
   } else {
     variants = ios_chrome_app_variants
   }
diff --git a/ios/chrome/app/resources/Info.plist b/ios/chrome/app/resources/Info.plist
index aae2d8c..98996f7 100644
--- a/ios/chrome/app/resources/Info.plist
+++ b/ios/chrome/app/resources/Info.plist
@@ -189,5 +189,7 @@
 	<string>IDS_IOS_PHOTO_LIBRARY_ADD_USAGE_DESCRIPTION</string>
 	<key>NSBluetoothPeripheralUsageDescription</key>
 	<string>IDS_IOS_BLUETOOTH_USAGE_DESCRIPTION</string>
+	<key>NSFaceIDUsageDescription</key>
+	<string>IDS_IOS_FACE_ID_USAGE_DESCRIPTION</string>
 </dict>
 </plist>
diff --git a/ios/chrome/app/resources/chrome_localize_strings_config.plist b/ios/chrome/app/resources/chrome_localize_strings_config.plist
index 723bc6e..39f2200 100644
--- a/ios/chrome/app/resources/chrome_localize_strings_config.plist
+++ b/ios/chrome/app/resources/chrome_localize_strings_config.plist
@@ -64,7 +64,12 @@
 					<key>output</key>
 					<string>NSPhotoLibraryAddUsageDescription</string>
 				</dict>
-
+				<dict>
+					<key>input</key>
+					<string>IDS_IOS_FACE_ID_USAGE_DESCRIPTION</string>
+					<key>output</key>
+					<string>NSFaceIDUsageDescription</string>
+				</dict>
 				<string>IDS_IOS_APPLICATION_SHORTCUT_NEWTAB_TITLE</string>
 				<string>IDS_IOS_APPLICATION_SHORTCUT_NEWINCOGNITOTAB_TITLE</string>
 				<string>IDS_IOS_APPLICATION_SHORTCUT_VOICE_SEARCH_TITLE</string>
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index 8ad7b9e..19d5623 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -174,6 +174,9 @@
       <message name="IDS_IOS_DISCONNECT_DIALOG_TITLE" desc="The title of the disconnect dialog [Length: 30em].">
         Sign out of Chromium?
       </message>
+      <message name="IDS_IOS_FACE_ID_USAGE_DESCRIPTION" desc="Specifies the reason for using the device's Face ID capabilities.">
+        Chromium uses Face ID to ensure authorized access to your passwords.
+      </message>
       <message name="IDS_IOS_FIRSTRUN_AGREE_TO_TERMS" desc="Label containing a link to the Terms of Service and Privacy Notice, displayed in the first run flow. [Length: 117em] [iOS only]">
         By using this application, you agree to Chromium’s <ph name="BEGIN_LINK_TOS">BEGIN_LINK_TOS</ph>Terms of Service<ph name="END_LINK_TOS">END_LINK_TOS</ph> and <ph name="BEGIN_LINK_PRIVACY">BEGIN_LINK_PRIVACY</ph>Privacy Notice<ph name="END_LINK_PRIVACY">END_LINK_PRIVACY</ph>.
       </message>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index 7480ff25..9d5c5504 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -174,6 +174,9 @@
       <message name="IDS_IOS_DISCONNECT_DIALOG_TITLE" desc="The title of the disconnect dialog [Length: 30em].">
         Sign out of Chrome?
       </message>
+      <message name="IDS_IOS_FACE_ID_USAGE_DESCRIPTION" desc="Specifies the reason for using the device's Face ID capabilities.">
+        Chrome uses Face ID to ensure authorized access to your passwords.
+      </message>
       <message name="IDS_IOS_FIRSTRUN_AGREE_TO_TERMS" desc="Label containing a link to the Terms of Service and Privacy Notice, displayed in the first run flow. [Length: 117em] [iOS only]">
       By using this application, you agree to Chrome’s <ph name="BEGIN_LINK_TOS">BEGIN_LINK_TOS</ph>Terms of Service<ph name="END_LINK_TOS">END_LINK_TOS</ph> and <ph name="BEGIN_LINK_PRIVACY">BEGIN_LINK_PRIVACY</ph>Privacy Notice<ph name="END_LINK_PRIVACY">END_LINK_PRIVACY</ph>.
       </message>
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index c732355..e1d3ada 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -50,7 +50,6 @@
   "+components/password_manager/core/browser",
   "+components/password_manager/core/common",
   "+components/password_manager/ios",
-  "+components/password_manager/sync/browser",
   "+components/payments/core",
   "+components/payments/mojom",
   "+components/pref_registry",
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 73c35364..2c8f350c 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -68,7 +68,6 @@
     "//components/metrics",
     "//components/net_log",
     "//components/password_manager/core/browser",
-    "//components/password_manager/sync/browser",
     "//components/pref_registry",
     "//components/prefs",
     "//components/proxy_config",
diff --git a/ios/chrome/browser/download/browser_download_service.h b/ios/chrome/browser/download/browser_download_service.h
index dd8934a2..d8b9258 100644
--- a/ios/chrome/browser/download/browser_download_service.h
+++ b/ios/chrome/browser/download/browser_download_service.h
@@ -38,7 +38,9 @@
   VirtualContactFile = 6,
   // text/calendar MIME type.
   iCalendar = 7,
-  kMaxValue = iCalendar,
+  // model/usd MIME type.
+  UniversalSceneDescription = 8,
+  kMaxValue = UniversalSceneDescription,
 };
 
 // Keyed Service which acts as web::DownloadController delegate and routes
diff --git a/ios/chrome/browser/download/browser_download_service.mm b/ios/chrome/browser/download/browser_download_service.mm
index 497ee29..79fc9e27 100644
--- a/ios/chrome/browser/download/browser_download_service.mm
+++ b/ios/chrome/browser/download/browser_download_service.mm
@@ -39,6 +39,9 @@
   if (mime_type == "text/calendar")
     return DownloadMimeTypeResult::iCalendar;
 
+  if (mime_type == "model/usd")
+    return DownloadMimeTypeResult::UniversalSceneDescription;
+
   return DownloadMimeTypeResult::Other;
 }
 }  // namespace
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 2f3e320..9d8db88 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -58,7 +58,6 @@
     "//components/password_manager/core/browser/form_parsing",
     "//components/password_manager/core/common",
     "//components/password_manager/ios",
-    "//components/password_manager/sync/browser",
     "//components/prefs",
     "//components/security_state/core",
     "//components/signin/core/browser",
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
index 528479b2..927342de 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
@@ -9,7 +9,7 @@
 #import "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_client_helper.h"
 #include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
-#include "components/password_manager/sync/browser/sync_credentials_filter.h"
+#include "components/password_manager/core/browser/sync_credentials_filter.h"
 #include "components/prefs/pref_member.h"
 
 namespace ios {
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn
index 17c2bda..bd154f84 100644
--- a/ios/chrome/browser/sync/BUILD.gn
+++ b/ios/chrome/browser/sync/BUILD.gn
@@ -44,7 +44,6 @@
     "//components/keyed_service/ios",
     "//components/network_time",
     "//components/password_manager/core/browser",
-    "//components/password_manager/sync/browser",
     "//components/pref_registry",
     "//components/prefs",
     "//components/reading_list/core",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 014c4a50..00f3291 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -31,8 +31,8 @@
 #include "components/history/core/browser/typed_url_sync_bridge.h"
 #include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/keyed_service/core/service_access_type.h"
+#include "components/password_manager/core/browser/password_model_worker.h"
 #include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/sync/browser/password_model_worker.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/search_engines/search_engine_data_type_controller.h"
 #include "components/sync/base/report_unrecoverable_error.h"
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index a9313e58..5494e16 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -46,30 +46,11 @@
   ]
   deps = [
     ":bookmarks_ui",
-    "resources:bookmark_bar_innershadow",
     "resources:bookmark_bar_shadow",
-    "resources:bookmark_black_delete",
-    "resources:bookmark_black_edit",
-    "resources:bookmark_black_move",
-    "resources:bookmark_black_select",
     "resources:bookmark_blue_check",
     "resources:bookmark_blue_folder",
     "resources:bookmark_blue_new_folder",
     "resources:bookmark_empty_star",
-    "resources:bookmark_gray_back",
-    "resources:bookmark_gray_check",
-    "resources:bookmark_gray_close",
-    "resources:bookmark_gray_edit",
-    "resources:bookmark_gray_folder",
-    "resources:bookmark_gray_folder_new",
-    "resources:bookmark_gray_menu",
-    "resources:bookmark_gray_new_folder",
-    "resources:bookmark_gray_star_large",
-    "resources:bookmark_more",
-    "resources:bookmark_white_close",
-    "resources:bookmark_white_delete",
-    "resources:bookmark_white_edit",
-    "resources:bookmark_white_move",
     "//base",
     "//base:i18n",
     "//components/bookmarks/browser",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
index 3ab820a..01dc0dc 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -38,11 +38,6 @@
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/text_field_styling.h"
-#import "ios/third_party/material_components_ios/src/components/Buttons/src/MDCFlatButton.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
@@ -183,15 +178,8 @@
                     browserState:(ios::ChromeBrowserState*)browserState {
   DCHECK(bookmark);
   DCHECK(browserState);
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleNoAppBar];
-  } else {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleWithAppBar];
-  }
+  self = [super initWithTableViewStyle:UITableViewStylePlain
+                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
   if (self) {
     DCHECK(!bookmark->is_folder());
     DCHECK(!browserState->IsOffTheRecord());
@@ -227,17 +215,12 @@
       kEstimatedTableSectionFooterHeight;
   self.view.accessibilityIdentifier = kBookmarkEditViewContainerIdentifier;
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    // Add a tableFooterView in order to disable separators at the bottom of the
-    // tableView.
-    self.tableView.tableFooterView = [[UIView alloc] init];
-    [self.tableView
-        setSeparatorInset:UIEdgeInsetsMake(
-                              0, kBookmarkCellHorizontalLeadingInset, 0, 0)];
-  } else {
-    self.navigationController.navigationBarHidden = YES;
-    [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
-  }
+  // Add a tableFooterView in order to disable separators at the bottom of the
+  // tableView.
+  self.tableView.tableFooterView = [[UIView alloc] init];
+  [self.tableView
+      setSeparatorInset:UIEdgeInsetsMake(0, kBookmarkCellHorizontalLeadingInset,
+                                         0, 0)];
 
   self.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_EDIT_SCREEN_TITLE);
 
@@ -274,28 +257,13 @@
                            target:nil
                            action:nil];
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    deleteButton.tintColor = [UIColor redColor];
-    // Setting the image to nil will cause the default shadowImage to be used,
-    // we need to create a new one.
-    [self.navigationController.toolbar setShadowImage:[UIImage new]
-                                   forToolbarPosition:UIBarPositionAny];
-    [self setToolbarItems:@[ spaceButton, deleteButton, spaceButton ]
-                 animated:NO];
-  } else {
-    self.navigationController.toolbar.barTintColor = [UIColor whiteColor];
-    deleteButton.title = [deleteButton.title uppercaseString];
-    [deleteButton
-        setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
-                                                 [[MDCTypography fontLoader]
-                                                     mediumFontOfSize:14],
-                                                 NSFontAttributeName,
-                                                 [UIColor blackColor],
-                                                 NSForegroundColorAttributeName,
-                                                 nil]
-                      forState:UIControlStateNormal];
-    [self setToolbarItems:@[ deleteButton, spaceButton ] animated:NO];
-  }
+  deleteButton.tintColor = [UIColor redColor];
+  // Setting the image to nil will cause the default shadowImage to be used,
+  // we need to create a new one.
+  [self.navigationController.toolbar setShadowImage:[UIImage new]
+                                 forToolbarPosition:UIBarPositionAny];
+  [self setToolbarItems:@[ spaceButton, deleteButton, spaceButton ]
+               animated:NO];
 
   [self updateUIFromBookmark];
 }
@@ -498,8 +466,7 @@
 
 - (void)textDidChangeForItem:(BookmarkTextFieldItem*)item {
   [self updateSaveButtonState];
-  if (experimental_flags::IsBookmarksUIRebootEnabled() &&
-      (self.displayingValidURL != [self inputURLIsValid])) {
+  if (self.displayingValidURL != [self inputURLIsValid]) {
     self.displayingValidURL = [self inputURLIsValid];
     UITableViewHeaderFooterView* footer = [self.tableView
         footerViewForSection:[self.tableViewModel sectionForSectionIdentifier:
@@ -551,15 +518,7 @@
     case ItemTypeName:
       cell.selectionStyle = UITableViewCellSelectionStyleNone;
       break;
-    case ItemTypeURL: {
-      if (!experimental_flags::IsBookmarksUIRebootEnabled()) {
-        LegacyBookmarkTextFieldCell* URLCell =
-            base::mac::ObjCCastStrict<LegacyBookmarkTextFieldCell>(cell);
-        URLCell.textField.textValidator = self;
-        URLCell.selectionStyle = UITableViewCellSelectionStyleNone;
-      }
-      break;
-    }
+    case ItemTypeURL:
     case ItemTypeFolder:
       break;
   }
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_empty_background.mm b/ios/chrome/browser/ui/bookmarks/bookmark_empty_background.mm
index f9f8528..d11528ec 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_empty_background.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_empty_background.mm
@@ -4,9 +4,7 @@
 
 #include "ios/chrome/browser/ui/bookmarks/bookmark_empty_background.h"
 
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -15,14 +13,10 @@
 namespace {
 // The spacing between the image and text label.
 const CGFloat kStackViewSpacing = 24.0;
-const CGFloat kLegacyStackViewSpacing = 5.0;
 
 // The margin between the stack view and the edges of its superview.
 const CGFloat kStackViewMargin = 24.0;
 
-// The font size to use when UIRefresh is disabled.
-const CGFloat kLegacyFontSize = 16.0;
-
 }  // namespace
 
 @interface BookmarkEmptyBackground ()
@@ -42,13 +36,9 @@
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
-    BOOL useRefreshUI = experimental_flags::IsBookmarksUIRebootEnabled();
-
     // The "star" image.
-    NSString* imageName =
-        useRefreshUI ? @"bookmark_empty_star" : @"bookmark_gray_star_large";
-    UIImageView* imageView =
-        [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
+    UIImageView* imageView = [[UIImageView alloc]
+        initWithImage:[UIImage imageNamed:@"bookmark_empty_star"]];
 
     // The explanatory text label.
     self.textLabel = [[UILabel alloc] init];
@@ -57,16 +47,10 @@
         kBookmarkEmptyStateExplanatoryLabelIdentifier;
     self.textLabel.textAlignment = NSTextAlignmentCenter;
     self.textLabel.numberOfLines = 0;
-    if (useRefreshUI) {
-      self.textLabel.font =
-          [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
-      self.textLabel.adjustsFontForContentSizeCategory = YES;
-      self.textLabel.textColor = [UIColor colorWithWhite:0 alpha:100.0 / 255];
-    } else {
-      self.textLabel.font =
-          [[MDCTypography fontLoader] mediumFontOfSize:kLegacyFontSize];
-      self.textLabel.textColor = [UIColor colorWithWhite:0 alpha:110.0 / 255];
-    }
+    self.textLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+    self.textLabel.adjustsFontForContentSizeCategory = YES;
+    self.textLabel.textColor = [UIColor colorWithWhite:0 alpha:100.0 / 255];
 
     // Vertical stack view that centers its contents.
     _stackView = [[UIStackView alloc]
@@ -75,8 +59,7 @@
     _stackView.axis = UILayoutConstraintAxisVertical;
     _stackView.alignment = UIStackViewAlignmentCenter;
     _stackView.distribution = UIStackViewDistributionEqualSpacing;
-    _stackView.spacing =
-        useRefreshUI ? kStackViewSpacing : kLegacyStackViewSpacing;
+    _stackView.spacing = kStackViewSpacing;
     [self addSubview:_stackView];
 
     // Center the stack view, with a minimum margin around the leading and
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
index d4ba7e7a..6fa6c28 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.mm
@@ -14,7 +14,6 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
@@ -29,12 +28,6 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Buttons/src/MDCFlatButton.h"
-#import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
-#import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -139,15 +132,8 @@
 - (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel {
   DCHECK(bookmarkModel);
   DCHECK(bookmarkModel->loaded());
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleNoAppBar];
-  } else {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleWithAppBar];
-  }
+  self = [super initWithTableViewStyle:UITableViewStylePlain
+                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
   if (self) {
     _bookmarkModel = bookmarkModel;
 
@@ -172,15 +158,10 @@
   self.tableView.rowHeight = UITableViewAutomaticDimension;
   self.tableView.sectionHeaderHeight = 0;
   self.tableView.sectionFooterHeight = 0;
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.tableView.tableFooterView = [[UIView alloc] init];
-    [self.tableView
-        setSeparatorInset:UIEdgeInsetsMake(
-                              0, kBookmarkCellHorizontalLeadingInset, 0, 0)];
-  } else {
-    self.navigationController.navigationBarHidden = YES;
-    [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
-  }
+  self.tableView.tableFooterView = [[UIView alloc] init];
+  [self.tableView
+      setSeparatorInset:UIEdgeInsetsMake(0, kBookmarkCellHorizontalLeadingInset,
+                                         0, 0)];
 
   // Add Done button.
   UIBarButtonItem* doneItem = [[UIBarButtonItem alloc]
@@ -493,27 +474,11 @@
       initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                            target:nil
                            action:nil];
-
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    deleteButton.tintColor = [UIColor redColor];
-    [self.navigationController.toolbar setShadowImage:[UIImage new]
-                                   forToolbarPosition:UIBarPositionAny];
-    [self setToolbarItems:@[ spaceButton, deleteButton, spaceButton ]
-                 animated:NO];
-  } else {
-    self.navigationController.toolbar.barTintColor = [UIColor whiteColor];
-    deleteButton.title = [deleteButton.title uppercaseString];
-    [deleteButton
-        setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
-                                                 [[MDCTypography fontLoader]
-                                                     mediumFontOfSize:14],
-                                                 NSFontAttributeName,
-                                                 [UIColor blackColor],
-                                                 NSForegroundColorAttributeName,
-                                                 nil]
-                      forState:UIControlStateNormal];
-    [self setToolbarItems:@[ deleteButton, spaceButton ] animated:NO];
-  }
+  deleteButton.tintColor = [UIColor redColor];
+  [self.navigationController.toolbar setShadowImage:[UIImage new]
+                                 forToolbarPosition:UIBarPositionAny];
+  [self setToolbarItems:@[ spaceButton, deleteButton, spaceButton ]
+               animated:NO];
 }
 
 - (void)updateSaveButtonState {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm
index b7175de..efb7ade9 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.mm
@@ -10,7 +10,6 @@
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
@@ -115,15 +114,8 @@
   DCHECK(bookmarkModel);
   DCHECK(bookmarkModel->loaded());
   DCHECK(selectedFolder == NULL || selectedFolder->is_folder());
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleNoAppBar];
-  } else {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleWithAppBar];
-  }
+  self = [super initWithTableViewStyle:UITableViewStylePlain
+                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
   if (self) {
     _allowsCancel = allowsCancel;
     _allowsNewFolders = allowsNewFolders;
@@ -159,20 +151,6 @@
       kBookmarkFolderPickerViewContainerIdentifier;
   self.title = l10n_util::GetNSString(IDS_IOS_BOOKMARK_CHOOSE_GROUP_BUTTON);
 
-  if (!experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.view.backgroundColor = [UIColor whiteColor];
-    UIBarButtonItem* doneItem = [[UIBarButtonItem alloc]
-        initWithTitle:l10n_util::GetNSString(
-                          IDS_IOS_BOOKMARK_EDIT_MODE_EXIT_MOBILE)
-                style:UIBarButtonItemStylePlain
-               target:self
-               action:@selector(done:)];
-    doneItem.accessibilityIdentifier =
-        kBookmarkFolderEditNavigationBarDoneButtonIdentifier;
-    self.navigationItem.rightBarButtonItem = doneItem;
-    [self setEdgesForExtendedLayout:UIRectEdgeNone];
-  }
-
   if (self.allowsCancel) {
     UIBarButtonItem* cancelItem =
         [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon closeIcon]
@@ -196,17 +174,9 @@
   // Configure the table view.
   self.tableView.autoresizingMask =
       UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    // Add a tableFooterView in order to disable separators at the bottom of the
-    // tableView.
-    self.tableView.tableFooterView = [[UIView alloc] init];
-  } else {
-    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-    // To support the pre UIRefresh we need to set the insets since
-    // UITableViewCell lines itself up with the tableView separator insets. The
-    // following line won't be needed for UIRefresh.
-    [self.tableView setSeparatorInset:UIEdgeInsetsMake(0, 51, 0, 0)];
-  }
+  // Add a tableFooterView in order to disable separators at the bottom of the
+  // tableView.
+  self.tableView.tableFooterView = [[UIView alloc] init];
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -285,10 +255,9 @@
 
     case SectionIdentifierBookmarkFolders: {
       int folderIndex = indexPath.row;
-      // On UIRefresh if |shouldShowDefaultSection| is YES, the first cell on
-      // this Section should call |pushFolderAddViewController|.
-      if (experimental_flags::IsBookmarksUIRebootEnabled() &&
-          [self shouldShowDefaultSection]) {
+      // If |shouldShowDefaultSection| is YES, the first cell on this section
+      // should call |pushFolderAddViewController|.
+      if ([self shouldShowDefaultSection]) {
         NSInteger itemType =
             [self.tableViewModel itemTypeForIndexPath:indexPath];
         if (itemType == ItemTypeCreateNewFolder) {
@@ -435,18 +404,10 @@
     BookmarkFolderItem* createFolderItem =
         [[BookmarkFolderItem alloc] initWithType:ItemTypeCreateNewFolder
                                            style:BookmarkFolderStyleNewFolder];
-    // On UIRefresh we add the "Add Folder" Item to the same section as the rest
-    // of the folder entries.
-    if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-      [self.tableViewModel addItem:createFolderItem
-           toSectionWithIdentifier:SectionIdentifierBookmarkFolders];
-    } else {
-      [self.tableViewModel
-          insertSectionWithIdentifier:SectionIdentifierAddFolder
-                              atIndex:0];
-      [self.tableViewModel addItem:createFolderItem
-           toSectionWithIdentifier:SectionIdentifierAddFolder];
-    }
+    // Add the "Add Folder" Item to the same section as the rest of the folder
+    // entries.
+    [self.tableViewModel addItem:createFolderItem
+         toSectionWithIdentifier:SectionIdentifierBookmarkFolders];
   }
 
   // Add Folders entries.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.mm
index 80f49e3..07bccf1 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_shared_state.h"
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell_title_editing.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 64d32bb..27059c8 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -17,7 +17,6 @@
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
 #import "ios/chrome/browser/metrics/new_tab_page_uma.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
@@ -40,11 +39,9 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell_title_edit_delegate.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/material_components/utils.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
@@ -59,7 +56,6 @@
 #import "ios/chrome/common/favicon/favicon_view.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/referrer.h"
 #include "skia/ext/skia_utils_ios.h"
@@ -137,31 +133,8 @@
   return urls;
 }
 
-// Shadow opacity for the NavigationController Toolbar.
-const CGFloat kShadowOpacity = 0.12f;
-// Shadow radius for the NavigationController Toolbar.
-const CGFloat kShadowRadius = 12.0f;
 }  // namespace
 
-// An AlertCoordinator with the "Action Sheet" style that does not provide an
-// anchor rect to its UIPopoverPresentationController. This is used by the
-// legacy bookmarks implementation in order to consistently render as an action
-// sheet and not as a popover.
-@interface LegacyBookmarksActionSheetCoordinator : AlertCoordinator
-@end
-
-@implementation LegacyBookmarksActionSheetCoordinator
-
-- (UIAlertController*)alertControllerWithTitle:(NSString*)title
-                                       message:(NSString*)message {
-  return [UIAlertController
-      alertControllerWithTitle:title
-                       message:message
-                preferredStyle:UIAlertControllerStyleActionSheet];
-}
-
-@end
-
 @interface BookmarkHomeViewController ()<BookmarkFolderViewControllerDelegate,
                                          BookmarkHomeConsumer,
                                          BookmarkHomeSharedStateObserver,
@@ -290,15 +263,8 @@
                   browserState:(ios::ChromeBrowserState*)browserState
                     dispatcher:(id<ApplicationCommands>)dispatcher {
   DCHECK(browserState);
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleNoAppBar];
-  } else {
-    self =
-        [super initWithTableViewStyle:UITableViewStylePlain
-                          appBarStyle:ChromeTableViewControllerStyleWithAppBar];
-  }
+  self = [super initWithTableViewStyle:UITableViewStylePlain
+                           appBarStyle:ChromeTableViewControllerStyleNoAppBar];
   if (self) {
     _browserState = browserState->GetOriginalChromeBrowserState();
     _loader = loader;
@@ -329,12 +295,11 @@
   DCHECK_EQ(_rootNode, self.bookmarks->root_node());
 
   NSMutableArray<BookmarkHomeViewController*>* stack = [NSMutableArray array];
-  // On UIRefresh we need to configure the root controller Navigationbar at this
-  // time when reconstructing from cache, or there will be a loading flicker if
-  // this gets done on viewDidLoad.
-  if (experimental_flags::IsBookmarksUIRebootEnabled())
-    [self setupNavigationForBookmarkHomeViewController:self
-                                     usingBookmarkNode:_rootNode];
+  // Configure the root controller Navigationbar at this time when
+  // reconstructing from cache, or there will be a loading flicker if this gets
+  // done on viewDidLoad.
+  [self setupNavigationForBookmarkHomeViewController:self
+                                   usingBookmarkNode:_rootNode];
   [stack addObject:self];
 
   int64_t cachedFolderID;
@@ -371,12 +336,11 @@
 
     BookmarkHomeViewController* controller =
         [self createControllerWithRootFolder:node];
-    // On UIRefresh we need to configure the controller's Navigationbar at this
-    // time when reconstructing from cache, or there will be a loading flicker
-    // if this gets done on viewDidLoad.
-    if (experimental_flags::IsBookmarksUIRebootEnabled())
-      [self setupNavigationForBookmarkHomeViewController:controller
-                                       usingBookmarkNode:node];
+    // Configure the controller's Navigationbar at this time when
+    // reconstructing from cache, or there will be a loading flicker if this
+    // gets done on viewDidLoad.
+    [self setupNavigationForBookmarkHomeViewController:controller
+                                     usingBookmarkNode:node];
     if (nodeID == cachedFolderID) {
       controller.cachedIndexPathRow = cachedIndexPathRow;
     }
@@ -391,76 +355,64 @@
   [super viewDidLoad];
 
   // Set Navigation Bar, Toolbar and TableView appearance.
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.navigationController.navigationBarHidden = NO;
-    self.navigationController.toolbar.translucent = YES;
-    // Add a tableFooterView in order to disable separators at the bottom of the
-    // tableView.
-    self.tableView.tableFooterView = [[UIView alloc] init];
-  } else {
-    self.navigationController.navigationBarHidden = YES;
-    self.navigationController.toolbar.translucent = NO;
-    self.navigationController.toolbar.barTintColor = [UIColor whiteColor];
-    self.navigationController.toolbar.layer.shadowRadius = kShadowRadius;
-    self.navigationController.toolbar.layer.shadowOpacity = kShadowOpacity;
-    // Disable separators while the loading spinner is showing.
-    // |loadBookmarkView| will bring them back if needed.
-    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-  }
+  self.navigationController.navigationBarHidden = NO;
+  self.navigationController.toolbar.translucent = YES;
+  // Add a tableFooterView in order to disable separators at the bottom of the
+  // tableView.
+  self.tableView.tableFooterView = [[UIView alloc] init];
+
   self.navigationController.toolbar.accessibilityIdentifier =
       kBookmarkHomeUIToolbarIdentifier;
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    // SearchController Configuration.
-    // Init the searchController with nil so the results are displayed on the
-    // same TableView.
-    self.searchController =
-        [[UISearchController alloc] initWithSearchResultsController:nil];
-    self.searchController.dimsBackgroundDuringPresentation = NO;
-    self.searchController.searchBar.userInteractionEnabled = NO;
-    self.searchController.delegate = self;
-    self.searchController.searchResultsUpdater = self;
-    self.searchController.searchBar.backgroundColor = [UIColor clearColor];
-    self.searchController.searchBar.accessibilityIdentifier =
-        kBookmarkHomeSearchBarIdentifier;
+  // SearchController Configuration.
+  // Init the searchController with nil so the results are displayed on the
+  // same TableView.
+  self.searchController =
+      [[UISearchController alloc] initWithSearchResultsController:nil];
+  self.searchController.dimsBackgroundDuringPresentation = NO;
+  self.searchController.searchBar.userInteractionEnabled = NO;
+  self.searchController.delegate = self;
+  self.searchController.searchResultsUpdater = self;
+  self.searchController.searchBar.backgroundColor = [UIColor clearColor];
+  self.searchController.searchBar.accessibilityIdentifier =
+      kBookmarkHomeSearchBarIdentifier;
 
-    // UIKit needs to know which controller will be presenting the
-    // searchController. If we don't add this trying to dismiss while
-    // SearchController is active will fail.
-    self.definesPresentationContext = YES;
+  // UIKit needs to know which controller will be presenting the
+  // searchController. If we don't add this trying to dismiss while
+  // SearchController is active will fail.
+  self.definesPresentationContext = YES;
 
-    self.scrimView = [[UIControl alloc] initWithFrame:self.tableView.bounds];
-    self.scrimView.backgroundColor =
-        [UIColor colorWithWhite:0
-                          alpha:kTableViewNavigationWhiteAlphaForSearchScrim];
-    self.scrimView.translatesAutoresizingMaskIntoConstraints = NO;
-    self.scrimView.autoresizingMask =
-        UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-    self.scrimView.accessibilityIdentifier = kBookmarkHomeSearchScrimIdentifier;
-    [self.scrimView addTarget:self
-                       action:@selector(dismissSearchController:)
-             forControlEvents:UIControlEventAllTouchEvents];
+  self.scrimView = [[UIControl alloc] initWithFrame:self.tableView.bounds];
+  self.scrimView.backgroundColor =
+      [UIColor colorWithWhite:0
+                        alpha:kTableViewNavigationWhiteAlphaForSearchScrim];
+  self.scrimView.translatesAutoresizingMaskIntoConstraints = NO;
+  self.scrimView.autoresizingMask =
+      UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+  self.scrimView.accessibilityIdentifier = kBookmarkHomeSearchScrimIdentifier;
+  [self.scrimView addTarget:self
+                     action:@selector(dismissSearchController:)
+           forControlEvents:UIControlEventAllTouchEvents];
 
-    // For iOS 11 and later, place the search bar in the navigation bar.
-    // Otherwise place the search bar in the table view's header.
-    if (@available(iOS 11, *)) {
-      self.navigationItem.searchController = self.searchController;
-      self.navigationItem.hidesSearchBarWhenScrolling = NO;
+  // For iOS 11 and later, place the search bar in the navigation bar.
+  // Otherwise place the search bar in the table view's header.
+  if (@available(iOS 11, *)) {
+    self.navigationItem.searchController = self.searchController;
+    self.navigationItem.hidesSearchBarWhenScrolling = NO;
 
-      // Center search bar vertically so it looks centered in the header when
-      // searching.  The cancel button is centered / decentered on
-      // viewWillAppear and viewDidDisappear.
-      UIOffset offset =
-          UIOffsetMake(0.0f, kTableViewNavigationVerticalOffsetForSearchHeader);
-      self.searchController.searchBar.searchFieldBackgroundPositionAdjustment =
-          offset;
-    } else {
-      self.tableView.tableHeaderView = self.searchController.searchBar;
-    }
-
-    self.searchTerm = @"";
+    // Center search bar vertically so it looks centered in the header when
+    // searching.  The cancel button is centered / decentered on
+    // viewWillAppear and viewDidDisappear.
+    UIOffset offset =
+        UIOffsetMake(0.0f, kTableViewNavigationVerticalOffsetForSearchHeader);
+    self.searchController.searchBar.searchFieldBackgroundPositionAdjustment =
+        offset;
+  } else {
+    self.tableView.tableHeaderView = self.searchController.searchBar;
   }
 
+  self.searchTerm = @"";
+
   if (self.bookmarks->loaded()) {
     [self loadBookmarkViews];
   } else {
@@ -571,10 +523,6 @@
   // line will also create a default footer of height 30.
   self.tableView.sectionFooterHeight = 1;
   self.sharedState.tableView.allowsMultipleSelectionDuringEditing = YES;
-  if (!experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.sharedState.tableView.separatorStyle =
-        UITableViewCellSeparatorStyleNone;
-  }
 
   UILongPressGestureRecognizer* longPressRecognizer =
       [[UILongPressGestureRecognizer alloc]
@@ -600,9 +548,7 @@
     [self setupUIStackCacheIfApplicable];
   }
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.searchController.searchBar.userInteractionEnabled = YES;
-  }
+  self.searchController.searchBar.userInteractionEnabled = YES;
 
   DCHECK(self.bookmarks->loaded());
   DCHECK([self isViewLoaded]);
@@ -620,8 +566,7 @@
 #pragma mark - BookmarkHomeConsumer
 
 - (void)refreshContents {
-  if (experimental_flags::IsBookmarksUIRebootEnabled() &&
-      self.sharedState.currentlyShowingSearchResults) {
+  if (self.sharedState.currentlyShowingSearchResults) {
     NSString* noResults = l10n_util::GetNSString(IDS_HISTORY_NO_SEARCH_RESULTS);
     [self.mediator computeBookmarkTableViewDataMatching:self.searchTerm
                              orShowMessageWhenNoResults:noResults];
@@ -1084,24 +1029,12 @@
             (BookmarkHomeViewController*)viewController
                                    usingBookmarkNode:
                                        (const bookmarks::BookmarkNode*)node {
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    viewController.navigationItem.leftBarButtonItem.action = @selector(back);
-    // Disable large titles on every VC but the root controller.
-    if (@available(iOS 11, *)) {
-      if (node != self.bookmarks->root_node()) {
-        viewController.navigationItem.largeTitleDisplayMode =
-            UINavigationItemLargeTitleDisplayModeNever;
-      }
-    }
-  } else {
-    viewController.navigationController.navigationBarHidden = YES;
-    if (viewController.navigationController.viewControllers.count > 1) {
-      // Add custom back button.
-      UIBarButtonItem* backButton =
-          [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon]
-                                              target:self
-                                              action:@selector(back)];
-      viewController.navigationItem.leftBarButtonItem = backButton;
+  viewController.navigationItem.leftBarButtonItem.action = @selector(back);
+  // Disable large titles on every VC but the root controller.
+  if (@available(iOS 11, *)) {
+    if (node != self.bookmarks->root_node()) {
+      viewController.navigationItem.largeTitleDisplayMode =
+          UINavigationItemLargeTitleDisplayModeNever;
     }
   }
 
@@ -1221,11 +1154,9 @@
   self.sharedState.currentlyInEditMode = editing;
   [self setContextBarState:editing ? BookmarksContextBarBeginSelection
                                    : BookmarksContextBarDefault];
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.searchController.searchBar.userInteractionEnabled = !editing;
-    self.searchController.searchBar.alpha =
-        editing ? kTableViewNavigationAlphaForDisabledSearchBar : 1.0;
-  }
+  self.searchController.searchBar.userInteractionEnabled = !editing;
+  self.searchController.searchBar.alpha =
+      editing ? kTableViewNavigationAlphaForDisabledSearchBar : 1.0;
 }
 
 // Row selection of the tableView will be cleared after reloadData.  This
@@ -1479,18 +1410,11 @@
   // one node is selected.
   DCHECK(nodes.size() > 0);
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
-        initWithBaseViewController:self
-                             title:nil
-                           message:nil
-                     barButtonItem:self.moreButton];
-  } else {
-    self.actionSheetCoordinator = [[LegacyBookmarksActionSheetCoordinator alloc]
-        initWithBaseViewController:self
-                             title:nil
-                           message:nil];
-  }
+  self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self
+                           title:nil
+                         message:nil
+                   barButtonItem:self.moreButton];
 
   switch (self.contextBarState) {
     case BookmarksContextBarSingleURLSelection:
@@ -1776,40 +1700,25 @@
               backgroundColor:(UIColor*)backgroundColor
                     textColor:(UIColor*)textColor
                  fallbackText:(NSString*)fallbackText {
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    TableViewURLCell* URLCell = base::mac::ObjCCastStrict<TableViewURLCell>(
-        [self.sharedState.tableView cellForRowAtIndexPath:indexPath]);
-    if (!URLCell)
-      return;
-    if (image)
-      [URLCell.faviconView
-          configureWithAttributes:[FaviconAttributes
-                                      attributesWithImage:image]];
-    else {
-      // UI Refresh fallback colors are default fixed.
-      textColor =
-          [UIColor colorWithWhite:kFallbackIconDefaultTextColorWhitePercentage
-                            alpha:1.0];
-      backgroundColor = UIColorFromRGB(kFallbackIconDefaultBackgroundColor);
-      [URLCell.faviconView
-          configureWithAttributes:[FaviconAttributes
-                                      attributesWithMonogram:fallbackText
-                                                   textColor:textColor
-                                             backgroundColor:backgroundColor
-                                      defaultBackgroundColor:NO]];
-    }
+  TableViewURLCell* URLCell = base::mac::ObjCCastStrict<TableViewURLCell>(
+      [self.sharedState.tableView cellForRowAtIndexPath:indexPath]);
+  if (!URLCell)
+    return;
+  if (image) {
+    [URLCell.faviconView
+        configureWithAttributes:[FaviconAttributes attributesWithImage:image]];
   } else {
-    BookmarkTableCell* cell =
-        [self.sharedState.tableView cellForRowAtIndexPath:indexPath];
-    if (!cell)
-      return;
-    if (image) {
-      [cell setImage:image];
-    } else {
-      [cell setPlaceholderText:fallbackText
-                     textColor:textColor
-               backgroundColor:backgroundColor];
-    }
+    // Fallback colors are default fixed.
+    textColor =
+        [UIColor colorWithWhite:kFallbackIconDefaultTextColorWhitePercentage
+                          alpha:1.0];
+    backgroundColor = UIColorFromRGB(kFallbackIconDefaultBackgroundColor);
+    [URLCell.faviconView
+        configureWithAttributes:[FaviconAttributes
+                                    attributesWithMonogram:fallbackText
+                                                 textColor:textColor
+                                           backgroundColor:backgroundColor
+                                    defaultBackgroundColor:NO]];
   }
 }
 
@@ -1897,19 +1806,12 @@
     return;
   }
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
-        initWithBaseViewController:self
-                             title:nil
-                           message:nil
-                              rect:CGRectMake(touchPoint.x, touchPoint.y, 1, 1)
-                              view:self.tableView];
-  } else {
-    self.actionSheetCoordinator = [[LegacyBookmarksActionSheetCoordinator alloc]
-        initWithBaseViewController:self
-                             title:nil
-                           message:nil];
-  }
+  self.actionSheetCoordinator = [[ActionSheetCoordinator alloc]
+      initWithBaseViewController:self
+                           title:nil
+                         message:nil
+                            rect:CGRectMake(touchPoint.x, touchPoint.y, 1, 1)
+                            view:self.tableView];
 
   if (node->is_url()) {
     [self configureCoordinator:self.actionSheetCoordinator
@@ -1992,32 +1894,19 @@
   if (item.type == BookmarkHomeItemTypeBookmark) {
     BookmarkHomeNodeItem* nodeItem =
         base::mac::ObjCCastStrict<BookmarkHomeNodeItem>(item);
-    if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-      if (nodeItem.bookmarkNode->is_folder() &&
-          nodeItem.bookmarkNode == self.sharedState.editingFolderNode) {
-        TableViewBookmarkFolderCell* tableCell =
-            base::mac::ObjCCastStrict<TableViewBookmarkFolderCell>(cell);
-        // Delay starting edit, so that the cell is fully created. This is
-        // needed when scrolling away and then back into the editingCell,
-        // without the delay the cell will resign first responder before its
-        // created.
-        dispatch_async(dispatch_get_main_queue(), ^{
-          self.sharedState.editingFolderCell = tableCell;
-          [tableCell startEdit];
-          tableCell.textDelegate = self;
-        });
-      }
-    } else {
-      BookmarkTableCell* tableCell =
-          base::mac::ObjCCastStrict<BookmarkTableCell>(cell);
-      if (nodeItem.bookmarkNode == self.sharedState.editingFolderNode) {
-        // Delay starting edit, so that the cell is fully created.
-        dispatch_async(dispatch_get_main_queue(), ^{
-          self.sharedState.editingFolderCell = tableCell;
-          [tableCell startEdit];
-          tableCell.textDelegate = self;
-        });
-      }
+    if (nodeItem.bookmarkNode->is_folder() &&
+        nodeItem.bookmarkNode == self.sharedState.editingFolderNode) {
+      TableViewBookmarkFolderCell* tableCell =
+          base::mac::ObjCCastStrict<TableViewBookmarkFolderCell>(cell);
+      // Delay starting edit, so that the cell is fully created. This is
+      // needed when scrolling away and then back into the editingCell,
+      // without the delay the cell will resign first responder before its
+      // created.
+      dispatch_async(dispatch_get_main_queue(), ^{
+        self.sharedState.editingFolderCell = tableCell;
+        [tableCell startEdit];
+        tableCell.textDelegate = self;
+      });
     }
 
     // Cancel previous load attempts.
@@ -2122,13 +2011,6 @@
 
 - (CGFloat)tableView:(UITableView*)tableView
     heightForRowAtIndexPath:(NSIndexPath*)indexPath {
-  if (!experimental_flags::IsBookmarksUIRebootEnabled()) {
-    NSInteger sectionIdentifier = [self.sharedState.tableViewModel
-        sectionIdentifierForSection:indexPath.section];
-    if (sectionIdentifier == BookmarkHomeSectionIdentifierBookmarks) {
-      return kEstimatedRowHeight;
-    }
-  }
   return UITableViewAutomaticDimension;
 }
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index 35e9fed..dc295ba 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -17,7 +17,6 @@
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/metrics/new_tab_page_uma.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.h"
@@ -37,7 +36,6 @@
 #import "ios/chrome/browser/ui/table_view/table_view_presentation_controller_delegate.h"
 #include "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/browser/ui/url_loader.h"
-#import "ios/chrome/browser/ui/util/form_sheet_navigation_controller.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
 #import "ios/web/public/navigation_manager.h"
@@ -504,47 +502,32 @@
 - (void)presentTableViewController:(ChromeTableViewController*)viewController
     withReplacementViewControllers:
         (NSArray<ChromeTableViewController*>*)replacementViewControllers {
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    TableViewNavigationController* navController =
-        [[TableViewNavigationController alloc] initWithTable:viewController];
-    self.bookmarkNavigationController = navController;
-    if (replacementViewControllers) {
-      [navController setViewControllers:replacementViewControllers];
-    }
-
-    navController.toolbarHidden = YES;
-    self.bookmarkNavigationControllerDelegate =
-        [[TableViewNavigationControllerDelegate alloc] init];
-    navController.delegate = self.bookmarkNavigationControllerDelegate;
-    self.bookmarkTransitioningDelegate =
-        [[BookmarkTransitioningDelegate alloc] init];
-    self.bookmarkTransitioningDelegate.presentationControllerModalDelegate =
-        self;
-    navController.transitioningDelegate = self.bookmarkTransitioningDelegate;
-    navController.modalPresentationStyle = UIModalPresentationCustom;
-
-    [_parentController presentViewController:navController
-                                    animated:YES
-                                  completion:nil];
-
-    TableViewPresentationController* presentationController =
-        base::mac::ObjCCastStrict<TableViewPresentationController>(
-            navController.presentationController);
-    self.bookmarkNavigationControllerDelegate.modalController =
-        presentationController;
-  } else {
-    FormSheetNavigationController* navController =
-        [[FormSheetNavigationController alloc]
-            initWithRootViewController:viewController];
-    if (replacementViewControllers) {
-      [navController setViewControllers:replacementViewControllers];
-    }
-    navController.modalPresentationStyle = UIModalPresentationFormSheet;
-    self.bookmarkNavigationController = navController;
-    [_parentController presentViewController:navController
-                                    animated:YES
-                                  completion:nil];
+  TableViewNavigationController* navController =
+      [[TableViewNavigationController alloc] initWithTable:viewController];
+  self.bookmarkNavigationController = navController;
+  if (replacementViewControllers) {
+    [navController setViewControllers:replacementViewControllers];
   }
+
+  navController.toolbarHidden = YES;
+  self.bookmarkNavigationControllerDelegate =
+      [[TableViewNavigationControllerDelegate alloc] init];
+  navController.delegate = self.bookmarkNavigationControllerDelegate;
+  self.bookmarkTransitioningDelegate =
+      [[BookmarkTransitioningDelegate alloc] init];
+  self.bookmarkTransitioningDelegate.presentationControllerModalDelegate = self;
+  navController.transitioningDelegate = self.bookmarkTransitioningDelegate;
+  navController.modalPresentationStyle = UIModalPresentationCustom;
+
+  [_parentController presentViewController:navController
+                                  animated:YES
+                                completion:nil];
+
+  TableViewPresentationController* presentationController =
+      base::mac::ObjCCastStrict<TableViewPresentationController>(
+          navController.presentationController);
+  self.bookmarkNavigationControllerDelegate.modalController =
+      presentationController;
 }
 
 - (void)openURLInCurrentTab:(const GURL&)url {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm
index 7ad91e0..9384ea13 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
 
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -13,14 +12,6 @@
 
 @implementation BookmarkNavigationController
 
-- (id)initWithRootViewController:(UIViewController*)rootViewController {
-  self = [super initWithRootViewController:rootViewController];
-  if (self && !experimental_flags::IsBookmarksUIRebootEnabled()) {
-    [self setNavigationBarHidden:YES];
-  }
-  return self;
-}
-
 - (void)viewDidLoad {
   [super viewDidLoad];
   self.view.backgroundColor = [UIColor whiteColor];
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index 2a02d9c..957e6af 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -18,7 +18,6 @@
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
@@ -83,17 +82,6 @@
   return ButtonWithAccessibilityLabelId(IDS_TOOLTIP_STAR);
 }
 
-// Matcher for the button to add bookmark.
-id<GREYMatcher> AddBookmarkButton() {
-  return ButtonWithAccessibilityLabelId(IDS_BOOKMARK_ADD_EDITOR_TITLE);
-}
-
-// Matcher for the lit star buttom on iPhone that will open the edit button
-// screen.
-id<GREYMatcher> LitStarButtoniPhone() {
-  return ButtonWithAccessibilityLabelId(IDS_IOS_TOOLS_MENU_EDIT_BOOKMARK);
-}
-
 // Matcher for the button to edit bookmark.
 id<GREYMatcher> EditBookmarkButton() {
   return ButtonWithAccessibilityLabelId(IDS_IOS_BOOKMARK_ACTION_EDIT);
@@ -107,30 +95,22 @@
 // Matcher for the Back button to |previousViewControllerLabel| on the bookmarks
 // UI.
 id<GREYMatcher> NavigateBackButtonTo(NSString* previousViewControllerLabel) {
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    // When using the stock UINavigationBar back button item, the button's label
-    // may be truncated to the word "Back", or to nothing at all.  It is not
-    // possible to know which label will be used, as the OS makes that decision,
-    // so try to search for any of them.
-    id<GREYMatcher> buttonLabelMatcher =
-        grey_anyOf(grey_accessibilityLabel(previousViewControllerLabel),
-                   grey_accessibilityLabel(@"Back"), nil);
+  // When using the stock UINavigationBar back button item, the button's label
+  // may be truncated to the word "Back", or to nothing at all.  It is not
+  // possible to know which label will be used, as the OS makes that decision,
+  // so try to search for any of them.
+  id<GREYMatcher> buttonLabelMatcher =
+      grey_anyOf(grey_accessibilityLabel(previousViewControllerLabel),
+                 grey_accessibilityLabel(@"Back"), nil);
 
-    if (@available(iOS 11, *)) {
-      return grey_allOf(
-          grey_kindOfClass([UIButton class]),
-          grey_ancestor(grey_kindOfClass([UINavigationBar class])),
-          buttonLabelMatcher, nil);
-    } else {
-      return grey_allOf(
-          grey_accessibilityTrait(UIAccessibilityTraitButton),
-          grey_ancestor(grey_kindOfClass([UINavigationBar class])),
-          buttonLabelMatcher, nil);
-    }
+  if (@available(iOS 11, *)) {
+    return grey_allOf(grey_kindOfClass([UIButton class]),
+                      grey_ancestor(grey_kindOfClass([UINavigationBar class])),
+                      buttonLabelMatcher, nil);
   } else {
-    return grey_allOf(grey_accessibilityLabel(l10n_util::GetNSString(
-                          IDS_IOS_BOOKMARK_NEW_BACK_LABEL)),
-                      grey_enabled(), nil);
+    return grey_allOf(grey_accessibilityTrait(UIAccessibilityTraitButton),
+                      grey_ancestor(grey_kindOfClass([UINavigationBar class])),
+                      buttonLabelMatcher, nil);
   }
 }
 
@@ -218,68 +198,7 @@
 
 // Verifies that adding a bookmark and removing a bookmark via the UI properly
 // updates the BookmarkModel.
-- (void)testAddRemoveBookmarkLegacy {
-  if (IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is non UIRefresh only.");
-  }
-  const GURL bookmarkedURL = web::test::HttpServer::MakeUrl(
-      "http://ios/testing/data/http_server_files/pony.html");
-  std::string expectedURLContent = bookmarkedURL.GetContent();
-  NSString* bookmarkTitle = @"my bookmark";
-
-  [ChromeEarlGrey loadURL:bookmarkedURL];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
-                                          expectedURLContent)]
-      assertWithMatcher:grey_notNil()];
-
-  // Add the bookmark from the UI.
-  [BookmarksTestCase bookmarkCurrentTabWithTitle:bookmarkTitle];
-
-  // Verify the bookmark is set.
-  [BookmarksTestCase assertBookmarksWithTitle:bookmarkTitle expectedCount:1];
-
-  NSString* const kStarLitLabel =
-      !IsCompactWidth()
-          ? l10n_util::GetNSString(IDS_TOOLTIP_STAR)
-          : l10n_util::GetNSString(IDS_IOS_BOOKMARK_EDIT_SCREEN_TITLE);
-  // Verify the star is lit.
-  if (IsCompactWidth()) {
-    [ChromeEarlGreyUI openToolsMenu];
-  }
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarLitLabel)]
-      assertWithMatcher:grey_notNil()];
-
-  // Clear the bookmark via the UI.
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarLitLabel)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kBookmarkEditDeleteButtonIdentifier)]
-      performAction:grey_tap()];
-
-  // Verify the bookmark is not in the BookmarkModel.
-  [BookmarksTestCase assertBookmarksWithTitle:bookmarkTitle expectedCount:0];
-
-  NSString* const kStarUnlitLabel =
-      !IsCompactWidth() ? l10n_util::GetNSString(IDS_TOOLTIP_STAR)
-                        : l10n_util::GetNSString(IDS_BOOKMARK_ADD_EDITOR_TITLE);
-
-  // Verify the star is not lit.
-  if (IsCompactWidth()) {
-    [ChromeEarlGreyUI openToolsMenu];
-  }
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(kStarUnlitLabel)]
-      assertWithMatcher:grey_notNil()];
-
-  // Close the opened tab.
-  [chrome_test_util::BrowserCommandDispatcherForMainBVC() closeCurrentTab];
-}
-
-// Verifies that adding a bookmark and removing a bookmark via the UI properly
-// updates the BookmarkModel.
 - (void)testAddRemoveBookmark {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
   const GURL bookmarkedURL = web::test::HttpServer::MakeUrl(
       "http://ios/testing/data/http_server_files/pony.html");
   std::string expectedURLContent = bookmarkedURL.GetContent();
@@ -441,19 +360,14 @@
     [[EarlGrey selectElementWithMatcher:StarButton()] performAction:grey_tap()];
   } else {
     [ChromeEarlGreyUI openToolsMenu];
-    if (IsUIRefreshPhase1Enabled()) {
-      [[[EarlGrey
-          selectElementWithMatcher:grey_allOf(grey_accessibilityID(
-                                                  kToolsMenuEditBookmark),
-                                              grey_sufficientlyVisible(), nil)]
-             usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
-          onElementWithMatcher:grey_accessibilityID(
-                                   kPopupMenuToolsMenuTableViewId)]
-          performAction:grey_tap()];
-    } else {
-      [[EarlGrey selectElementWithMatcher:LitStarButtoniPhone()]
-          performAction:grey_tap()];
-    }
+    [[[EarlGrey
+        selectElementWithMatcher:grey_allOf(grey_accessibilityID(
+                                                kToolsMenuEditBookmark),
+                                            grey_sufficientlyVisible(), nil)]
+           usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+        onElementWithMatcher:grey_accessibilityID(
+                                 kPopupMenuToolsMenuTableViewId)]
+        performAction:grey_tap()];
   }
   GREYAssertTrue(chrome_test_util::GetRegisteredKeyCommandsCount() == 0,
                  @"No keyboard commands are registered.");
@@ -857,12 +771,6 @@
 }
 
 - (void)testCachePositionIsRecreated {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Legacy UI doesn't scroll completely to the bottom, this causes the "
-        @"cell to be partially hidden by the custom toolbar, making the test "
-        @"fail.");
-  }
   [BookmarksTestCase setupBookmarksWhichExceedsScreenHeight];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -1147,26 +1055,14 @@
 
 // Adds a bookmark for the current tab. Must be called when on a tab.
 + (void)starCurrentTab {
-  if (IsUIRefreshPhase1Enabled()) {
-    [ChromeEarlGreyUI openToolsMenu];
-    [[[EarlGrey
-        selectElementWithMatcher:grey_allOf(grey_accessibilityID(
-                                                kToolsMenuAddToBookmarks),
-                                            grey_sufficientlyVisible(), nil)]
-           usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
-        onElementWithMatcher:grey_accessibilityID(
-                                 kPopupMenuToolsMenuTableViewId)]
-        performAction:grey_tap()];
-  } else {
-    if (!IsCompactWidth()) {
-      [[EarlGrey selectElementWithMatcher:StarButton()]
-          performAction:grey_tap()];
-    } else {
-      [ChromeEarlGreyUI openToolsMenu];
-      [[EarlGrey selectElementWithMatcher:AddBookmarkButton()]
-          performAction:grey_tap()];
-    }
-  }
+  [ChromeEarlGreyUI openToolsMenu];
+  [[[EarlGrey
+      selectElementWithMatcher:grey_allOf(grey_accessibilityID(
+                                              kToolsMenuAddToBookmarks),
+                                          grey_sufficientlyVisible(), nil)]
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown, 200)
+      onElementWithMatcher:grey_accessibilityID(kPopupMenuToolsMenuTableViewId)]
+      performAction:grey_tap()];
 }
 
 // Check that the currently edited bookmark is in |folderName| folder.
@@ -1839,8 +1735,8 @@
   // fail on devices. Disabling this test under these conditions on the
   // meantime.
   if (@available(iOS 11, *)) {
-    if (experimental_flags::IsBookmarksUIRebootEnabled() && !IsCompactWidth()) {
-      EARL_GREY_TEST_SKIPPED(@"Test disabled on UIRefresh iPad on iOS11.");
+    if (!IsCompactWidth()) {
+      EARL_GREY_TEST_SKIPPED(@"Test disabled on iPad on iOS11.");
     }
   }
 
@@ -1891,8 +1787,8 @@
   // fail on devices. Disabling this test under these conditions on the
   // meantime.
   if (@available(iOS 11, *)) {
-    if (experimental_flags::IsBookmarksUIRebootEnabled() && !IsCompactWidth()) {
-      EARL_GREY_TEST_SKIPPED(@"Test disabled on UIRefresh iPad on iOS11.");
+    if (!IsCompactWidth()) {
+      EARL_GREY_TEST_SKIPPED(@"Test disabled on iPad on iOS11.");
     }
   }
 
@@ -4177,10 +4073,6 @@
 
 // Tests that the search bar is shown on root.
 - (void)testSearchBarShownOnRoot {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
 
@@ -4192,10 +4084,6 @@
 
 // Tests that the search bar is shown on mobile list.
 - (void)testSearchBarShownOnMobileBookmarks {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4208,10 +4096,6 @@
 
 // Tests the search.
 - (void)testSearchResults {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4270,10 +4154,6 @@
 
 // Tests that you get 'No Results' when no matching bookmarks are found.
 - (void)testSearchWithNoResults {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4290,10 +4170,6 @@
 
 // Tests that scrim is shown while search box is enabled with no queries.
 - (void)testSearchScrimShownWhenSearchBoxEnabled {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4336,10 +4212,6 @@
 // Tests that tapping scrim while search box is enabled dismisses the search
 // controller.
 - (void)testSearchTapOnScrimCancelsSearchController {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4371,10 +4243,6 @@
 
 // Tests cancelling search restores the node's bookmarks.
 - (void)testSearchCancelRestoresNodeBookmarks {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4411,10 +4279,6 @@
 
 // Tests that the navigation bar isn't shown when search is focused and empty.
 - (void)testSearchHidesNavigationBar {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4441,10 +4305,6 @@
 // Tests that you can long press and edit a bookmark and see edits when going
 // back to search.
 - (void)testSearchLongPressEditOnURL {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4480,18 +4340,14 @@
 
 // Tests that you can swipe items in search mode.
 - (void)testSearchItemsCanBeSwipedToDelete {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   // TODO(crbug.com/851227): On UIRefresh non Compact Width on iOS11, the
   // bookmark cell is being deleted by grey_swipeFastInDirection.
   // grey_swipeFastInDirectionWithStartPoint doesn't work either and it might
   // fail on devices. Disabling this test under these conditions on the
   // meantime.
   if (@available(iOS 11, *)) {
-    if (experimental_flags::IsBookmarksUIRebootEnabled() && !IsCompactWidth()) {
-      EARL_GREY_TEST_SKIPPED(@"Test disabled on UIRefresh iPad on iOS11.");
+    if (!IsCompactWidth()) {
+      EARL_GREY_TEST_SKIPPED(@"Test disabled on iPad on iOS11.");
     }
   }
 
@@ -4514,10 +4370,6 @@
 
 // Tests that you can't search while in edit mode.
 - (void)testDisablesSearchOnEditMode {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4549,10 +4401,6 @@
 
 // Tests that new Folder is disabled when search results are shown.
 - (void)testSearchDisablesNewFolderButtonOnNavigationBar {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4576,10 +4424,6 @@
 // Tests that a single edit is possible when searching and selecting a single
 // URL in edit mode.
 - (void)testSearchEditModeEditOnSingleURL {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4623,10 +4467,6 @@
 
 // Tests that multiple deletes on search results works.
 - (void)testSearchEditModeDeleteOnMultipleURL {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4674,10 +4514,6 @@
 
 // Tests that multiple moves on search results works.
 - (void)testMoveFunctionalityOnMultipleUrlSelection {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
   [BookmarksTestCase openMobileBookmarks];
@@ -4749,10 +4585,6 @@
 
 // Tests that a search and single edit is possible when searching over root.
 - (void)testSearchEditPossibleOnRoot {
-  if (!IsUIRefreshPhase1Enabled()) {
-    EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
-  }
-
   [BookmarksTestCase setupStandardBookmarks];
   [BookmarksTestCase openBookmarks];
 
diff --git a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
index f5b4fa4..8a7ace1 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
@@ -12,8 +12,6 @@
     "bookmark_home_promo_item.mm",
     "bookmark_parent_folder_item.h",
     "bookmark_parent_folder_item.mm",
-    "bookmark_table_cell.h",
-    "bookmark_table_cell.mm",
     "bookmark_table_cell_title_edit_delegate.h",
     "bookmark_table_cell_title_editing.h",
     "bookmark_table_signin_promo_cell.h",
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm
index 830816da..c2e6812 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.mm
@@ -6,7 +6,6 @@
 
 #include "base/i18n/rtl.h"
 #include "base/mac/foundation_util.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell_title_edit_delegate.h"
@@ -45,11 +44,7 @@
 
 - (instancetype)initWithType:(NSInteger)type style:(BookmarkFolderStyle)style {
   if ((self = [super initWithType:type])) {
-    if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-      self.cellClass = [TableViewBookmarkFolderCell class];
-    } else {
-      self.cellClass = [LegacyTableViewBookmarkFolderCell class];
-    }
+    self.cellClass = [TableViewBookmarkFolderCell class];
     self.style = style;
   }
   return self;
@@ -58,61 +53,34 @@
 - (void)configureCell:(UITableViewCell*)cell
            withStyler:(ChromeTableViewStyler*)styler {
   [super configureCell:cell withStyler:styler];
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    TableViewBookmarkFolderCell* folderCell =
-        base::mac::ObjCCastStrict<TableViewBookmarkFolderCell>(cell);
-    switch (self.style) {
-      case BookmarkFolderStyleNewFolder: {
-        folderCell.folderTitleTextField.text =
-            l10n_util::GetNSString(IDS_IOS_BOOKMARK_CREATE_GROUP);
-        folderCell.folderImageView.image =
-            [UIImage imageNamed:@"bookmark_blue_new_folder"];
-        folderCell.accessibilityIdentifier =
-            kBookmarkCreateNewFolderCellIdentifier;
-        folderCell.accessibilityTraits |= UIAccessibilityTraitButton;
-        break;
-      }
-      case BookmarkFolderStyleFolderEntry: {
-        folderCell.folderTitleTextField.text = self.title;
-        folderCell.accessibilityIdentifier = self.title;
-        folderCell.accessibilityTraits |= UIAccessibilityTraitButton;
-        if (self.isCurrentFolder)
-          folderCell.bookmarkAccessoryType =
-              TableViewBookmarkFolderAccessoryTypeCheckmark;
-        // In order to indent the cell's content we need to modify its
-        // indentation constraint.
-        folderCell.indentationConstraint.constant =
-            folderCell.indentationConstraint.constant +
-            kFolderCellIndentationWidth * self.indentationLevel;
-        folderCell.folderImageView.image =
-            [UIImage imageNamed:@"bookmark_blue_folder"];
-        break;
-      }
+  TableViewBookmarkFolderCell* folderCell =
+      base::mac::ObjCCastStrict<TableViewBookmarkFolderCell>(cell);
+  switch (self.style) {
+    case BookmarkFolderStyleNewFolder: {
+      folderCell.folderTitleTextField.text =
+          l10n_util::GetNSString(IDS_IOS_BOOKMARK_CREATE_GROUP);
+      folderCell.folderImageView.image =
+          [UIImage imageNamed:@"bookmark_blue_new_folder"];
+      folderCell.accessibilityIdentifier =
+          kBookmarkCreateNewFolderCellIdentifier;
+      folderCell.accessibilityTraits |= UIAccessibilityTraitButton;
+      break;
     }
-  } else {
-    LegacyTableViewBookmarkFolderCell* folderCell =
-        base::mac::ObjCCastStrict<LegacyTableViewBookmarkFolderCell>(cell);
-    switch (self.style) {
-      case BookmarkFolderStyleNewFolder: {
-        folderCell.textLabel.text =
-            l10n_util::GetNSString(IDS_IOS_BOOKMARK_CREATE_GROUP);
-        folderCell.imageView.image =
-            [UIImage imageNamed:@"bookmark_gray_new_folder"];
-        folderCell.accessibilityIdentifier =
-            kBookmarkCreateNewFolderCellIdentifier;
-        break;
-      }
-      case BookmarkFolderStyleFolderEntry: {
-        folderCell.textLabel.text = self.title;
-        folderCell.accessibilityIdentifier = self.title;
-        folderCell.accessibilityLabel = self.title;
-        folderCell.checked = self.isCurrentFolder;
-        folderCell.indentationLevel = self.indentationLevel;
-        folderCell.indentationWidth = kFolderCellIndentationWidth;
-        folderCell.imageView.image =
-            [UIImage imageNamed:@"bookmark_gray_folder_new"];
-        break;
-      }
+    case BookmarkFolderStyleFolderEntry: {
+      folderCell.folderTitleTextField.text = self.title;
+      folderCell.accessibilityIdentifier = self.title;
+      folderCell.accessibilityTraits |= UIAccessibilityTraitButton;
+      if (self.isCurrentFolder)
+        folderCell.bookmarkAccessoryType =
+            TableViewBookmarkFolderAccessoryTypeCheckmark;
+      // In order to indent the cell's content we need to modify its
+      // indentation constraint.
+      folderCell.indentationConstraint.constant =
+          folderCell.indentationConstraint.constant +
+          kFolderCellIndentationWidth * self.indentationLevel;
+      folderCell.folderImageView.image =
+          [UIImage imageNamed:@"bookmark_blue_folder"];
+      break;
     }
   }
 }
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm
index a3292e3..6fbb999 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_node_item.mm
@@ -7,10 +7,8 @@
 #include "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_node.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_folder_item.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -23,14 +21,10 @@
 - (instancetype)initWithType:(NSInteger)type
                 bookmarkNode:(const bookmarks::BookmarkNode*)node {
   if ((self = [super initWithType:type])) {
-    if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-      if (node->is_folder()) {
-        self.cellClass = [TableViewBookmarkFolderCell class];
-      } else {
-        self.cellClass = [TableViewURLCell class];
-      }
+    if (node->is_folder()) {
+      self.cellClass = [TableViewBookmarkFolderCell class];
     } else {
-      self.cellClass = [BookmarkTableCell class];
+      self.cellClass = [TableViewURLCell class];
     }
     _bookmarkNode = node;
   }
@@ -40,33 +34,27 @@
 - (void)configureCell:(UITableViewCell*)cell
            withStyler:(ChromeTableViewStyler*)styler {
   [super configureCell:cell withStyler:styler];
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    if (_bookmarkNode->is_folder()) {
-      TableViewBookmarkFolderCell* bookmarkCell =
-          base::mac::ObjCCastStrict<TableViewBookmarkFolderCell>(cell);
-      bookmarkCell.folderTitleTextField.text =
-          bookmark_utils_ios::TitleForBookmarkNode(_bookmarkNode);
-      bookmarkCell.folderImageView.image =
-          [UIImage imageNamed:@"bookmark_blue_folder"];
-      bookmarkCell.bookmarkAccessoryType =
-          TableViewBookmarkFolderAccessoryTypeDisclosureIndicator;
-      bookmarkCell.accessibilityIdentifier =
-          bookmark_utils_ios::TitleForBookmarkNode(_bookmarkNode);
-      bookmarkCell.accessibilityTraits |= UIAccessibilityTraitButton;
-    } else {
-      TableViewURLCell* urlCell =
-          base::mac::ObjCCastStrict<TableViewURLCell>(cell);
-      urlCell.titleLabel.text =
-          bookmark_utils_ios::TitleForBookmarkNode(_bookmarkNode);
-      urlCell.URLLabel.text =
-          base::SysUTF8ToNSString(_bookmarkNode->url().host());
-      urlCell.accessibilityTraits |= UIAccessibilityTraitButton;
-      [urlCell configureUILayout];
-    }
+  if (_bookmarkNode->is_folder()) {
+    TableViewBookmarkFolderCell* bookmarkCell =
+        base::mac::ObjCCastStrict<TableViewBookmarkFolderCell>(cell);
+    bookmarkCell.folderTitleTextField.text =
+        bookmark_utils_ios::TitleForBookmarkNode(_bookmarkNode);
+    bookmarkCell.folderImageView.image =
+        [UIImage imageNamed:@"bookmark_blue_folder"];
+    bookmarkCell.bookmarkAccessoryType =
+        TableViewBookmarkFolderAccessoryTypeDisclosureIndicator;
+    bookmarkCell.accessibilityIdentifier =
+        bookmark_utils_ios::TitleForBookmarkNode(_bookmarkNode);
+    bookmarkCell.accessibilityTraits |= UIAccessibilityTraitButton;
   } else {
-    BookmarkTableCell* bookmarkCell =
-        base::mac::ObjCCastStrict<BookmarkTableCell>(cell);
-    [bookmarkCell setNode:self.bookmarkNode];
+    TableViewURLCell* urlCell =
+        base::mac::ObjCCastStrict<TableViewURLCell>(cell);
+    urlCell.titleLabel.text =
+        bookmark_utils_ios::TitleForBookmarkNode(_bookmarkNode);
+    urlCell.URLLabel.text =
+        base::SysUTF8ToNSString(_bookmarkNode->url().host());
+    urlCell.accessibilityTraits |= UIAccessibilityTraitButton;
+    [urlCell configureUILayout];
   }
 }
 
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm
index 605a1ece..7e1b1ed7 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_home_promo_item.mm
@@ -9,7 +9,6 @@
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
-#include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -36,16 +35,8 @@
   // Basic UI configuration
   signinPromoCell.signinPromoView.textLabel.text =
       l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_BOOKMARKS);
-  if (IsUIRefreshPhase1Enabled()) {
-    signinPromoCell.signinPromoView.backgroundColor =
-        styler.tableViewBackgroundColor;
-  } else {
-    signinPromoCell.signinPromoView.backgroundColor = [UIColor whiteColor];
-    signinPromoCell.signinPromoView.layer.borderColor =
-        [UIColor colorWithWhite:0.0 alpha:0.08].CGColor;
-    signinPromoCell.signinPromoView.layer.borderWidth = 1.0f;
-  }
-
+  signinPromoCell.signinPromoView.backgroundColor =
+      styler.tableViewBackgroundColor;
   // Use the mediator to configure the rest of the Cell based on the current
   // signin state.
   SigninPromoViewMediator* mediator = self.delegate.signinPromoViewMediator;
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
index e88534ac..67a345be 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.mm
@@ -6,7 +6,6 @@
 
 #include "base/i18n/rtl.h"
 #include "base/mac/foundation_util.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
@@ -29,11 +28,7 @@
   self = [super initWithType:type];
   if (self) {
     self.accessibilityIdentifier = @"Change Folder";
-    if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-      self.cellClass = [BookmarkParentFolderCell class];
-    } else {
-      self.cellClass = [LegacyBookmarkParentFolderCell class];
-    }
+    self.cellClass = [BookmarkParentFolderCell class];
   }
   return self;
 }
@@ -43,15 +38,9 @@
 - (void)configureCell:(UITableViewCell*)tableCell
            withStyler:(ChromeTableViewStyler*)styler {
   [super configureCell:tableCell withStyler:styler];
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    BookmarkParentFolderCell* cell =
-        base::mac::ObjCCastStrict<BookmarkParentFolderCell>(tableCell);
-    cell.parentFolderNameLabel.text = self.title;
-  } else {
-    LegacyBookmarkParentFolderCell* cell =
-        base::mac::ObjCCastStrict<LegacyBookmarkParentFolderCell>(tableCell);
-    cell.parentFolderNameLabel.text = self.title;
-  }
+  BookmarkParentFolderCell* cell =
+      base::mac::ObjCCastStrict<BookmarkParentFolderCell>(tableCell);
+  cell.parentFolderNameLabel.text = self.title;
 }
 
 @end
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h
deleted file mode 100644
index 452f8792..0000000
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_BOOKMARK_TABLE_CELL_H_
-#define IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_BOOKMARK_TABLE_CELL_H_
-
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell_title_editing.h"
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-
-namespace bookmarks {
-class BookmarkNode;
-}  // namespace bookmarks
-
-@class BookmarkTableCell;
-
-// Cell to display bookmark folders and URLs.
-// |---------------------------------------------|
-// |                                             |
-// |[Favicon] [title]                         [>]|
-// |                                             |
-// |---------------------------------------------|
-//
-
-@interface BookmarkTableCell : UITableViewCell<BookmarkTableCellTitleEditing>
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)reuseIdentifier
-    NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
-
-// Identifier for -[UITableView registerClass:forCellWithReuseIdentifier:].
-+ (NSString*)reuseIdentifier;
-
-// Sets the favicon image.
-- (void)setImage:(UIImage*)image;
-
-// Sets placeholder text, when favicon is missing.
-- (void)setPlaceholderText:(NSString*)text
-                 textColor:(UIColor*)textColor
-           backgroundColor:(UIColor*)backgroundColor;
-
-// Set the bookmark node this cell shows.
-- (void)setNode:(const bookmarks::BookmarkNode*)node;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_BOOKMARK_TABLE_CELL_H_
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.mm
deleted file mode 100644
index a44d5803..0000000
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.mm
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
-
-#include "components/bookmarks/browser/bookmark_model.h"
-#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell_title_edit_delegate.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Image size, in points.
-const CGFloat kBookmarkTableCellImageSize = 16.0;
-
-// Padding in table cell.
-const CGFloat kBookmarkTableCellImagePadding = 16.0;
-}  // namespace
-
-@interface BookmarkTableCell ()<UITextFieldDelegate>
-
-// Icon view.
-@property(nonatomic, weak) UIImageView* iconView;
-
-// The label, that displays placeholder text when favicon is missing.
-@property(nonatomic, strong) UILabel* placeholderLabel;
-
-// The title text.
-@property(nonatomic, strong) UITextField* titleText;
-
-// Separator view. Displayed at 1 pixel height at the bottom.
-@property(nonatomic, strong) UIView* separatorView;
-
-// Lists the accessibility elements that are to be seen by UIAccessibility.
-@property(nonatomic, readonly) NSMutableArray* accessibilityElements;
-
-// True when title text has ended editing and committed.
-@property(nonatomic, assign) BOOL isTextCommitted;
-
-@end
-
-@implementation BookmarkTableCell
-@synthesize iconView = _iconView;
-@synthesize placeholderLabel = _placeholderLabel;
-@synthesize titleText = _titleText;
-@synthesize textDelegate = _textDelegate;
-@synthesize separatorView = _separatorView;
-@synthesize accessibilityElements = _accessibilityElements;
-@synthesize isTextCommitted = _isTextCommitted;
-
-#pragma mark - Initializer
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)bookmarkCellIdentifier {
-  self = [super initWithStyle:style reuseIdentifier:bookmarkCellIdentifier];
-  if (self) {
-    _titleText = [[UITextField alloc] initWithFrame:CGRectZero];
-    _titleText.textColor = [[MDCPalette greyPalette] tint900];
-    _titleText.font = [MDCTypography subheadFont];
-    _titleText.userInteractionEnabled = NO;
-
-    // Create icon view.
-    UIImageView* iconView = [[UIImageView alloc] init];
-    _iconView = iconView;
-    [_iconView setHidden:NO];
-    [_iconView.widthAnchor
-        constraintEqualToConstant:kBookmarkTableCellImageSize]
-        .active = YES;
-    [_iconView.heightAnchor
-        constraintEqualToConstant:kBookmarkTableCellImageSize]
-        .active = YES;
-
-    // Create placeholder label.
-    _placeholderLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    _placeholderLabel.textAlignment = NSTextAlignmentCenter;
-    _placeholderLabel.font = [MDCTypography captionFont];
-    [_placeholderLabel setHidden:YES];
-    [_placeholderLabel.widthAnchor
-        constraintEqualToConstant:kBookmarkTableCellImageSize]
-        .active = YES;
-    [_placeholderLabel.heightAnchor
-        constraintEqualToConstant:kBookmarkTableCellImageSize]
-        .active = YES;
-
-    // Create and configure StackView.
-    UIStackView* contentStack = [[UIStackView alloc]
-        initWithArrangedSubviews:@[ _iconView, _placeholderLabel, _titleText ]];
-    [self.contentView addSubview:contentStack];
-    contentStack.spacing = kBookmarkTableCellImagePadding;
-    contentStack.alignment = UIStackViewAlignmentCenter;
-    contentStack.translatesAutoresizingMaskIntoConstraints = NO;
-    [NSLayoutConstraint activateConstraints:@[
-      [contentStack.topAnchor
-          constraintEqualToAnchor:self.contentView.topAnchor],
-      [contentStack.bottomAnchor
-          constraintEqualToAnchor:self.contentView.bottomAnchor],
-      [contentStack.leadingAnchor
-          constraintEqualToAnchor:self.contentView.leadingAnchor
-                         constant:kBookmarkTableCellImagePadding],
-      [contentStack.trailingAnchor
-          constraintEqualToAnchor:self.contentView.trailingAnchor
-                         constant:-kBookmarkTableCellImagePadding]
-    ]];
-
-    // Add separator view.
-    _separatorView = [[UIView alloc] initWithFrame:CGRectZero];
-    [self.contentView addSubview:_separatorView];
-
-    CGFloat pixelSize = 1 / [[UIScreen mainScreen] scale];
-    [NSLayoutConstraint activateConstraints:@[
-      [_separatorView.leadingAnchor
-          constraintEqualToAnchor:_titleText.leadingAnchor],
-      [_separatorView.trailingAnchor
-          constraintEqualToAnchor:self.trailingAnchor],
-      [_separatorView.heightAnchor constraintEqualToConstant:pixelSize],
-      [_separatorView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
-    ]];
-    _separatorView.translatesAutoresizingMaskIntoConstraints = NO;
-    _separatorView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:.12];
-
-    // Setup accessibility elements.
-    _accessibilityElements = [[NSMutableArray alloc] init];
-    self.contentView.isAccessibilityElement = YES;
-    self.contentView.accessibilityTraits |= UIAccessibilityTraitButton;
-    [_accessibilityElements addObject:self.contentView];
-  }
-  return self;
-}
-
-#pragma mark - Public
-
-- (void)setNode:(const bookmarks::BookmarkNode*)node {
-  self.titleText.text = bookmark_utils_ios::TitleForBookmarkNode(node);
-  [self updateAccessibilityValues];
-
-  if (node->is_folder()) {
-    self.iconView.image = [UIImage imageNamed:@"bookmark_gray_folder_new"];
-    [self setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
-  } else {
-    [self setAccessoryType:UITableViewCellAccessoryNone];
-  }
-}
-
-- (void)startEdit {
-  self.isTextCommitted = NO;
-  self.titleText.userInteractionEnabled = YES;
-  self.titleText.enablesReturnKeyAutomatically = YES;
-  self.titleText.keyboardType = UIKeyboardTypeDefault;
-  self.titleText.returnKeyType = UIReturnKeyDone;
-  self.titleText.accessibilityIdentifier = @"bookmark_editing_text";
-  self.accessoryType = UITableViewCellAccessoryNone;
-  [self.titleText becomeFirstResponder];
-  // selectAll doesn't work immediately after calling becomeFirstResponder.
-  // Do selectAll on the next run loop.
-  dispatch_async(dispatch_get_main_queue(), ^{
-    if ([self.titleText isFirstResponder]) {
-      [self.titleText selectAll:nil];
-    }
-  });
-  if (![self.accessibilityElements containsObject:self.titleText]) {
-    [self.accessibilityElements addObject:self.titleText];
-  }
-  self.titleText.delegate = self;
-}
-
-- (void)stopEdit {
-  if (self.isTextCommitted) {
-    return;
-  }
-  self.isTextCommitted = YES;
-  [self.textDelegate textDidChangeTo:self.titleText.text];
-  self.titleText.userInteractionEnabled = NO;
-  [self.titleText endEditing:YES];
-  [self.accessibilityElements removeObject:self.titleText];
-}
-
-+ (NSString*)reuseIdentifier {
-  return @"BookmarkTableCellIdentifier";
-}
-
-- (void)setImage:(UIImage*)image {
-  [self.iconView setHidden:NO];
-  [self.placeholderLabel setHidden:YES];
-
-  [self.iconView setImage:image];
-}
-
-- (void)setPlaceholderText:(NSString*)text
-                 textColor:(UIColor*)textColor
-           backgroundColor:(UIColor*)backgroundColor {
-  [self.iconView setHidden:YES];
-  [self.placeholderLabel setHidden:NO];
-
-  self.placeholderLabel.backgroundColor = backgroundColor;
-  self.placeholderLabel.textColor = textColor;
-  self.placeholderLabel.text = text;
-}
-
-#pragma mark - Layout
-
-- (void)prepareForReuse {
-  self.iconView.image = nil;
-  self.placeholderLabel.hidden = YES;
-  self.iconView.hidden = NO;
-  self.titleText.text = nil;
-  self.titleText.accessibilityIdentifier = nil;
-  self.titleText.userInteractionEnabled = NO;
-  [self.accessibilityElements removeObject:self.titleText];
-  self.textDelegate = nil;
-  [super prepareForReuse];
-}
-
-#pragma mark - Persist placeholder background color
-
-- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
-  // Prevent placeholderLabel's background color from being cleared.
-  UIColor* backgroundColor = self.placeholderLabel.backgroundColor;
-  [super setHighlighted:highlighted animated:animated];
-  self.placeholderLabel.backgroundColor = backgroundColor;
-}
-
-- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
-  // Prevent placeholderLabel's background color from being cleared.
-  UIColor* backgroundColor = self.placeholderLabel.backgroundColor;
-  [super setSelected:selected animated:animated];
-  self.placeholderLabel.backgroundColor = backgroundColor;
-  if (selected) {
-    self.contentView.accessibilityTraits |= UIAccessibilityTraitSelected;
-  } else {
-    self.contentView.accessibilityTraits &= ~UIAccessibilityTraitSelected;
-  }
-}
-
-#pragma mark - Accessibility
-
-- (void)updateAccessibilityValues {
-  self.contentView.accessibilityLabel = self.titleText.text;
-  self.contentView.accessibilityIdentifier = self.titleText.text;
-}
-
-- (NSInteger)accessibilityElementCount {
-  return [self.accessibilityElements count];
-}
-
-- (id)accessibilityElementAtIndex:(NSInteger)index {
-  return [self.accessibilityElements objectAtIndex:index];
-}
-
-- (NSInteger)indexOfAccessibilityElement:(id)element {
-  return [self.accessibilityElements indexOfObject:element];
-}
-
-#pragma mark - UITextFieldDelegate
-
-// This method hides the keyboard when the return key is pressed.
-- (BOOL)textFieldShouldReturn:(UITextField*)textField {
-  [self stopEdit];
-  return YES;
-}
-
-// This method is called when titleText resigns its first responder status.
-// (when return/dimiss key is pressed, or when navigating away.)
-- (void)textFieldDidEndEditing:(UITextField*)textField
-                        reason:(UITextFieldDidEndEditingReason)reason {
-  [self stopEdit];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
index 5f766d8..00feaee 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h
@@ -47,11 +47,4 @@
 
 @end
 
-@interface LegacyBookmarkTextFieldCell : UITableViewCell
-
-// Text field to display the title or the URL of the bookmark node.
-@property(nonatomic, readonly, strong) UITextField<TextFieldStyling>* textField;
-
-@end
-
 #endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_BOOKMARK_TEXT_FIELD_ITEM_H_
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
index 681c086..ddc2949 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.mm
@@ -6,7 +6,6 @@
 
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
-#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_ui_constants.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -28,11 +27,7 @@
 
 - (instancetype)initWithType:(NSInteger)type {
   self = [super initWithType:type];
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    self.cellClass = [BookmarkTextFieldCell class];
-  } else {
-    self.cellClass = [LegacyBookmarkTextFieldCell class];
-  }
+  self.cellClass = [BookmarkTextFieldCell class];
   return self;
 }
 
@@ -42,35 +37,20 @@
            withStyler:(ChromeTableViewStyler*)styler {
   [super configureCell:tableCell withStyler:styler];
 
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    BookmarkTextFieldCell* cell =
-        base::mac::ObjCCastStrict<BookmarkTextFieldCell>(tableCell);
-    cell.textField.text = self.text;
-    cell.titleLabel.text = self.placeholder;
-    cell.textField.placeholder = self.placeholder;
-    cell.textField.tag = self.type;
-    [cell.textField addTarget:self
-                       action:@selector(textFieldDidChange:)
-             forControlEvents:UIControlEventEditingChanged];
-    cell.textField.delegate = self.delegate;
-    cell.textField.accessibilityLabel = self.text;
-    cell.textField.accessibilityIdentifier = [NSString
-        stringWithFormat:@"%@_textField", self.accessibilityIdentifier];
-    cell.selectionStyle = UITableViewCellSelectionStyleNone;
-  } else {
-    LegacyBookmarkTextFieldCell* cell =
-        base::mac::ObjCCastStrict<LegacyBookmarkTextFieldCell>(tableCell);
-    cell.textField.text = self.text;
-    cell.textField.placeholder = self.placeholder;
-    cell.textField.tag = self.type;
-    [cell.textField addTarget:self
-                       action:@selector(textFieldDidChange:)
-             forControlEvents:UIControlEventEditingChanged];
-    cell.textField.delegate = self.delegate;
-    cell.textField.accessibilityLabel = self.text;
-    cell.textField.accessibilityIdentifier = [NSString
-        stringWithFormat:@"%@_textField", self.accessibilityIdentifier];
-  }
+  BookmarkTextFieldCell* cell =
+      base::mac::ObjCCastStrict<BookmarkTextFieldCell>(tableCell);
+  cell.textField.text = self.text;
+  cell.titleLabel.text = self.placeholder;
+  cell.textField.placeholder = self.placeholder;
+  cell.textField.tag = self.type;
+  [cell.textField addTarget:self
+                     action:@selector(textFieldDidChange:)
+           forControlEvents:UIControlEventEditingChanged];
+  cell.textField.delegate = self.delegate;
+  cell.textField.accessibilityLabel = self.text;
+  cell.textField.accessibilityIdentifier =
+      [NSString stringWithFormat:@"%@_textField", self.accessibilityIdentifier];
+  cell.selectionStyle = UITableViewCellSelectionStyleNone;
 }
 
 #pragma mark UIControlEventEditingChanged
@@ -168,58 +148,3 @@
 }
 
 @end
-
-#pragma mark - LegacyBookmarkTextFieldCell
-
-@interface LegacyBookmarkTextFieldCell ()
-@property(nonatomic, readwrite, strong)
-    UITextField<TextFieldStyling>* textField;
-@end
-
-@implementation LegacyBookmarkTextFieldCell
-
-@synthesize textField = _textField;
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style
-              reuseIdentifier:(NSString*)reuseIdentifier {
-  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
-  if (self) {
-    _textField =
-        ios::GetChromeBrowserProvider()->CreateStyledTextField(CGRectZero);
-    _textField.translatesAutoresizingMaskIntoConstraints = NO;
-    _textField.textColor = bookmark_utils_ios::darkTextColor();
-    _textField.clearButtonMode = UITextFieldViewModeWhileEditing;
-    _textField.placeholderStyle =
-        TextFieldStylingPlaceholderFloatingPlaceholder;
-    [self.contentView addSubview:_textField];
-    const CGFloat kHorizontalPadding = 15;
-    const CGFloat kTopPadding = 8;
-    [NSLayoutConstraint activateConstraints:@[
-      [_textField.leadingAnchor
-          constraintEqualToAnchor:self.contentView.leadingAnchor
-                         constant:kHorizontalPadding],
-      [_textField.topAnchor constraintEqualToAnchor:self.contentView.topAnchor
-                                           constant:kTopPadding],
-      [_textField.trailingAnchor
-          constraintEqualToAnchor:self.contentView.trailingAnchor
-                         constant:-kHorizontalPadding],
-      [_textField.bottomAnchor
-          constraintEqualToAnchor:self.contentView.bottomAnchor
-                         constant:-kTopPadding],
-    ]];
-  }
-  return self;
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  [self.textField resignFirstResponder];
-  [self.textField removeTarget:nil
-                        action:NULL
-              forControlEvents:UIControlEventAllEvents];
-  self.textField.delegate = nil;
-  self.textField.text = nil;
-  self.textField.textValidator = nil;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn b/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn
index b8b2c0e1..4acf390 100644
--- a/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn
@@ -4,15 +4,6 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
-imageset("bookmark_bar_innershadow") {
-  sources = [
-    "bookmark_bar_innershadow.imageset/Contents.json",
-    "bookmark_bar_innershadow.imageset/bookmark_bar_innershadow.png",
-    "bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@2x.png",
-    "bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@3x.png",
-  ]
-}
-
 imageset("bookmark_bar_shadow") {
   sources = [
     "bookmark_bar_shadow.imageset/Contents.json",
@@ -22,42 +13,6 @@
   ]
 }
 
-imageset("bookmark_black_delete") {
-  sources = [
-    "bookmark_black_delete.imageset/Contents.json",
-    "bookmark_black_delete.imageset/bookmark_black_delete.png",
-    "bookmark_black_delete.imageset/bookmark_black_delete@2x.png",
-    "bookmark_black_delete.imageset/bookmark_black_delete@3x.png",
-  ]
-}
-
-imageset("bookmark_black_edit") {
-  sources = [
-    "bookmark_black_edit.imageset/Contents.json",
-    "bookmark_black_edit.imageset/bookmark_black_edit.png",
-    "bookmark_black_edit.imageset/bookmark_black_edit@2x.png",
-    "bookmark_black_edit.imageset/bookmark_black_edit@3x.png",
-  ]
-}
-
-imageset("bookmark_black_move") {
-  sources = [
-    "bookmark_black_move.imageset/Contents.json",
-    "bookmark_black_move.imageset/bookmark_black_move.png",
-    "bookmark_black_move.imageset/bookmark_black_move@2x.png",
-    "bookmark_black_move.imageset/bookmark_black_move@3x.png",
-  ]
-}
-
-imageset("bookmark_black_select") {
-  sources = [
-    "bookmark_black_select.imageset/Contents.json",
-    "bookmark_black_select.imageset/bookmark_black_select.png",
-    "bookmark_black_select.imageset/bookmark_black_select@2x.png",
-    "bookmark_black_select.imageset/bookmark_black_select@3x.png",
-  ]
-}
-
 imageset("bookmark_blue_check") {
   sources = [
     "bookmark_blue_check.imageset/Contents.json",
@@ -93,129 +48,3 @@
     "bookmark_empty_star.imageset/bookmark_empty_star@3x.png",
   ]
 }
-
-imageset("bookmark_gray_back") {
-  sources = [
-    "bookmark_gray_back.imageset/Contents.json",
-    "bookmark_gray_back.imageset/bookmark_gray_back.png",
-    "bookmark_gray_back.imageset/bookmark_gray_back@2x.png",
-    "bookmark_gray_back.imageset/bookmark_gray_back@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_check") {
-  sources = [
-    "bookmark_gray_check.imageset/Contents.json",
-    "bookmark_gray_check.imageset/bookmark_gray_check.png",
-    "bookmark_gray_check.imageset/bookmark_gray_check@2x.png",
-    "bookmark_gray_check.imageset/bookmark_gray_check@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_close") {
-  sources = [
-    "bookmark_gray_close.imageset/Contents.json",
-    "bookmark_gray_close.imageset/bookmark_gray_close.png",
-    "bookmark_gray_close.imageset/bookmark_gray_close@2x.png",
-    "bookmark_gray_close.imageset/bookmark_gray_close@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_edit") {
-  sources = [
-    "bookmark_gray_edit.imageset/Contents.json",
-    "bookmark_gray_edit.imageset/bookmark_gray_edit.png",
-    "bookmark_gray_edit.imageset/bookmark_gray_edit@2x.png",
-    "bookmark_gray_edit.imageset/bookmark_gray_edit@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_folder") {
-  sources = [
-    "bookmark_gray_folder.imageset/Contents.json",
-    "bookmark_gray_folder.imageset/bookmark_gray_folder.png",
-    "bookmark_gray_folder.imageset/bookmark_gray_folder@2x.png",
-    "bookmark_gray_folder.imageset/bookmark_gray_folder@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_folder_new") {
-  sources = [
-    "bookmark_gray_folder_new.imageset/Contents.json",
-    "bookmark_gray_folder_new.imageset/bookmark_gray_folder_new.png",
-    "bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@2x.png",
-    "bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_menu") {
-  sources = [
-    "bookmark_gray_menu.imageset/Contents.json",
-    "bookmark_gray_menu.imageset/bookmark_gray_menu.png",
-    "bookmark_gray_menu.imageset/bookmark_gray_menu@2x.png",
-    "bookmark_gray_menu.imageset/bookmark_gray_menu@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_new_folder") {
-  sources = [
-    "bookmark_gray_new_folder.imageset/Contents.json",
-    "bookmark_gray_new_folder.imageset/bookmark_gray_new_folder.png",
-    "bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@2x.png",
-    "bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@3x.png",
-  ]
-}
-
-imageset("bookmark_gray_star_large") {
-  sources = [
-    "bookmark_gray_star_large.imageset/Contents.json",
-    "bookmark_gray_star_large.imageset/bookmark_gray_star_large.png",
-    "bookmark_gray_star_large.imageset/bookmark_gray_star_large@2x.png",
-    "bookmark_gray_star_large.imageset/bookmark_gray_star_large@3x.png",
-  ]
-}
-
-imageset("bookmark_more") {
-  sources = [
-    "bookmark_more.imageset/Contents.json",
-    "bookmark_more.imageset/bookmark_more.png",
-    "bookmark_more.imageset/bookmark_more@2x.png",
-    "bookmark_more.imageset/bookmark_more@3x.png",
-  ]
-}
-
-imageset("bookmark_white_close") {
-  sources = [
-    "bookmark_white_close.imageset/Contents.json",
-    "bookmark_white_close.imageset/bookmark_white_close.png",
-    "bookmark_white_close.imageset/bookmark_white_close@2x.png",
-    "bookmark_white_close.imageset/bookmark_white_close@3x.png",
-  ]
-}
-
-imageset("bookmark_white_delete") {
-  sources = [
-    "bookmark_white_delete.imageset/Contents.json",
-    "bookmark_white_delete.imageset/bookmark_white_delete.png",
-    "bookmark_white_delete.imageset/bookmark_white_delete@2x.png",
-    "bookmark_white_delete.imageset/bookmark_white_delete@3x.png",
-  ]
-}
-
-imageset("bookmark_white_edit") {
-  sources = [
-    "bookmark_white_edit.imageset/Contents.json",
-    "bookmark_white_edit.imageset/bookmark_white_edit.png",
-    "bookmark_white_edit.imageset/bookmark_white_edit@2x.png",
-    "bookmark_white_edit.imageset/bookmark_white_edit@3x.png",
-  ]
-}
-
-imageset("bookmark_white_move") {
-  sources = [
-    "bookmark_white_move.imageset/Contents.json",
-    "bookmark_white_move.imageset/bookmark_white_move.png",
-    "bookmark_white_move.imageset/bookmark_white_move@2x.png",
-    "bookmark_white_move.imageset/bookmark_white_move@3x.png",
-  ]
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/Contents.json
deleted file mode 100644
index 9f213be..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_bar_innershadow.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_bar_innershadow@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_bar_innershadow@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/Contents.json
deleted file mode 100644
index a3aa666..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_black_delete.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_black_delete@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_black_delete@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/Contents.json
deleted file mode 100644
index 56ca0e64..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_black_edit.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_black_edit@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_black_edit@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/Contents.json
deleted file mode 100644
index 93df647..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_black_move.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_black_move@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_black_move@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/Contents.json
deleted file mode 100644
index 7543e35..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_black_select.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_black_select@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_black_select@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/Contents.json
deleted file mode 100644
index eebfa310..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_back.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_back@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_back@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/Contents.json
deleted file mode 100644
index 036ada9f..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_check.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_check@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_check@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/Contents.json
deleted file mode 100644
index 80c2e50..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_close.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_close@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_close@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/Contents.json
deleted file mode 100644
index f96796f..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_edit.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_edit@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_edit@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/Contents.json
deleted file mode 100644
index 8b51991..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_folder.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_folder@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_folder@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/Contents.json
deleted file mode 100644
index cde60aca..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_folder_new.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_folder_new@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_folder_new@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/Contents.json
deleted file mode 100644
index 700b5a0..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_menu.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_menu@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_menu@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/Contents.json
deleted file mode 100644
index d9ed64b6..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_new_folder.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_new_folder@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_new_folder@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/Contents.json
deleted file mode 100644
index a720adc..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_gray_star_large.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_gray_star_large@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_gray_star_large@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/Contents.json
deleted file mode 100644
index 14ca574..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_more.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_more@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_more@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/Contents.json
deleted file mode 100644
index 6c2600bc..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_white_close.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_white_close@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_white_close@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/Contents.json
deleted file mode 100644
index 4fab163..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_white_delete.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_white_delete@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_white_delete@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/Contents.json
deleted file mode 100644
index d87726c..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_white_edit.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_white_edit@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_white_edit@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/Contents.json
deleted file mode 100644
index 2c970e3..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_white_move.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_white_move@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_white_move@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator.h b/ios/chrome/browser/ui/reading_list/reading_list_mediator.h
index 6bcd919..7c15ff7 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator.h
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator.h
@@ -9,10 +9,6 @@
 
 #import "ios/chrome/browser/ui/reading_list/reading_list_data_source.h"
 
-namespace favicon {
-class LargeIconService;
-}
-
 class FaviconLoader;
 class GURL;
 class ReadingListEntry;
@@ -24,16 +20,11 @@
 
 - (nullable instancetype)init NS_UNAVAILABLE;
 
-// TODO(crbug.com/878796): Deprecated. Remove this as part of UIRefresh cleanup.
-- (nullable instancetype)
-   initWithModel:(nonnull ReadingListModel*)model
-largeIconService:(nonnull favicon::LargeIconService*)largeIconService
- listItemFactory:(nonnull ReadingListListItemFactory*)itemFactory;
-
 - (nullable instancetype)initWithModel:(nonnull ReadingListModel*)model
                          faviconLoader:(nonnull FaviconLoader*)faviconLoader
                        listItemFactory:
-                           (nonnull ReadingListListItemFactory*)itemFactory;
+                           (nonnull ReadingListListItemFactory*)itemFactory
+    NS_DESIGNATED_INITIALIZER;
 
 // Returns the entry corresponding to the |item|. The item should be of type
 // ReadingListCollectionViewItem. Returns nullptr if there is no corresponding
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm b/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm
index ab607f1..cb41283 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator.mm
@@ -9,13 +9,11 @@
 #import "base/mac/foundation_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
-#include "components/favicon/core/large_icon_service.h"
 #include "components/reading_list/core/reading_list_model.h"
 #import "components/reading_list/ios/reading_list_model_bridge_observer.h"
 #include "components/url_formatter/url_formatter.h"
 #import "ios/chrome/browser/favicon/favicon_loader.h"
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
-#import "ios/chrome/browser/ui/favicon/favicon_attributes_provider.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_data_sink.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_list_item_factory.h"
@@ -55,13 +53,6 @@
 // The ListItem factory passed on initialization.
 @property(nonatomic, strong) ReadingListListItemFactory* itemFactory;
 
-// Lazily instantiated.
-@property(nonatomic, strong, readonly)
-    FaviconAttributesProvider* attributesProvider;
-
-@property(nonatomic, assign, readonly)
-    favicon::LargeIconService* largeIconService;
-
 // Favicon Service used for UIRefresh Collections.
 @property(nonatomic, assign, readonly) FaviconLoader* faviconLoader;
 
@@ -73,29 +64,11 @@
 @synthesize model = _model;
 @synthesize shouldMonitorModel = _shouldMonitorModel;
 @synthesize itemFactory = _itemFactory;
-@synthesize attributesProvider = _attributesProvider;
-@synthesize largeIconService = _largeIconService;
 @synthesize faviconLoader = _faviconLoader;
 
 #pragma mark - Public
 
 - (instancetype)initWithModel:(ReadingListModel*)model
-             largeIconService:(favicon::LargeIconService*)largeIconService
-              listItemFactory:(ReadingListListItemFactory*)itemFactory {
-  self = [super init];
-  if (self) {
-    _model = model;
-    _largeIconService = largeIconService;
-    _itemFactory = itemFactory;
-    _shouldMonitorModel = YES;
-
-    // This triggers the callback method. Should be created last.
-    _modelBridge.reset(new ReadingListModelBridge(self, model));
-  }
-  return self;
-}
-
-- (instancetype)initWithModel:(ReadingListModel*)model
                 faviconLoader:(nonnull FaviconLoader*)faviconLoader
               listItemFactory:(ReadingListListItemFactory*)itemFactory {
   self = [super init];
@@ -195,17 +168,11 @@
 
         [strongSelf.dataSink itemHasChangedAfterDelay:strongItem];
       };
-  if (self.faviconLoader) {
     FaviconAttributes* cachedAttributes = self.faviconLoader->FaviconForUrl(
         item.faviconPageURL, kFaviconMinWidthHeight, kFaviconWidthHeight,
         /*fallback_to_google_server=*/false, completionBlock);
     DCHECK(cachedAttributes);
     return completionBlock(cachedAttributes);
-  } else {
-    DCHECK(self.attributesProvider);
-    [self.attributesProvider fetchFaviconAttributesForURL:item.faviconPageURL
-                                               completion:completionBlock];
-  }
 }
 
 - (void)beginBatchUpdates {
@@ -220,21 +187,6 @@
 
 #pragma mark - Properties
 
-- (FaviconAttributesProvider*)attributesProvider {
-  if (_attributesProvider) {
-    return _attributesProvider;
-  }
-  DCHECK(self.largeIconService);
-  // Accept any favicon even the smallest ones (16x16) as it is better than the
-  // fallback icon.
-  // Pass 1 as minimum size to avoid empty favicons.
-  _attributesProvider = [[FaviconAttributesProvider alloc]
-      initWithFaviconSize:kFaviconPreferredSize
-           minFaviconSize:1
-         largeIconService:self.largeIconService];
-  return _attributesProvider;
-}
-
 - (void)setDataSink:(id<ReadingListDataSink>)dataSink {
   _dataSink = dataSink;
   if (self.model->loaded()) {
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
index b3100f9..097c8b7c 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_mediator_unittest.mm
@@ -70,18 +70,11 @@
     large_icon_service_.reset(new favicon::LargeIconService(
         &mock_favicon_service_, /*image_fetcher=*/nullptr));
 
-    if (GetParam() == FaviconServiceType::FAVICON_LOADER) {
       favicon_loader.reset(new FaviconLoader(large_icon_service_.get()));
       mediator_ = [[ReadingListMediator alloc]
             initWithModel:model_.get()
             faviconLoader:favicon_loader.get()
           listItemFactory:[[ReadingListListItemFactory alloc] init]];
-    } else {
-      mediator_ = [[ReadingListMediator alloc]
-             initWithModel:model_.get()
-          largeIconService:large_icon_service_.get()
-           listItemFactory:[[ReadingListListItemFactory alloc] init]];
-    }
   }
 
  protected:
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn
index 50d039d..b712648 100644
--- a/ios/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -9,6 +9,8 @@
     "about_chrome_collection_view_controller.mm",
     "accounts_collection_view_controller.h",
     "accounts_collection_view_controller.mm",
+    "alpha_animated_collection_view_flow_layout.h",
+    "alpha_animated_collection_view_flow_layout.mm",
     "autofill_credit_card_collection_view_controller.h",
     "autofill_credit_card_collection_view_controller.mm",
     "autofill_credit_card_edit_collection_view_controller.h",
diff --git a/ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.h b/ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.h
new file mode 100644
index 0000000..a3e5ce9
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.h
@@ -0,0 +1,15 @@
+// Copyright 2018 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 IOS_CHROME_BROWSER_UI_SETTINGS_ALPHA_ANIMATED_COLLECTION_VIEW_FLOW_LAYOUT_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_ALPHA_ANIMATED_COLLECTION_VIEW_FLOW_LAYOUT_H_
+
+#import "ios/third_party/material_components_ios/src/components/Collections/src/MDCCollectionViewFlowLayout.h"
+
+// An |MDCCollectionViewFlowLayout| that uses alpha for animation, which makes
+// rotation on the device look smoother.
+@interface AlphaAnimatedCollectionViewFlowLayout : MDCCollectionViewFlowLayout
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_ALPHA_ANIMATED_COLLECTION_VIEW_FLOW_LAYOUT_H_
diff --git a/ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.mm b/ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.mm
new file mode 100644
index 0000000..313bddc
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.mm
@@ -0,0 +1,61 @@
+// Copyright 2018 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.
+
+#import "ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.h"
+
+#import <UIKit/UIKit.h>
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation AlphaAnimatedCollectionViewFlowLayout
+
+- (UICollectionViewLayoutAttributes*)
+initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath*)itemIndexPath {
+  UICollectionViewLayoutAttributes* attr = [[super
+      initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath] copy];
+  attr.alpha = 0;
+  return attr;
+}
+
+- (UICollectionViewLayoutAttributes*)
+initialLayoutAttributesForAppearingSupplementaryElementOfKind:
+    (NSString*)elementKind
+                                                  atIndexPath:
+                                                      (NSIndexPath*)
+                                                          elementIndexPath {
+  UICollectionViewLayoutAttributes* attr = [[super
+      initialLayoutAttributesForAppearingSupplementaryElementOfKind:elementKind
+                                                        atIndexPath:
+                                                            elementIndexPath]
+      copy];
+  attr.alpha = 0;
+  return attr;
+}
+
+- (UICollectionViewLayoutAttributes*)
+finalLayoutAttributesForDisappearingItemAtIndexPath:
+    (NSIndexPath*)itemIndexPath {
+  UICollectionViewLayoutAttributes* attr = [[super
+      finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath] copy];
+  attr.alpha = 0;
+  return attr;
+}
+
+- (UICollectionViewLayoutAttributes*)
+finalLayoutAttributesForDisappearingSupplementaryElementOfKind:
+    (NSString*)elementKind
+                                                   atIndexPath:
+                                                       (NSIndexPath*)
+                                                           elementIndexPath {
+  UICollectionViewLayoutAttributes* attr = [[super
+      finalLayoutAttributesForDisappearingSupplementaryElementOfKind:elementKind
+                                                         atIndexPath:
+                                                             elementIndexPath]
+      copy];
+  attr.alpha = 0;
+  return attr;
+}
+@end
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module.mm b/ios/chrome/browser/ui/settings/reauthentication_module.mm
index f13aa6d..07e34e8 100644
--- a/ios/chrome/browser/ui/settings/reauthentication_module.mm
+++ b/ios/chrome/browser/ui/settings/reauthentication_module.mm
@@ -41,7 +41,7 @@
 
 - (BOOL)canAttemptReauth {
   LAContext* context = _createLAContext();
-  // The authentication method is Touch ID or passcode.
+  // The authentication method is Touch ID, Face ID or passcode.
   return
       [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:nil];
 }
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
index 0528f3c..cefdfb2b 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -35,6 +35,7 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
+#import "ios/chrome/browser/ui/settings/alpha_animated_collection_view_flow_layout.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_search_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h"
@@ -216,7 +217,8 @@
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
   DCHECK(browserState);
-  UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
+  MDCCollectionViewFlowLayout* layout =
+      [[AlphaAnimatedCollectionViewFlowLayout alloc] init];
   self =
       [super initWithLayout:layout style:CollectionViewControllerStyleAppBar];
   if (self) {
diff --git a/ios/chrome/browser/ui/util/BUILD.gn b/ios/chrome/browser/ui/util/BUILD.gn
index 850fb7af..9b6a71f7 100644
--- a/ios/chrome/browser/ui/util/BUILD.gn
+++ b/ios/chrome/browser/ui/util/BUILD.gn
@@ -11,8 +11,6 @@
     "core_text_util.mm",
     "force_touch_long_press_gesture_recognizer.h",
     "force_touch_long_press_gesture_recognizer.mm",
-    "form_sheet_navigation_controller.h",
-    "form_sheet_navigation_controller.mm",
     "i18n_string.h",
     "i18n_string.mm",
     "label_link_controller.h",
diff --git a/ios/chrome/browser/ui/util/form_sheet_navigation_controller.h b/ios/chrome/browser/ui/util/form_sheet_navigation_controller.h
deleted file mode 100644
index c1315c2..0000000
--- a/ios/chrome/browser/ui/util/form_sheet_navigation_controller.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_UTIL_FORM_SHEET_NAVIGATION_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_UTIL_FORM_SHEET_NAVIGATION_CONTROLLER_H_
-
-#import <UIKit/UIKit.h>
-
-// A navigation controller subclass that respects the
-// disablesAutomaticKeyboardDismissal of its top view controller. This is useful
-// when presenting some view controllers in a navigation controller with
-// UIModalPresentationFormSheet.
-@interface FormSheetNavigationController : UINavigationController
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_UTIL_FORM_SHEET_NAVIGATION_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/util/form_sheet_navigation_controller.mm b/ios/chrome/browser/ui/util/form_sheet_navigation_controller.mm
deleted file mode 100644
index ceb16e7..0000000
--- a/ios/chrome/browser/ui/util/form_sheet_navigation_controller.mm
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/util/form_sheet_navigation_controller.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation FormSheetNavigationController
-
-- (BOOL)disablesAutomaticKeyboardDismissal {
-  return self.topViewController.disablesAutomaticKeyboardDismissal;
-}
-
-@end
diff --git a/ios/third_party/firebase/BUILD.gn b/ios/third_party/firebase/BUILD.gn
index e947febe..9fa73ea2 100644
--- a/ios/third_party/firebase/BUILD.gn
+++ b/ios/third_party/firebase/BUILD.gn
@@ -2,13 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//ios/third_party/firebase/firebase.gni")
-
 source_set("firebase") {
-  assert(
-      ios_firebase_resources_target != "",
-      "ios_firebase_resources_target must be defined if Firebase SDK is enabled.")
-
   # From gn documentation:
   #   https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/reference.md#ldflags
   # "ldflags are NOT pushed to dependents, so applying ldflags to source sets
@@ -19,9 +13,6 @@
   # This source_set must be specified as a direct deps of an ios_app_bundle
   # target for ldflags specified in :firebase_config to be applied.
   public_configs = [ ":firebase_config" ]
-  deps = [
-    ios_firebase_resources_target,
-  ]
 }
 
 config("firebase_config") {
diff --git a/ios/web/public/web_task_traits.h b/ios/web/public/web_task_traits.h
index 260c03999..88dafe7 100644
--- a/ios/web/public/web_task_traits.h
+++ b/ios/web/public/web_task_traits.h
@@ -31,6 +31,10 @@
 // To obtain a TaskRunner for the UI thread (analogous for the IO thread):
 //     base::CreateSingleThreadTaskRunnerWithTraits({WebThread::UI});
 //
+// Tasks posted to the same WebThread with the same traits will be executed
+// in the order they were posted, regardless of the TaskRunners they were
+// posted via.
+//
 // See //base/task/post_task.h for more detailed documentation.
 //
 // Posting to a WebThread must only be done after it was initialized (ref.
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 33b6fd5..ea33a51 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -265,7 +265,6 @@
   "//components/password_manager/core/browser/form_parsing:form_parsing",
   "//components/password_manager/core/common",
   "//components/password_manager/ios",
-  "//components/password_manager/sync/browser",
   "//components/pref_registry",
   "//components/prefs",
   "//components/proxy_config",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index 7636c26..e8b462e 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -15,7 +15,6 @@
   "+components/net_log",
   "+components/password_manager/core",
   "+components/password_manager/ios",
-  "+components/password_manager/sync",
   "+components/pref_registry",
   "+components/prefs",
   "+components/proxy_config",
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 2ec1c6b..e8e21cb 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -18,8 +18,8 @@
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/keyed_service/core/service_access_type.h"
+#include "components/password_manager/core/browser/password_model_worker.h"
 #include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/sync/browser/password_model_worker.h"
 #include "components/sync/driver/sync_api_component_factory.h"
 #include "components/sync/driver/sync_util.h"
 #include "components/sync/engine/passive_model_worker.h"
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index e017324..1541631 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -96,6 +96,7 @@
       params_(params),
       handler_(handler),
       task_runner_(audio_manager->GetTaskRunner()),
+      construction_time_(base::TimeTicks::Now()),
       output_device_id_(output_device_id),
       stream_(NULL),
       diverting_to_stream_(NULL),
@@ -118,6 +119,8 @@
   CHECK_EQ(kClosed, state_);
   CHECK_EQ(nullptr, stream_);
   CHECK(duplication_targets_.empty());
+  UMA_HISTOGRAM_LONG_TIMES("Media.AudioOutputController.LifeTime",
+                           base::TimeTicks::Now() - construction_time_);
 }
 
 // static
diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h
index 8c8afe5..a76ef38 100644
--- a/media/audio/audio_output_controller.h
+++ b/media/audio/audio_output_controller.h
@@ -276,6 +276,10 @@
   // The message loop of audio manager thread that this object runs on.
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  // Time when the controller is constructed. Used to record its lifetime on
+  // destruction.
+  const base::TimeTicks construction_time_;
+
   // Specifies the device id of the output device to open or empty for the
   // default output device.
   std::string output_device_id_;
diff --git a/media/capture/video/video_capture_device_unittest.cc b/media/capture/video/video_capture_device_unittest.cc
index 464def1..de269cd9 100644
--- a/media/capture/video/video_capture_device_unittest.cc
+++ b/media/capture/video/video_capture_device_unittest.cc
@@ -377,6 +377,17 @@
     return true;
   }
 
+  gfx::Size GetSupportedCaptureSize(
+      const VideoCaptureDeviceDescriptor& device) {
+    VideoCaptureFormats supported_formats;
+    video_capture_device_factory_->GetSupportedFormats(device,
+                                                       &supported_formats);
+    if (supported_formats.size() == 0)
+      return gfx::Size(0, 0);
+
+    return supported_formats.begin()->frame_size;
+  }
+
 #if defined(OS_WIN)
   base::win::ScopedCOMInitializer initialize_com_;
 #endif
@@ -615,6 +626,10 @@
   if (!descriptor)
     return;
 
+  const gfx::Size frame_size = GetSupportedCaptureSize(*descriptor);
+  if (frame_size == gfx::Size(0, 0))
+    return;
+
 #if defined(OS_ANDROID)
   // TODO(mcasas): fails on Lollipop devices, reconnect https://crbug.com/646840
   if (base::android::BuildInfo::GetInstance()->sdk_int() <
@@ -631,7 +646,7 @@
   EXPECT_CALL(*video_capture_client_, OnStarted());
 
   VideoCaptureParams capture_params;
-  capture_params.requested_format.frame_size.SetSize(320, 240);
+  capture_params.requested_format.frame_size = frame_size;
   capture_params.requested_format.frame_rate = 30;
   capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
   device->AllocateAndStart(capture_params, std::move(video_capture_client_));
@@ -657,6 +672,10 @@
   if (!descriptor)
     return;
 
+  const gfx::Size frame_size = GetSupportedCaptureSize(*descriptor);
+  if (frame_size == gfx::Size(0, 0))
+    return;
+
 #if defined(OS_ANDROID)
   // TODO(mcasas): fails on Lollipop devices, reconnect https://crbug.com/646840
   if (base::android::BuildInfo::GetInstance()->sdk_int() <
@@ -673,7 +692,7 @@
   EXPECT_CALL(*video_capture_client_, OnStarted());
 
   VideoCaptureParams capture_params;
-  capture_params.requested_format.frame_size.SetSize(320, 240);
+  capture_params.requested_format.frame_size = frame_size;
   capture_params.requested_format.frame_rate = 30;
   capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
   device->AllocateAndStart(capture_params, std::move(video_capture_client_));
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 0602a87..cb6adb2 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -1566,6 +1566,7 @@
 }
 
 double VEAClient::frames_per_second() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   LOG_ASSERT(num_encoded_frames_ != 0UL);
   base::TimeDelta duration = last_frame_ready_time_ - first_frame_start_time_;
   return num_encoded_frames_ / duration.InSecondsF();
@@ -1626,6 +1627,7 @@
 }
 
 void VEAClient::VerifyOutputTimestamp(base::TimeDelta timestamp) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   // One input frame may be mapped to multiple output frames, so the current
   // timestamp should be equal to previous timestamp or the top of
   // frame_timestamps_.
@@ -1929,6 +1931,7 @@
 }
 
 void VEAClient::LogPerf() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   g_env->LogToFile("Measured encoder FPS",
                    base::StringPrintf("%.3f", frames_per_second()));
 
@@ -2000,11 +2003,13 @@
 }
 
 void VEAClient::VerifyMinFPS() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (test_perf_)
     EXPECT_GE(frames_per_second(), kMinPerfFPS);
 }
 
 void VEAClient::VerifyStreamProperties() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   LOG_ASSERT(num_frames_since_last_check_ > 0UL);
   LOG_ASSERT(encoded_stream_size_since_last_check_ > 0UL);
   unsigned int bitrate = static_cast<unsigned int>(
@@ -2025,8 +2030,8 @@
 }
 
 void VEAClient::WriteIvfFileHeader() {
+  DCHECK(thread_checker_.CalledOnValidThread());
   IvfFileHeader header = {};
-
   memcpy(header.signature, kIvfHeaderSignature, sizeof(header.signature));
   header.version = 0;
   header.header_size = sizeof(header);
@@ -2046,6 +2051,7 @@
 }
 
 void VEAClient::WriteIvfFrameHeader(int frame_index, size_t frame_size) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   IvfFrameHeader header = {};
 
   header.frame_size = static_cast<uint32_t>(frame_size);
@@ -2145,6 +2151,7 @@
 
 void SimpleVEAClientBase::FeedEncoderWithOutput(base::SharedMemory* shm,
                                                 size_t output_size) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (!has_encoder())
     return;
 
diff --git a/media/midi/midi_manager.cc b/media/midi/midi_manager.cc
index cf62e189..913faca 100644
--- a/media/midi/midi_manager.cc
+++ b/media/midi/midi_manager.cc
@@ -58,20 +58,11 @@
 
 }  // namespace
 
-MidiManager::MidiManager(MidiService* service)
-    : initialization_state_(InitializationState::NOT_STARTED),
-      finalized_(false),
-      result_(Result::NOT_INITIALIZED),
-      data_sent_(false),
-      data_received_(false),
-      service_(service) {
+MidiManager::MidiManager(MidiService* service) : service_(service) {
   ReportUsage(Usage::CREATED);
 }
 
 MidiManager::~MidiManager() {
-  // Make sure that Finalize() is called to clean up resources allocated on
-  // the Chrome_IOThread.
-  base::AutoLock auto_lock(lock_);
   CHECK(finalized_);
 }
 
@@ -85,12 +76,13 @@
 
 void MidiManager::Shutdown() {
   Finalize();
+  finalized_ = true;
 
   base::AutoLock auto_lock(lock_);
-  if (session_thread_runner_)
+  if (session_thread_runner_) {
     DCHECK(session_thread_runner_->BelongsToCurrentThread());
-
-  finalized_ = true;
+    session_thread_runner_ = nullptr;
+  }
 
   UMA_HISTOGRAM_ENUMERATION("Media.Midi.ResultOnShutdown", result_,
                             static_cast<Sample>(Result::MAX) + 1);
@@ -110,18 +102,16 @@
   for (auto* client : clients_)
     client->Detach();
   clients_.clear();
-
-  session_thread_runner_ = nullptr;
 }
 
 void MidiManager::StartSession(MidiManagerClient* client) {
+  DCHECK(!finalized_);
   ReportUsage(Usage::SESSION_STARTED);
 
   bool needs_initialization = false;
 
   {
     base::AutoLock auto_lock(lock_);
-    DCHECK(!finalized_);
 
     if (clients_.find(client) != clients_.end() ||
         pending_clients_.find(client) != pending_clients_.end()) {
@@ -207,22 +197,23 @@
 }
 
 void MidiManager::CompleteInitialization(Result result) {
+  DCHECK(!finalized_);
+  DCHECK_EQ(InitializationState::STARTED, initialization_state_);
+
   TRACE_EVENT0("midi", "MidiManager::CompleteInitialization");
   ReportUsage(Usage::INITIALIZED);
 
   base::AutoLock auto_lock(lock_);
+  if (!session_thread_runner_)
+    return;
+  DCHECK(session_thread_runner_->BelongsToCurrentThread());
+
   UMA_HISTOGRAM_ENUMERATION("Media.Midi.InputPorts", input_ports_.size(),
                             kMaxUmaDevices + 1);
   UMA_HISTOGRAM_ENUMERATION("Media.Midi.OutputPorts", output_ports_.size(),
                             kMaxUmaDevices + 1);
 
-  if (!session_thread_runner_)
-    return;
-  DCHECK(session_thread_runner_->BelongsToCurrentThread());
-
-  DCHECK(!finalized_);
   DCHECK(clients_.empty());
-  DCHECK_EQ(initialization_state_, InitializationState::STARTED);
   initialization_state_ = InitializationState::COMPLETED;
   result_ = result;
 
@@ -300,4 +291,13 @@
     client->ReceiveMidiData(port_index, data, length, timestamp);
 }
 
+size_t MidiManager::GetClientCountForTesting() {
+  base::AutoLock auto_lock(lock_);
+  return clients_.size();
+}
+
+size_t MidiManager::GetPendingClientCountForTesting() {
+  return pending_clients_.size();
+}
+
 }  // namespace midi
diff --git a/media/midi/midi_manager.h b/media/midi/midi_manager.h
index 183bf57..5b0ad08e 100644
--- a/media/midi/midi_manager.h
+++ b/media/midi/midi_manager.h
@@ -165,10 +165,8 @@
                        base::TimeTicks time);
 
   // Only for testing.
-  size_t clients_size_for_testing() const { return clients_.size(); }
-  size_t pending_clients_size_for_testing() const {
-    return pending_clients_.size();
-  }
+  size_t GetClientCountForTesting();
+  size_t GetPendingClientCountForTesting();
 
   MidiService* service() { return service_; }
 
@@ -179,34 +177,38 @@
     COMPLETED,
   };
 
-  // Keeps track of all clients who wish to receive MIDI data.
-  // TODO(toyoshim): Enable GUARDED_BY once a testing function is fixed.
-  std::set<MidiManagerClient*> clients_;  // GUARDED_BY(lock_);
+  // Note: Members that are not protected by any lock should be accessed only on
+  // the I/O thread.
+
+  // Tracks platform dependent initialization state.
+  InitializationState initialization_state_ = InitializationState::NOT_STARTED;
+
+  // Keeps false until Finalize() is called.
+  bool finalized_ = false;
+
+  // Keeps the platform dependent initialization result if initialization is
+  // completed. Otherwise keeps mojom::Result::NOT_INITIALIZED.
+  mojom::Result result_ = mojom::Result::NOT_INITIALIZED;
 
   // Keeps track of all clients who are waiting for CompleteStartSession().
   std::set<MidiManagerClient*> pending_clients_;
 
+  // Keeps track of all clients who wish to receive MIDI data.
+  std::set<MidiManagerClient*> clients_ GUARDED_BY(lock_);
+
   // Keeps a SingleThreadTaskRunner of the thread that calls StartSession in
-  // order to invoke CompleteStartSession() on the thread.
-  scoped_refptr<base::SingleThreadTaskRunner> session_thread_runner_;
-
-  // Tracks platform dependent initialization state.
-  InitializationState initialization_state_;
-
-  // Keeps false until Finalize() is called.
-  bool finalized_;
-
-  // Keeps the platform dependent initialization result if initialization is
-  // completed. Otherwise keeps mojom::Result::NOT_INITIALIZED.
-  mojom::Result result_;
+  // order to invoke CompleteStartSession() on the thread. This is touched only
+  // on the IO thread usually, but to be guarded by |lock_| for thread checks.
+  scoped_refptr<base::SingleThreadTaskRunner> session_thread_runner_
+      GUARDED_BY(lock_);
 
   // Keeps all MidiPortInfo.
   MidiPortInfoList input_ports_ GUARDED_BY(lock_);
   MidiPortInfoList output_ports_ GUARDED_BY(lock_);
 
   // Tracks if actual data transmission happens.
-  bool data_sent_ GUARDED_BY(lock_);
-  bool data_received_ GUARDED_BY(lock_);
+  bool data_sent_ GUARDED_BY(lock_) = false;
+  bool data_received_ GUARDED_BY(lock_) = false;
 
   // Protects members above.
   base::Lock lock_;
diff --git a/media/midi/midi_manager_unittest.cc b/media/midi/midi_manager_unittest.cc
index 691d70c..d55ca672 100644
--- a/media/midi/midi_manager_unittest.cc
+++ b/media/midi/midi_manager_unittest.cc
@@ -59,13 +59,9 @@
     CompleteInitialization(result);
   }
 
-  size_t GetClientCount() const {
-    return clients_size_for_testing();
-  }
+  size_t GetClientCount() { return GetClientCountForTesting(); }
 
-  size_t GetPendingClientCount() const {
-    return pending_clients_size_for_testing();
-  }
+  size_t GetPendingClientCount() { return GetPendingClientCountForTesting(); }
 
   bool IsInitialized() const { return initialized_; }
 
diff --git a/media/midi/midi_manager_winrt.cc b/media/midi/midi_manager_winrt.cc
index e2ae5e4..b8796583 100644
--- a/media/midi/midi_manager_winrt.cc
+++ b/media/midi/midi_manager_winrt.cc
@@ -850,6 +850,7 @@
                                        const std::vector<uint8_t>& data) {
   DCHECK(service()->task_service()->IsOnTaskRunner(kComTaskRunner));
 
+  base::AutoLock auto_lock(lazy_init_member_lock_);
   MidiPort<IMidiOutPort>* port = port_manager_out_->GetPortByIndex(port_index);
   if (!(port && port->handle)) {
     VLOG(1) << "Port not available: " << port_index;
diff --git a/media/midi/midi_manager_winrt.h b/media/midi/midi_manager_winrt.h
index aee6353..e083a6d 100644
--- a/media/midi/midi_manager_winrt.h
+++ b/media/midi/midi_manager_winrt.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/strings/string16.h"
+#include "base/thread_annotations.h"
 #include "media/midi/midi_manager.h"
 
 namespace midi {
@@ -52,10 +53,10 @@
   base::Lock lazy_init_member_lock_;
 
   // All operations to Midi{In|Out}PortManager should be done on kComTaskRunner.
-  std::unique_ptr<MidiInPortManager>
-      port_manager_in_;  // GUARDED_BY(lazy_init_member_lock_)
-  std::unique_ptr<MidiOutPortManager>
-      port_manager_out_;  // GUARDED_BY(lazy_init_member_lock_)
+  std::unique_ptr<MidiInPortManager> port_manager_in_
+      GUARDED_BY(lazy_init_member_lock_);
+  std::unique_ptr<MidiOutPortManager> port_manager_out_
+      GUARDED_BY(lazy_init_member_lock_);
 
   // Incremented when a MidiPortManager is ready.
   uint8_t port_manager_ready_count_ = 0;
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index 3797c91..1a72bc45 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -440,15 +440,23 @@
 
 bool BaseTestServer::LoadTestRootCert() const {
   TestRootCerts* root_certs = TestRootCerts::GetInstance();
-  if (!root_certs)
-    return false;
+  DCHECK(root_certs);
 
   // Should always use absolute path to load the root certificate.
   base::FilePath root_certificate_path;
-  if (!GetLocalCertificatesDir(certificates_dir_, &root_certificate_path))
+  if (!GetLocalCertificatesDir(certificates_dir_, &root_certificate_path)) {
+    LOG(ERROR) << "Could not get local certificates directory from "
+               << certificates_dir_ << ".";
     return false;
+  }
 
-  return RegisterRootCertsInternal(root_certificate_path);
+  if (!RegisterRootCertsInternal(root_certificate_path)) {
+    LOG(ERROR) << "Could not register root certificates from "
+               << root_certificate_path << ".";
+    return false;
+  }
+
+  return true;
 }
 
 scoped_refptr<X509Certificate> BaseTestServer::GetCertificate() const {
@@ -520,8 +528,10 @@
   DCHECK(host_port_pair_.port());
   DCHECK(!started_);
 
-  if (UsingSSL(type_) && !LoadTestRootCert())
-      return false;
+  if (UsingSSL(type_) && !LoadTestRootCert()) {
+    LOG(ERROR) << "Could not load test root certificate.";
+    return false;
+  }
 
   started_ = true;
   allowed_port_.reset(new ScopedPortException(host_port_pair_.port()));
diff --git a/net/test/spawned_test_server/local_test_server.cc b/net/test/spawned_test_server/local_test_server.cc
index c4378a5..689effb 100644
--- a/net/test/spawned_test_server/local_test_server.cc
+++ b/net/test/spawned_test_server/local_test_server.cc
@@ -95,14 +95,20 @@
 
   // Get path to Python server script.
   base::FilePath testserver_path;
-  if (!GetTestServerPath(&testserver_path))
+  if (!GetTestServerPath(&testserver_path)) {
+    LOG(ERROR) << "Could not get test server path.";
     return false;
+  }
 
-  if (!SetPythonPath())
+  if (!SetPythonPath()) {
+    LOG(ERROR) << "Could not set Python path.";
     return false;
+  }
 
-  if (!LaunchPython(testserver_path))
+  if (!LaunchPython(testserver_path)) {
+    LOG(ERROR) << "Could not launch Python with path " << testserver_path;
     return false;
+  }
 
   return true;
 }
diff --git a/net/third_party/spdy/core/hpack/hpack_entry.cc b/net/third_party/spdy/core/hpack/hpack_entry.cc
index cd14bdf..216438c 100644
--- a/net/third_party/spdy/core/hpack/hpack_entry.cc
+++ b/net/third_party/spdy/core/hpack/hpack_entry.cc
@@ -53,6 +53,8 @@
   insertion_index_ = other.insertion_index_;
   type_ = other.type_;
   if (type_ == LOOKUP) {
+    name_.clear();
+    value_.clear();
     name_ref_ = other.name_ref_;
     value_ref_ = other.value_ref_;
     return *this;
diff --git a/services/audio/output_controller.cc b/services/audio/output_controller.cc
index 00e503a..96f1105 100644
--- a/services/audio/output_controller.cc
+++ b/services/audio/output_controller.cc
@@ -127,6 +127,7 @@
       params_(params),
       handler_(handler),
       task_runner_(audio_manager->GetTaskRunner()),
+      construction_time_(base::TimeTicks::Now()),
       output_device_id_(output_device_id),
       stream_(NULL),
       disable_local_output_(false),
@@ -153,6 +154,8 @@
   DCHECK_EQ(nullptr, stream_);
   DCHECK(snoopers_.empty());
   DCHECK(should_duplicate_.IsZero());
+  UMA_HISTOGRAM_LONG_TIMES("Media.AudioOutputController.LifeTime",
+                           base::TimeTicks::Now() - construction_time_);
 }
 
 bool OutputController::Create(bool is_for_device_change) {
diff --git a/services/audio/output_controller.h b/services/audio/output_controller.h
index 3589f132..772d71e 100644
--- a/services/audio/output_controller.h
+++ b/services/audio/output_controller.h
@@ -242,6 +242,10 @@
   // via tasks run by this TaskRunner.
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
+  // Time when the controller is constructed. Used to record its lifetime on
+  // destruction.
+  const base::TimeTicks construction_time_;
+
   // Specifies the device id of the output device to open or empty for the
   // default output device.
   const std::string output_device_id_;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 7fb72945..d0fb7d7b 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -514,9 +514,7 @@
     "AudioService": [
         {
             "platforms": [
-                "linux",
-                "mac",
-                "windows"
+                "linux"
             ],
             "experiments": [
                 {
@@ -534,6 +532,26 @@
         },
         {
             "platforms": [
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "AudioProcess_LaunchOnStartup_Sandboxed_v7",
+                    "params": {
+                        "teardown_timeout_s": "0"
+                    },
+                    "enable_features": [
+                        "AudioServiceAudioStreams",
+                        "AudioServiceLaunchOnStartup",
+                        "AudioServiceOutOfProcess",
+                        "AudioServiceSandbox"
+                    ]
+                }
+            ]
+        },
+        {
+            "platforms": [
                 "android",
                 "chromeos"
             ],
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index f02b50b3..961e624 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -53,7 +53,6 @@
 crbug.com/626703 external/wpt/css/css-writing-modes/sizing-orthog-vlr-in-htb-004.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/two-levels-of-orthogonal-flows-percentage.html [ Pass ]
 crbug.com/855279 fast/css/text-overflow-ellipsis-vertical-hittest.html [ Pass ]
-crbug.com/591099 fast/dom/inner-text-first-letter.html [ Pass ]
 crbug.com/591099 fast/dom/nodesFromRect/nodesFromRect-basic.html [ Failure ]
 
 # New failures are appended below by the script.
@@ -194,6 +193,8 @@
 crbug.com/591099 external/wpt/css/selectors/selector-placeholder-shown-type-change-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/selectors/selector-read-write-type-change-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/selectors/selector-required-type-change-002.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-paint-clip-002.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-paint-clip-006.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-horiz-002.xhtml [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html [ Pass ]
@@ -237,7 +238,7 @@
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ]
@@ -271,7 +272,7 @@
 crbug.com/591099 external/wpt/media-source/mediasource-config-change-mp4-v-bitrate.html [ Failure ]
 crbug.com/591099 external/wpt/offscreen-canvas/convert-to-blob/offscreencanvas.convert.to.blob.html [ Pass ]
 crbug.com/591099 external/wpt/performance-timeline/po-observe.html [ Timeout ]
-crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture-twice.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture-twice.html [ Pass ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/quirks/line-height-calculation.html [ Failure ]
 crbug.com/591099 external/wpt/requestidlecallback/callback-iframe.html [ Pass ]
@@ -330,7 +331,7 @@
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_outline_shorthand.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_white-space_normal_wrapped.html [ Failure ]
 crbug.com/591099 external/wpt/workers/Worker_ErrorEvent_error.htm [ Pass ]
-crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Timeout ]
+crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Crash Timeout ]
 crbug.com/591099 external/wpt/workers/baseurl/alpha/worker-in-worker.html [ Pass ]
 crbug.com/591099 external/wpt/workers/constructors/Worker/same-origin.html [ Timeout ]
 crbug.com/591099 external/wpt/workers/semantics/interface-objects/004.html [ Failure ]
@@ -338,7 +339,7 @@
 crbug.com/591099 external/wpt/xhr/send-content-type-string.htm [ Pass ]
 crbug.com/591099 external/wpt/xhr/send-entity-body-document.htm [ Pass ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
-crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Crash Failure ]
+crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Failure ]
 crbug.com/591099 fast/block/float/overlapping-floats-paint-hittest-order-1.html [ Failure ]
 crbug.com/591099 fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html [ Failure ]
 crbug.com/591099 fast/borders/bidi-002.html [ Failure ]
@@ -369,7 +370,7 @@
 crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
 crbug.com/591099 fast/overflow/recompute-overflow-of-layout-root-container.html [ Failure ]
 crbug.com/591099 fast/replaced/table-replaced-element.html [ Failure ]
-crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Pass ]
+crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Pass ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
 crbug.com/591099 fast/table/border-collapsing/004-vertical.html [ Failure ]
 crbug.com/591099 fast/table/border-collapsing/composited-cell-collapsed-border.html [ Failure ]
@@ -402,7 +403,7 @@
 crbug.com/591099 http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-datasaver-warning.js [ Failure ]
-crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
 crbug.com/591099 http/tests/intersection-observer/v2/cross-origin-effects.html [ Failure ]
 crbug.com/591099 http/tests/intersection-observer/v2/cross-origin-occlusion.html [ Failure ]
@@ -411,7 +412,7 @@
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-appcache.https.html [ Crash Failure ]
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.https.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash ]
-crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Pass ]
+crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Crash Pass Timeout ]
 crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Failure ]
@@ -487,10 +488,10 @@
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/feature-policy-vibrate/ [ Skip ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Failure ]
-crbug.com/591099 virtual/gpu/fast/canvas/canvas-arc-circumference.html [ Failure Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-arc-circumference.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-color-over-image.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-gradient-over-pattern.html [ Pass Timeout ]
-crbug.com/591099 virtual/gpu/fast/canvas/canvas-ellipse-circumference.html [ Failure Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-ellipse-circumference.html [ Failure ]
 crbug.com/591099 virtual/intersection-observer-v2/intersection-observer/v2/text-shadow.html [ Failure ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
@@ -526,5 +527,5 @@
 crbug.com/591099 virtual/threaded/ [ Skip ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/mouse-cursor.html [ Failure ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/591099 virtual/video-surface-layer/media/video-layer-crash.html [ Crash Failure ]
-crbug.com/591099 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/video-layer-crash.html [ Crash Failure Pass ]
+crbug.com/591099 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 07a21c3..5d32c9dd 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1922,3 +1922,14 @@
 crbug.com/846170 http/tests/lazyload/lazy.html [ WontFix ]
 crbug.com/846170 http/tests/lazyload/attribute.html [ WontFix ]
 crbug.com/846170 http/tests/lazyload/fixed-dimension.html [ WontFix ]
+
+# Tests that are not supported if outofblink-cors feature is enabled.
+# These functionarities should be verified on browser_tests for outofblink-cors.
+crbug.com/870172 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-all.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-all.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ WontFix ]
+crbug.com/870172 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 6ab23f222..08f5a46c 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1805,19 +1805,11 @@
 crbug.com/870173 virtual/outofblink-cors/http/tests/security/img-redirect-to-crossorigin-credentials.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors/http/tests/security/script-crossorigin-redirect-credentials.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors/http/tests/security/video-poster-cross-origin-crash2.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors-ns/http/tests/security/img-redirect-to-crossorigin-credentials.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors-ns/http/tests/security/isolatedWorld/cross-origin-xhr.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors-ns/http/tests/security/script-crossorigin-redirect-credentials.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors-ns/http/tests/security/video-poster-cross-origin-crash2.html [ Failure ]
 crbug.com/870173 virtual/outofblink-cors-ns/http/tests/navigation/form-targets-cross-site-frame-no-referrer.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
-crbug.com/870173 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
 
 # ====== Out of Blink CORS related tests END ======
 
@@ -2830,6 +2822,7 @@
 crbug.com/875249 external/wpt/infrastructure/testdriver/bless.html [ Timeout Pass ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/css-masking/mask-svg-content/mask-text-001.svg [ Failure ]
 crbug.com/626703 external/wpt/css/css-backgrounds/border-image-width-008.html [ Failure ]
 crbug.com/626703 external/wpt/content-security-policy/generic/only-valid-whitespaces-are-allowed.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/referrer-policy/css-integration/svg/internal-stylesheet.html [ Timeout ]
@@ -4734,6 +4727,17 @@
 crbug.com/840659 external/wpt/webrtc/protocol/video-codecs.https.html [ Pass Failure ]
 crbug.com/840659 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/protocol/video-codecs.https.html [ Pass Failure ]
 
+# WebRTC: In "Plan B", remote tracks are unmuted by default, so tests time out
+# waiting for "unmute".
+crbug.com/889487 external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html [ Timeout ]
+# WebRTC: In "Unified Plan", remote tracks are correctly muted by default, but
+# they unmute whether or not RTP packets arrive which is incorrect, this causes
+# a timeout in the "checkMute" test because the "unmute" listeners are hooked up
+# after we've already unmuted. The "checkMute" test likely contain bugs that
+# would cause a timeout anyway, but our implementation times out even before
+# that part due to incorrect behavior.
+crbug.com/889487 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpTransceiver.https.html [ Timeout ]
+
 # Sheriff 2018-04-11
 crbug.com/831796 fast/events/autoscroll-in-textfield.html [ Failure Pass ]
 crbug.com/831685 [ Linux ] external/wpt/2dcontext/compositing/2d.composite.canvas.lighter.html [ Pass Timeout ]
@@ -5122,9 +5126,6 @@
 # Test frequently times out on Mac CQ bots.
 crbug.com/874703 [ Mac ] http/tests/devtools/extensions/extensions-panel.js [ Timeout Pass ]
 
-# This won't pass until the bug fixed.
-crbug.com/875287 fast/frames/crash-frameset-CSS-content-property.html [ Crash ]
-
 # Wake Lock api test timeouts
 crbug.com/872530 external/wpt/wake-lock/wakelock-applicability-manual.https.html [ Pass Timeout ]
 crbug.com/872530 external/wpt/wake-lock/wakelock-document-hidden.https.html [ Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index b82cb863..a731f0e 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -50929,6 +50929,66 @@
      {}
     ]
    ],
+   "css/css-masking/mask-svg-content/mask-negative-scale.svg": [
+    [
+     "/css/css-masking/mask-svg-content/mask-negative-scale.svg",
+     [
+      [
+       "/css/css-masking/mask-svg-content/reference/mask-negative-scale-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-masking/mask-svg-content/mask-text-001.svg": [
+    [
+     "/css/css-masking/mask-svg-content/mask-text-001.svg",
+     [
+      [
+       "/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-masking/mask-svg-content/mask-type-001.svg": [
+    [
+     "/css/css-masking/mask-svg-content/mask-type-001.svg",
+     [
+      [
+       "/css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-masking/mask-svg-content/mask-type-002.svg": [
+    [
+     "/css/css-masking/mask-svg-content/mask-type-002.svg",
+     [
+      [
+       "/css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-masking/mask-svg-content/mask-type-003.svg": [
+    [
+     "/css/css-masking/mask-svg-content/mask-type-003.svg",
+     [
+      [
+       "/css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-masking/test-mask.html": [
     [
      "/css/css-masking/test-mask.html",
@@ -131484,6 +131544,21 @@
      {}
     ]
    ],
+   "css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "css/css-masking/mask-svg-content/reference/mask-negative-scale-001-ref.svg": [
+    [
+     {}
+    ]
+   ],
+   "css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg": [
+    [
+     {}
+    ]
+   ],
    "css/css-masking/parsing/clip-path-invalid-expected.txt": [
     [
      {}
@@ -171459,11 +171534,6 @@
      {}
     ]
    ],
-   "selection/idlharness.window-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "selection/interfaces-expected.txt": [
     [
      {}
@@ -172739,6 +172809,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/import-module-scripts.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/import-scripts-redirect.https-expected.txt": [
     [
      {}
@@ -260173,6 +260248,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/import-module-scripts.https.html": [
+    [
+     "/service-workers/service-worker/import-module-scripts.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/import-scripts-redirect.https.html": [
     [
      "/service-workers/service-worker/import-scripts-redirect.https.html",
@@ -267625,6 +267706,12 @@
      {}
     ]
    ],
+   "webrtc/RTCPeerConnection-remote-track-mute.https.html": [
+    [
+     "/webrtc/RTCPeerConnection-remote-track-mute.https.html",
+     {}
+    ]
+   ],
    "webrtc/RTCPeerConnection-removeTrack.https.html": [
     [
      "/webrtc/RTCPeerConnection-removeTrack.https.html",
@@ -331624,6 +331711,38 @@
    "cab55923d32ddb9525cb81a12d8035b1bf51bb4c",
    "support"
   ],
+  "css/css-masking/mask-svg-content/mask-negative-scale.svg": [
+   "36b7abb42eb157b9feff158c6dfb399249ee437c",
+   "reftest"
+  ],
+  "css/css-masking/mask-svg-content/mask-text-001.svg": [
+   "1dd5c546af3f90ad4ea97e9df7c8f19f70473f86",
+   "reftest"
+  ],
+  "css/css-masking/mask-svg-content/mask-type-001.svg": [
+   "9bcc40d55b1eba6d2811a3529f33a8f1a7ecdd03",
+   "reftest"
+  ],
+  "css/css-masking/mask-svg-content/mask-type-002.svg": [
+   "c298297329cf2d04bb53ae7cf8dbbb42551dfe4c",
+   "reftest"
+  ],
+  "css/css-masking/mask-svg-content/mask-type-003.svg": [
+   "891405dc46a5d200873d94608ea6de71e77adf38",
+   "reftest"
+  ],
+  "css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg": [
+   "c83ec87e7bd06b73983b6c80c9712b8b924e9375",
+   "support"
+  ],
+  "css/css-masking/mask-svg-content/reference/mask-negative-scale-001-ref.svg": [
+   "1ed0513327d4ac3735c81104834f68afe80e607d",
+   "support"
+  ],
+  "css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg": [
+   "48737c03d1e9d8be22b67c990be0d3ff9b420160",
+   "support"
+  ],
   "css/css-masking/parsing/clip-invalid.html": [
    "852612027840e24673432bcdcf6abaa33f422631",
    "testharness"
@@ -359993,7 +360112,7 @@
    "reftest"
   ],
   "css/motion/offset-path-serialization.html": [
-   "1c000919518e4052d1c9546580c9b9cca89883c7",
+   "7c835c7371f3d78a53c2bff3f6da626dba0bab87",
    "testharness"
   ],
   "css/motion/offset-path-string-001.html": [
@@ -417888,10 +418007,6 @@
    "ea119f2fc40c11884f7602a685c1094282884214",
    "testharness"
   ],
-  "selection/idlharness.window-expected.txt": [
-   "be537210e7b58298e3103f7bc79cbfef2fefceaa",
-   "support"
-  ],
   "selection/idlharness.window.js": [
    "b211797777ddbca73d26372a62c27813583a5734",
    "testharness"
@@ -419496,6 +419611,14 @@
    "e63f6b348a861345101670b9c3d87aaa4977b0c4",
    "testharness"
   ],
+  "service-workers/service-worker/import-module-scripts.https-expected.txt": [
+   "c45166005be52bde9ecde3129e595cac691744a8",
+   "support"
+  ],
+  "service-workers/service-worker/import-module-scripts.https.html": [
+   "e82911a1bd002d1039ba5a5ae31b51a3a90e1905",
+   "testharness"
+  ],
   "service-workers/service-worker/import-scripts-redirect.https-expected.txt": [
    "54836e4b4571ec6e7a194c1f4520abbebe9b98a3",
    "support"
@@ -428841,7 +428964,7 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-helper.js": [
-   "27ff1873790cfc4f71a07e1735ec4389ee330a18",
+   "b13e580998efce83c8bb158bce3d7747ec6f8bd9",
    "support"
   ],
   "webrtc/RTCPeerConnection-iceConnectionState-expected.txt": [
@@ -428892,6 +429015,10 @@
    "64ad212a5ba4e0c6bf5589f4cda3a4c7a508cdc2",
    "testharness"
   ],
+  "webrtc/RTCPeerConnection-remote-track-mute.https.html": [
+   "56fe761425096e963589309b828a8a7f7d36a9be",
+   "testharness"
+  ],
   "webrtc/RTCPeerConnection-removeTrack.https-expected.txt": [
    "d90c5ccdaada3111c5ff2e9f2e11c30d72e38c40",
    "support"
@@ -429001,11 +429128,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-transceivers.https-expected.txt": [
-   "2a12474313367427f7c8369ce10950934aff54af",
+   "f265ed4211de4d882635c208307edf0451b62843",
    "support"
   ],
   "webrtc/RTCPeerConnection-transceivers.https.html": [
-   "c89737c99fcebe76b1156499cb7269e7b0a67af1",
+   "1f980ea389a77551a33750d33349110e3b02b72a",
    "testharness"
   ],
   "webrtc/RTCPeerConnectionIceEvent-constructor-expected.txt": [
@@ -434605,7 +434732,7 @@
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-blob-url.any.js": [
-   "e3f61867c5b9e4ef23f19477d66222bb9ce7579e",
+   "f51a821d1813df81187e8c78d6251f9f29cf45eb",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-csp.html": [
@@ -434613,7 +434740,7 @@
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-data-url.any.js": [
-   "10bac0dfbf7567579f682908cbcde2ef45733447",
+   "0d8510da0c24ad378d1215157a70b4fd615a3d94",
    "testharness"
   ],
   "workers/modules/dedicated-worker-import-failure.html": [
@@ -434633,7 +434760,7 @@
    "testharness"
   ],
   "workers/modules/dedicated-worker-import.any.js": [
-   "805dbf3288c0644415203b3670b7827a9981a2b8",
+   "308c5e74c157da005257fd03fa9bc714c6d0eee7",
    "testharness"
   ],
   "workers/modules/dedicated-worker-options-credentials.html": [
@@ -434653,7 +434780,7 @@
    "support"
   ],
   "workers/modules/resources/dynamic-import-and-then-static-import-worker.js": [
-   "39ab5c237e2ab54423dd32945afa3ae902087763",
+   "9a386e63be51dcdae988de99bdd76709bf49d1b6",
    "support"
   ],
   "workers/modules/resources/dynamic-import-given-url-worker.js": [
@@ -434673,7 +434800,7 @@
    "support"
   ],
   "workers/modules/resources/dynamic-import-worker.js": [
-   "cd321fe24606bb55f3be570e31740b99d6fbff47",
+   "07f4df9db3ebd94dbc5ffd56fa7df36635a93857",
    "support"
   ],
   "workers/modules/resources/empty-worker.js": [
@@ -434681,11 +434808,11 @@
    "support"
   ],
   "workers/modules/resources/eval-dynamic-import-worker.js": [
-   "e92aff21a885536713141bd23a37733d5a66bfe2",
+   "af57b19f98ddcae391c4a55eb7ad1f51a4a0acf5",
    "support"
   ],
   "workers/modules/resources/export-on-dynamic-import-script.js": [
-   "8d172c324d306d8e0792e3637be3fdfcdc354927",
+   "bab7cb48d24931a82df5c1fd5b195f9eecbc9123",
    "support"
   ],
   "workers/modules/resources/export-on-dynamic-import-script.js.headers": [
@@ -434717,15 +434844,15 @@
    "support"
   ],
   "workers/modules/resources/import-test-cases.js": [
-   "919c20e0d4c78c8f90447c01252a34727df967bb",
+   "c5830e97eebc88b12a5ed1f600e810df443204f8",
    "support"
   ],
   "workers/modules/resources/nested-dynamic-import-worker.js": [
-   "5ae82f8aa054f8f3a61475994c4e658ba282c890",
+   "cb37f6e20f67c13f77582de19a1d4bd852537aa7",
    "support"
   ],
   "workers/modules/resources/nested-static-import-worker.js": [
-   "72ab31cb1c6ef1b77f4de3610cde2e58e094669d",
+   "7599faaa099f594a05d71f628d548f6732b2b193",
    "support"
   ],
   "workers/modules/resources/new-worker-window.html": [
@@ -434741,7 +434868,7 @@
    "support"
   ],
   "workers/modules/resources/static-import-and-then-dynamic-import-worker.js": [
-   "89125e0af7b0af62823628cb248a02c9b1d24343",
+   "cd98d8c17df652d367b0720492c432851f10f66a",
    "support"
   ],
   "workers/modules/resources/static-import-non-existent-script-worker.js": [
@@ -434761,7 +434888,7 @@
    "support"
   ],
   "workers/modules/resources/static-import-worker.js": [
-   "f0639153a94feaef8efa30feabf26752ba058853",
+   "48751dbe03bb0f7de23e26911ac7af5733c7d5f1",
    "support"
   ],
   "workers/name-property-expected.txt": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-negative-scale.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-negative-scale.svg
new file mode 100644
index 0000000..36b7abb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-negative-scale.svg
@@ -0,0 +1,40 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"
+	 xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="testmeta">
+	<title>CSS Masking: mask with negative scale target</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/>
+	<html:link rel="match" href="reference/mask-negative-scale-001-ref.svg"/>
+	<metadata class="flags">svg</metadata>
+	<desc class="assert">The masked target elements get scaled with negative
+	factors. Check if that influences masking. You should see 4 green
+	rectangles with smaller blue rectangles in it in various rotations.</desc>
+</g>
+<defs>
+<g id="img" transform="translate(10,10)">
+	<rect width="200" height="200" fill="red"/>
+	<rect width="100" height="100" fill="green"/>
+	<rect width="50" height="50" fill="blue"/>
+</g>
+</defs>
+
+<mask id="mask">
+	<rect x="10" y="10" width="90" height="90" fill="white"/>
+</mask>
+
+<g transform="translate(200, 200)">
+<g transform="matrix(1 0 0 1 -100 -100)" mask="url(#mask)">
+	<use xlink:href="#img"/>
+</g>
+<g transform="matrix(-1 0 0 -1 -100 -100)" mask="url(#mask)">
+	<use xlink:href="#img"/>
+</g>
+<g transform="matrix(-1 0 0 1 -100 -100)" mask="url(#mask)">
+	<use xlink:href="#img"/>
+</g>
+<g transform="matrix(1 0 0 -1 -100 -100)" mask="url(#mask)">
+	<use xlink:href="#img"/>
+</g>
+</g>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-text-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-text-001.svg
new file mode 100644
index 0000000..1dd5c54
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-text-001.svg
@@ -0,0 +1,18 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"
+	 xmlns:xlink="http://www.w3.org/1999/xlink" width="100px" height="100px">
+<g id="testmeta">
+	<title>CSS Masking: mask with transformed text content</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/>
+	<html:link rel="match" href="reference/mask-text-001-ref.svg"/>
+	<metadata class="flags">svg</metadata>
+	<desc class="assert">The masked target elements get scaled with negative
+	factors. Check if that influences masking. You should see 4 green
+	rectangles with smaller blue rectangles in it in various rotations.</desc>
+</g>
+<mask id="mask">
+	<text fill="#fff" font-family="Ahem" font-size="12px" transform="rotate(90 50 50)" x="50%" y="50%">foobar</text>
+</mask>
+<rect width="100%" height="100%" x="0" y="0" mask="url(#mask)"/>
+</svg>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-001.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-001.svg
new file mode 100644
index 0000000..9bcc40d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-001.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<g id="testmeta">
+	<title>CSS Masking: mask without mask-type alpha</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-mask-type"/>
+	<html:link rel="match" href="reference/mask-green-square-001-ref.svg"/>
+	<metadata class="flags">svg</metadata>
+	<desc class="assert">The mask type "alpha" is applied to the mask element.
+	The mask should take the alpha channel of the content to mask. You should
+	see a green square.</desc>
+</g>
+<mask id="mask" mask-type="alpha">
+	<rect width="200" height="200" fill="black" opacity="0"/>
+	<rect x="50" y="50" width="100" height="100" fill="black"/>
+</mask>
+<rect width="200" height="200" fill="green" mask="url(#mask)"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-002.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-002.svg
new file mode 100644
index 0000000..c298297
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-002.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<g id="testmeta">
+	<title>CSS Masking: mask without mask-type luminance</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-mask-type"/>
+	<html:link rel="match" href="reference/mask-green-square-001-ref.svg"/>
+	<metadata class="flags">svg</metadata>
+	<desc class="assert">The mask type "alpha" is applied to the mask element.
+	The mask should take the luminocity of the content to mask. You should
+	see a green square.</desc>
+</g>
+<mask id="mask" mask-type="luminance">
+	<rect width="200" height="200" fill="black"/>
+	<rect x="50" y="50" width="100" height="100" fill="white"/>
+</mask>
+<rect width="200" height="200" fill="green" mask="url(#mask)"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-003.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-003.svg
new file mode 100644
index 0000000..891405d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/mask-type-003.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<g id="testmeta">
+	<title>CSS Masking: mask without specified mask-type</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#svg-masks"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#MaskElement"/>
+	<html:link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-mask-type"/>
+	<html:link rel="match" href="reference/mask-green-square-001-ref.svg"/>
+	<metadata class="flags">svg</metadata>
+	<desc class="assert">No mask type was specified the mask element should
+	take the luminocity of the content to mask. You should see a green square.
+	</desc>
+</g>
+<mask id="mask">
+	<rect width="200" height="200" fill="black"/>
+	<rect x="50" y="50" width="100" height="100" fill="white"/>
+</mask>
+<rect width="200" height="200" fill="green" mask="url(#mask)"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg
new file mode 100644
index 0000000..c83ec87e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-green-square-001-ref.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<g id="testmeta">
+	<title>CSS Masking: Reftest reference</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<metadata class="flags">svg</metadata>
+</g>
+<rect x="50" y="50" width="100" height="100" fill="green"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-negative-scale-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-negative-scale-001-ref.svg
new file mode 100644
index 0000000..1ed0513
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-negative-scale-001-ref.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<g id="testmeta">
+	<title>CSS Masking: Reftest reference</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<metadata class="flags">svg</metadata>
+</g>
+<rect width="90" height="90" fill="green"/>
+<rect x="40" y="40" width="50" height="50" fill="blue"/>
+<rect x="110" width="90" height="90" fill="green"/>
+<rect x="110" y="40" width="50" height="50" fill="blue"/>
+<rect y="110" width="90" height="90" fill="green"/>
+<rect x="40" y="110" width="50" height="50" fill="blue"/>
+<rect x="110" y="110" width="90" height="90" fill="green"/>
+<rect x="110" y="110" width="50" height="50" fill="blue"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg
new file mode 100644
index 0000000..48737c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<g id="testmeta">
+	<title>CSS Masking: Reftest reference</title>
+	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
+	<metadata class="flags">svg</metadata>
+</g>
+<text fill="#000" font-family="Ahem" font-size="12px" transform="rotate(90 50 50)" x="50" y="50">foobar</text>
+</svg>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-path-serialization.html b/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-path-serialization.html
index 1c00091..7c835c7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-path-serialization.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/motion/offset-path-serialization.html
@@ -36,6 +36,10 @@
   target.style.offsetPath = '  path(  "m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50"  )  ';
   assert_equals(target.style.offsetPath, 'path("m 10 20 a 10 20 30 1 0 40 50 a 110 120 30 1 1 140 50")');
   assert_equals(getComputedStyle(target).offsetPath, 'path("M 10 20 A 10 20 30 1 0 50 70 A 110 120 30 1 1 190 120")');
+
+  target.style.offsetPath = 'path("M 1 2 H 3 v 4 h 5 V 6 h 7 v 8")';
+  assert_equals(target.style.offsetPath, 'path("M 1 2 H 3 v 4 h 5 V 6 h 7 v 8")');
+  assert_equals(getComputedStyle(target).offsetPath, 'path("M 1 2 H 3 V 6 H 8 V 6 H 15 V 14")');
 });
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html
new file mode 100644
index 0000000..0fc49e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-img-element/decode/image-decode-with-quick-attach-svg.tentative.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>SVGImageElement.prototype.decode(), attach to DOM before promise resolves.</title>
+<link rel=help href="https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<svg></svg>
+<script>
+"use strict";
+
+promise_test(function() {
+  var img = document.createElementNS('http://www.w3.org/2000/svg', 'image');
+  img.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', "/images/green.png");
+  const promise = img.decode().then(function(arg) {
+    assert_equals(arg, undefined);
+  });
+  // Don't wait for the promise to resolve before attaching the image.
+  // The promise should still resolve successfully.
+  document.querySelector('svg').appendChild(img);
+  return promise;
+}, document.title);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/idlharness.window-expected.txt
deleted file mode 100644
index be537210..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/idlharness.window-expected.txt
+++ /dev/null
@@ -1,83 +0,0 @@
-This is a testharness.js-based test.
-Found 79 tests; 73 PASS, 6 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS idl_test setup
-PASS Partial interface Document: original interface defined
-PASS Partial interface Window: original interface defined
-PASS Partial interface GlobalEventHandlers: original interface defined
-PASS Selection interface: existence and properties of interface object
-PASS Selection interface object length
-PASS Selection interface object name
-PASS Selection interface: existence and properties of interface prototype object
-PASS Selection interface: existence and properties of interface prototype object's "constructor" property
-PASS Selection interface: existence and properties of interface prototype object's @@unscopables property
-PASS Selection interface: attribute anchorNode
-PASS Selection interface: attribute anchorOffset
-PASS Selection interface: attribute focusNode
-PASS Selection interface: attribute focusOffset
-PASS Selection interface: attribute isCollapsed
-PASS Selection interface: attribute rangeCount
-PASS Selection interface: attribute type
-PASS Selection interface: operation getRangeAt(unsigned long)
-PASS Selection interface: operation addRange(Range)
-PASS Selection interface: operation removeRange(Range)
-PASS Selection interface: operation removeAllRanges()
-PASS Selection interface: operation empty()
-PASS Selection interface: operation collapse(Node, unsigned long)
-PASS Selection interface: operation setPosition(Node, unsigned long)
-PASS Selection interface: operation collapseToStart()
-PASS Selection interface: operation collapseToEnd()
-PASS Selection interface: operation extend(Node, unsigned long)
-PASS Selection interface: operation setBaseAndExtent(Node, unsigned long, Node, unsigned long)
-PASS Selection interface: operation selectAllChildren(Node)
-PASS Selection interface: operation deleteFromDocument()
-PASS Selection interface: operation containsNode(Node, boolean)
-PASS Selection interface: stringifier
-PASS Selection must be primary interface of getSelection()
-PASS Stringification of getSelection()
-PASS Selection interface: getSelection() must inherit property "anchorNode" with the proper type
-PASS Selection interface: getSelection() must inherit property "anchorOffset" with the proper type
-PASS Selection interface: getSelection() must inherit property "focusNode" with the proper type
-PASS Selection interface: getSelection() must inherit property "focusOffset" with the proper type
-PASS Selection interface: getSelection() must inherit property "isCollapsed" with the proper type
-PASS Selection interface: getSelection() must inherit property "rangeCount" with the proper type
-PASS Selection interface: getSelection() must inherit property "type" with the proper type
-PASS Selection interface: getSelection() must inherit property "getRangeAt(unsigned long)" with the proper type
-PASS Selection interface: calling getRangeAt(unsigned long) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "addRange(Range)" with the proper type
-PASS Selection interface: calling addRange(Range) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "removeRange(Range)" with the proper type
-PASS Selection interface: calling removeRange(Range) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "removeAllRanges()" with the proper type
-PASS Selection interface: getSelection() must inherit property "empty()" with the proper type
-PASS Selection interface: getSelection() must inherit property "collapse(Node, unsigned long)" with the proper type
-PASS Selection interface: calling collapse(Node, unsigned long) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "setPosition(Node, unsigned long)" with the proper type
-PASS Selection interface: calling setPosition(Node, unsigned long) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "collapseToStart()" with the proper type
-PASS Selection interface: getSelection() must inherit property "collapseToEnd()" with the proper type
-PASS Selection interface: getSelection() must inherit property "extend(Node, unsigned long)" with the proper type
-PASS Selection interface: calling extend(Node, unsigned long) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "setBaseAndExtent(Node, unsigned long, Node, unsigned long)" with the proper type
-PASS Selection interface: calling setBaseAndExtent(Node, unsigned long, Node, unsigned long) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "selectAllChildren(Node)" with the proper type
-PASS Selection interface: calling selectAllChildren(Node) on getSelection() with too few arguments must throw TypeError
-PASS Selection interface: getSelection() must inherit property "deleteFromDocument()" with the proper type
-PASS Selection interface: getSelection() must inherit property "containsNode(Node, boolean)" with the proper type
-PASS Selection interface: calling containsNode(Node, boolean) on getSelection() with too few arguments must throw TypeError
-PASS Document interface: operation getSelection()
-PASS Document interface: attribute onselectstart
-PASS Document interface: attribute onselectionchange
-PASS Document interface: document must inherit property "getSelection()" with the proper type
-PASS Document interface: document must inherit property "onselectstart" with the proper type
-PASS Document interface: document must inherit property "onselectionchange" with the proper type
-FAIL HTMLElement interface: attribute onselectstart assert_own_property: expected property "onselectstart" missing
-FAIL HTMLElement interface: attribute onselectionchange assert_true: The prototype object must have a property "onselectionchange" expected true got false
-PASS Window interface: operation getSelection()
-FAIL Window interface: attribute onselectstart assert_own_property: The global object must have a property "onselectstart" expected property "onselectstart" missing
-FAIL Window interface: attribute onselectionchange assert_own_property: The global object must have a property "onselectionchange" expected property "onselectionchange" missing
-PASS Window interface: window must inherit property "getSelection()" with the proper type
-FAIL Window interface: window must inherit property "onselectstart" with the proper type assert_own_property: expected property "onselectstart" missing
-FAIL Window interface: window must inherit property "onselectionchange" with the proper type assert_own_property: expected property "onselectionchange" missing
-PASS WorkerGlobalScope interface: existence and properties of interface object
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
index 52e3170..3553f2b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
@@ -73,4 +73,14 @@
   test(t => {
     assert_element_accepts_non_trusted_type_explicit_set('a', 'rel', null, 'null');
   }, "a.rel accepts null");
+
+  test(t => {
+    let el = document.createElement('iframe');
+
+    assert_throws(new TypeError(), _ => {
+      el.setAttribute('SrC', INPUTS.URL);
+    });
+
+    assert_equals(el.src, '');
+  }, "`Element.prototype.setAttribute.SrC = string` throws.");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js
index 27ff187..b13e580 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-helper.js
@@ -463,11 +463,13 @@
   });
 }
 
+// Performs an offer exchange caller -> callee.
 async function exchangeOffer(caller, callee) {
   const offer = await caller.createOffer();
   await caller.setLocalDescription(offer);
   return callee.setRemoteDescription(offer);
 }
+// Performs an answer exchange caller -> callee.
 async function exchangeAnswer(caller, callee) {
   const answer = await callee.createAnswer();
   await callee.setLocalDescription(answer);
@@ -477,7 +479,18 @@
   await exchangeOffer(caller, callee);
   return exchangeAnswer(caller, callee);
 }
-
+// The returned promise is resolved with caller's ontrack event.
+async function exchangeAnswerAndListenToOntrack(t, caller, callee) {
+  const ontrackPromise = addEventListenerPromise(t, caller, 'track');
+  await exchangeAnswer(caller, callee);
+  return ontrackPromise;
+}
+// The returned promise is resolved with callee's ontrack event.
+async function exchangeOfferAndListenToOntrack(t, caller, callee) {
+  const ontrackPromise = addEventListenerPromise(t, callee, 'track');
+  await exchangeOffer(caller, callee);
+  return ontrackPromise;
+}
 
 // The resolver has a |promise| that can be resolved or rejected using |resolve|
 // or |reject|.
@@ -503,3 +516,27 @@
     }));
   });
 }
+
+function createPeerConnectionWithCleanup(t) {
+  const pc = new RTCPeerConnection();
+  t.add_cleanup(() => pc.close());
+  return pc;
+}
+
+async function createTrackAndStreamWithCleanup(t, kind = 'audio') {
+  let constraints = {};
+  constraints[kind] = true;
+  const stream = await navigator.mediaDevices.getUserMedia(constraints);
+  const [track] = stream.getTracks();
+  t.add_cleanup(() => track.stop());
+  return [track, stream];
+}
+
+function findTransceiverForSender(pc, sender) {
+  const transceivers = pc.getTransceivers();
+  for (let i = 0; i < transceivers.length; ++i) {
+    if (transceivers[i].sender == sender)
+      return transceivers[i];
+  }
+  return null;
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html
new file mode 100644
index 0000000..56fe7614
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-remote-track-mute.https.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection-transceivers.https.html</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+//   exchangeOffer
+//   exchangeOfferAndListenToOntrack
+//   exchangeAnswer
+//   exchangeAnswerAndListenToOntrack
+//   addEventListenerPromise
+//   createPeerConnectionWithCleanup
+//   createTrackAndStreamWithCleanup
+//   findTransceiverForSender
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+  const pc2 = createPeerConnectionWithCleanup(t);
+  exchangeIceCandidates(pc1, pc2);
+
+  const unmuteResolver = new Resolver();
+  let remoteTrack = null;
+  // The unmuting it timing sensitive so we hook up to the event directly
+  // instead of wrapping it in an EventWatcher which uses promises.
+  pc2.ontrack = t.step_func(e => {
+    remoteTrack = e.track;
+    assert_true(remoteTrack.muted, 'track is muted in ontrack');
+    remoteTrack.onunmute = t.step_func(e => {
+      assert_false(remoteTrack.muted, 'track is unmuted in onunmute');
+      unmuteResolver.resolve();
+    });
+    pc2.ontrack = t.step_func(e => {
+      assert_unreached('ontrack fired unexpectedly');
+    });
+  });
+  await exchangeOfferAnswer(pc1, pc2);
+  await unmuteResolver.promise;
+}, 'ontrack: track goes from muted to unmuted');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+  const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  exchangeIceCandidates(pc1, pc2);
+
+  const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  await exchangeAnswer(pc1, pc2);
+
+  const muteWatcher = new EventWatcher(t, e.track, ['mute']);
+  const mutePromise = muteWatcher.wait_for('mute');
+  localTransceiver.direction = 'inactive';
+  await exchangeOfferAnswer(pc1, pc2);
+
+  await mutePromise;
+}, 'Changing transceiver direction to \'inactive\' mutes the remote track');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+  const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  exchangeIceCandidates(pc1, pc2);
+
+  const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  await exchangeAnswer(pc1, pc2);
+  localTransceiver.direction = 'inactive';
+  await exchangeOfferAnswer(pc1, pc2);
+
+  const unmuteWatcher = new EventWatcher(t, e.track, ['unmute']);
+  const unmutePromise = unmuteWatcher.wait_for('unmute');
+  localTransceiver.direction = 'sendrecv';
+  await exchangeOfferAnswer(pc1, pc2);
+
+  await unmutePromise;
+}, 'Changing transceiver direction to \'sendrecv\' unmutes the remote track');
+
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+  const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  exchangeIceCandidates(pc1, pc2);
+
+  const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  await exchangeAnswer(pc1, pc2);
+  const muteWatcher = new EventWatcher(t, e.track, ['mute']);
+  const mutePromise = muteWatcher.wait_for('mute');
+  pc2.close();
+  await mutePromise;
+}, 'pc.close() mutes remote tracks');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
index 2a12474..f265ed42 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
@@ -40,5 +40,6 @@
 FAIL addTransceiver does not reuse reusable transceivers promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 FAIL Can setup two-way call using a single transceiver promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'direction' of null"
 FAIL Closing the PC stops the transceivers promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Changing transceiver direction to 'sendrecv' makes ontrack fire promise_test: Unhandled rejection with value: object "TypeError: Cannot set property 'direction' of null"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
index c89737c9..1f980ea 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCPeerConnection-transceivers.https.html
@@ -8,59 +8,14 @@
 'use strict';
 
 // The following helper functions are called from RTCPeerConnection-helper.js:
+//   exchangeOffer
+//   exchangeOfferAndListenToOntrack
+//   exchangeAnswer
+//   exchangeAnswerAndListenToOntrack
 //   addEventListenerPromise
-
-function createPeerConnectionWithCleanup(t) {
-  const pc = new RTCPeerConnection();
-  t.add_cleanup(() => pc.close());
-  return pc;
-}
-
-async function createTrackAndStreamWithCleanup(t, kind = 'audio') {
-  let constraints = {};
-  constraints[kind] = true;
-  const stream = await navigator.mediaDevices.getUserMedia(constraints);
-  const [track] = stream.getTracks();
-  t.add_cleanup(() => track.stop());
-  return [track, stream];
-}
-
-function findTransceiverForSender(pc, sender) {
-  const transceivers = pc.getTransceivers();
-  for (let i = 0; i < transceivers.length; ++i) {
-    if (transceivers[i].sender == sender)
-      return transceivers[i];
-  }
-  return null;
-}
-
-// Performs an offer exchange pc1 -> pc2.
-async function exchangeOffer(pc1, pc2) {
-  const offer = await pc1.createOffer();
-  await pc1.setLocalDescription(offer);
-  await pc2.setRemoteDescription(offer);
-}
-
-// The returned promise is resolved with pc2's ontrack event.
-async function exchangeOfferAndListenToOntrack(t, pc1, pc2) {
-  const ontrackPromise = addEventListenerPromise(t, pc2, 'track');
-  await exchangeOffer(pc1, pc2);
-  return ontrackPromise;
-}
-
-// Performs an answer exchange pc2 -> pc1.
-async function exchangeAnswer(pc1, pc2) {
-  const answer = await pc2.createAnswer();
-  await pc2.setLocalDescription(answer);
-  await pc1.setRemoteDescription(answer);
-}
-
-// The returned promise is resolved with pc1's ontrack event.
-async function exchangeAnswerAndListenToOntrack(t, pc1, pc2) {
-  const ontrackPromise = addEventListenerPromise(t, pc1, 'track');
-  await exchangeAnswer(pc1, pc2);
-  return ontrackPromise;
-}
+//   createPeerConnectionWithCleanup
+//   createTrackAndStreamWithCleanup
+//   findTransceiverForSender
 
 promise_test(async t => {
   const pc = createPeerConnectionWithCleanup(t);
@@ -493,4 +448,20 @@
   assert_true(transceiver.stopped);
 }, 'Closing the PC stops the transceivers');
 
+promise_test(async t => {
+  const pc1 = createPeerConnectionWithCleanup(t);
+  const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+  const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
+  const pc2 = createPeerConnectionWithCleanup(t);
+  exchangeIceCandidates(pc1, pc2);
+
+  const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+  await exchangeAnswer(pc1, pc2);
+  localTransceiver.direction = 'inactive';
+  await exchangeOfferAnswer(pc1, pc2);
+
+  localTransceiver.direction = 'sendrecv';
+  await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+}, 'Changing transceiver direction to \'sendrecv\' makes ontrack fire');
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/scrolltimeline-currenttime.html b/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/scrolltimeline-currenttime.html
index fff1559..4887f31 100644
--- a/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/scrolltimeline-currenttime.html
+++ b/third_party/WebKit/LayoutTests/fast/animation/scroll-animations/scrolltimeline-currenttime.html
@@ -1,39 +1,75 @@
 <!DOCTYPE html>
-<style>
-.scroller {
-  height: 100px;
-  width: 100px;
-  overflow: scroll;
-}
 
-.content {
-  height: 500px;
-  width: 500px;
-}
-</style>
-
+<script src='resources/scroll-timeline-util.js'></script>
 <script src='../../../resources/testharness.js'></script>
 <script src='../../../resources/testharnessreport.js'></script>
 
-<div id='scroller1' class='scroller'>
-  <div class='content'></div>
-</div>
+<body></body>
+
 <script>
+// Builds a generic structure that looks like:
+//
+// <div class="scroller">  // 100x100 viewport
+//   <div class="contents"></div>  // 500x500
+// </div>
+//
+// The |scrollerOverrides| and |contentOverrides| parameters are maps which
+// are applied to the scroller and contents style after basic setup.
+//
+// Returns the outer 'scroller' element.
+function setupScrollTimelineTest(
+    scrollerOverrides = new Map(), contentOverrides = new Map()) {
+  let scroller = document.createElement('div');
+  scroller.style.width = '100px';
+  scroller.style.height = '100px';
+  scroller.style.overflow = 'scroll';
+  for (const [key, value] of scrollerOverrides) {
+    scroller.style[key] = value;
+  }
+
+  let contents = document.createElement('div');
+  contents.style.width = '500px';
+  contents.style.height = '500px';
+  for (const [key, value] of contentOverrides) {
+    contents.style[key] = value;
+  }
+
+  scroller.appendChild(contents);
+  document.body.appendChild(scroller);
+  return scroller;
+}
+
+// Helper method to calculate the current time, implementing only step 5 of
+// https://wicg.github.io/scroll-animations/#current-time-algorithm
+function calculateCurrentTime(
+    currentScrollOffset, startScrollOffset, endScrollOffset,
+    effectiveTimeRange) {
+  return ((currentScrollOffset - startScrollOffset) /
+          (endScrollOffset - startScrollOffset)) *
+      effectiveTimeRange;
+}
+
 test(function() {
-  const scroller = document.querySelector('#scroller1');
+  const scroller = setupScrollTimelineTest();
   // For simplicity, we set the timeRange such that currentTime maps directly to
   // the value scrolled. We have a square scroller/contents, so can just compute
   // one edge and use it for all the timelines;
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const blockScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'block' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'block'});
   const inlineScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline' });
-  const horizontalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'horizontal' });
-  const verticalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'vertical' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline'});
+  const horizontalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal'
+  });
+  const verticalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'vertical'
+  });
 
   // Unscrolled, all timelines should read a currentTime of 0.
   assert_equals(blockScrollTimeline.currentTime, 0);
@@ -52,13 +88,7 @@
   assert_equals(horizontalScrollTimeline.currentTime, 75);
   assert_equals(verticalScrollTimeline.currentTime, 50);
 }, 'currentTime calculates the correct time based on scrolled amount');
-</script>
 
-
-<div id='scroller2' class='scroller'>
-  <div class='content' style='height: 1000px; width: 1000px;'></div>
-</div>
-<script>
 test(function() {
   // It is unfortunately difficult to calculate what scroll offset results in an
   // exact currentTime. Scrolling is calculated in integers which allows for the
@@ -67,10 +97,10 @@
   //
   // Instead we make the scroller content big enough that a 1-pixel rounding
   // difference results in a negligible difference in the output value.
-
-  const scroller = document.querySelector('#scroller2');
+  const contentOverrides = new Map([['width', '1000px'], ['height', '1000px']]);
+  const scroller = setupScrollTimelineTest(new Map(), contentOverrides);
   const scrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: 100, orientation: 'block' });
+      {scrollSource: scroller, timeRange: 100, orientation: 'block'});
 
   // Mapping timeRange to 100 gives a form of 'percentage scrolled', so
   // calculate where the 50% scroll mark would be.
@@ -79,14 +109,10 @@
 
   assert_approx_equals(scrollTimeline.currentTime, 50, 0.5);
 }, 'currentTime adjusts correctly for the timeRange');
-</script>
 
-<div id='scroller3' class='scroller' style='direction: rtl;'>
-  <div class='content'></div>
-</div>
-<script>
 test(function() {
-  const scroller = document.querySelector('#scroller3');
+  const scrollerOverrides = new Map([['direction', 'rtl']]);
+  const scroller = setupScrollTimelineTest(scrollerOverrides);
 
   // For simplicity, we set the timeRange such that currentTime maps directly to
   // the value scrolled. We have a square scroller/contents, so can just compute
@@ -94,13 +120,19 @@
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const blockScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'block' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'block'});
   const inlineScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline' });
-  const horizontalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'horizontal' });
-  const verticalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'vertical' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline'});
+  const horizontalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal'
+  });
+  const verticalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'vertical'
+  });
 
   // Unscrolled, all timelines should read a current time of 0 even though the
   // X-axis will have started at the right hand side for rtl.
@@ -119,14 +151,10 @@
   assert_equals(horizontalScrollTimeline.currentTime, scrollerSize - 75);
   assert_equals(verticalScrollTimeline.currentTime, 50);
 }, 'currentTime handles direction: rtl correctly');
-</script>
 
-<div id='scroller4' class='scroller' style='writing-mode: vertical-rl;'>
-  <div class='content'></div>
-</div>
-<script>
 test(function() {
-  const scroller = document.querySelector('#scroller4');
+  const scrollerOverrides = new Map([['writing-mode', 'vertical-rl']]);
+  const scroller = setupScrollTimelineTest(scrollerOverrides);
 
   // For simplicity, we set the timeRange such that currentTime maps directly to
   // the value scrolled. We have a square scroller/contents, so can just compute
@@ -134,13 +162,19 @@
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const blockScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'block' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'block'});
   const inlineScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline' });
-  const horizontalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'horizontal' });
-  const verticalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'vertical' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline'});
+  const horizontalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal'
+  });
+  const verticalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'vertical'
+  });
 
   // Unscrolled, all timelines should read a current time of 0 even though the
   // X-axis will have started at the right hand side for vertical-rl.
@@ -150,8 +184,9 @@
   assert_equals(verticalScrollTimeline.currentTime, 0);
 
   // For vertical-rl, the X-axis starts on the right-hand-side and is the block
-  // axis. The Y-axis is normal but is the inline axis. For the horizontal/vertical
-  // cases, horizontal starts on the right-hand-side and vertical is normal.
+  // axis. The Y-axis is normal but is the inline axis. For the
+  // horizontal/vertical cases, horizontal starts on the right-hand-side and
+  // vertical is normal.
   scroller.scrollTop = 50;
   scroller.scrollLeft = 75;
 
@@ -160,14 +195,10 @@
   assert_equals(horizontalScrollTimeline.currentTime, scrollerSize - 75);
   assert_equals(verticalScrollTimeline.currentTime, 50);
 }, 'currentTime handles writing-mode: vertical-rl correctly');
-</script>
 
-<div id='scroller5' class='scroller' style='writing-mode: vertical-lr;'>
-  <div class='content'></div>
-</div>
-<script>
 test(function() {
-  const scroller = document.querySelector('#scroller5');
+  const scrollerOverrides = new Map([['writing-mode', 'vertical-lr']]);
+  const scroller = setupScrollTimelineTest(scrollerOverrides);
 
   // For simplicity, we set the timeRange such that currentTime maps directly to
   // the value scrolled. We have a square scroller/contents, so can just compute
@@ -175,13 +206,19 @@
   const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
 
   const blockScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'block' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'block'});
   const inlineScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline' });
-  const horizontalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'horizontal' });
-  const verticalScrollTimeline = new ScrollTimeline(
-      { scrollSource: scroller, timeRange: scrollerSize, orientation: 'vertical' });
+      {scrollSource: scroller, timeRange: scrollerSize, orientation: 'inline'});
+  const horizontalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal'
+  });
+  const verticalScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'vertical'
+  });
 
   // Unscrolled, all timelines should read a current time of 0.
   assert_equals(blockScrollTimeline.currentTime, 0);
@@ -190,8 +227,8 @@
   assert_equals(verticalScrollTimeline.currentTime, 0);
 
   // For vertical-lr, both axes start at their 'normal' positions but the X-axis
-  // is the block direction and the Y-axis is the inline direction. This does not
-  // affect horizontal/vertical.
+  // is the block direction and the Y-axis is the inline direction. This does
+  // not affect horizontal/vertical.
   scroller.scrollTop = 50;
   scroller.scrollLeft = 75;
 
@@ -200,4 +237,380 @@
   assert_equals(horizontalScrollTimeline.currentTime, 75);
   assert_equals(verticalScrollTimeline.currentTime, 50);
 }, 'currentTime handles writing-mode: vertical-lr correctly');
+
+test(function() {
+  const scroller = setupScrollTimelineTest();
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const lengthScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    startScrollOffset: '20px'
+  });
+  const percentageScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    startScrollOffset: '20%'
+  });
+  const calcScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    startScrollOffset: 'calc(20% - 5px)'
+  });
+
+  // Unscrolled, all timelines should read a current time of unresolved, since
+  // the current offset (0) will be less than the startScrollOffset.
+  assert_equals(lengthScrollTimeline.currentTime, NaN);
+  assert_equals(percentageScrollTimeline.currentTime, NaN);
+  assert_equals(calcScrollTimeline.currentTime, NaN);
+
+  // Check the length-based ScrollTimeline.
+  scroller.scrollTop = 19;
+  assert_equals(lengthScrollTimeline.currentTime, NaN);
+  scroller.scrollTop = 20;
+  assert_equals(lengthScrollTimeline.currentTime, 0);
+  scroller.scrollTop = 50;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(50, 20, scrollerSize, scrollerSize));
+  scroller.scrollTop = 200;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(200, 20, scrollerSize, scrollerSize));
+
+  // Check the percentage-based ScrollTimeline.
+  scroller.scrollTop = 0.19 * scrollerSize;
+  assert_equals(percentageScrollTimeline.currentTime, NaN);
+  scroller.scrollTop = 0.20 * scrollerSize;
+  assert_equals(percentageScrollTimeline.currentTime, 0);
+  scroller.scrollTop = 0.50 * scrollerSize;
+  assert_equals(
+      percentageScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0.2 * scrollerSize, scrollerSize, scrollerSize));
+
+  // Check the calc-based ScrollTimeline.
+  scroller.scrollTop = 0.2 * scrollerSize - 10;
+  assert_equals(calcScrollTimeline.currentTime, NaN);
+  scroller.scrollTop = 0.2 * scrollerSize - 5;
+  assert_equals(calcScrollTimeline.currentTime, 0);
+  scroller.scrollTop = 0.2 * scrollerSize;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0.2 * scrollerSize - 5, scrollerSize,
+          scrollerSize));
+  scroller.scrollTop = 0.5 * scrollerSize;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0.2 * scrollerSize - 5, scrollerSize,
+          scrollerSize));
+}, 'currentTime handles startScrollOffset correctly');
+
+test(function() {
+  const scrollerOverrides = new Map([['direction', 'rtl']]);
+  const scroller = setupScrollTimelineTest(scrollerOverrides);
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const lengthScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal',
+    startScrollOffset: '20px'
+  });
+  const percentageScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal',
+    startScrollOffset: '20%'
+  });
+  const calcScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal',
+    startScrollOffset: 'calc(20% - 5px)'
+  });
+
+  // Unscrolled, all timelines should read a current time of unresolved, since
+  // the current offset (0) will be less than the startScrollOffset.
+  assert_equals(lengthScrollTimeline.currentTime, NaN);
+  assert_equals(percentageScrollTimeline.currentTime, NaN);
+  assert_equals(calcScrollTimeline.currentTime, NaN);
+
+  // With direction rtl offsets are inverted, such that scrollLeft ==
+  // scrollerSize is the 'zero' point for currentTime. However the
+  // startScrollOffset is an absolute distance along the offset, so doesn't
+  // need adjusting.
+
+  // Check the length-based ScrollTimeline.
+  scroller.scrollLeft = scrollerSize;
+  assert_equals(lengthScrollTimeline.currentTime, NaN);
+  scroller.scrollLeft = scrollerSize - 20;
+  assert_equals(lengthScrollTimeline.currentTime, 0);
+  scroller.scrollLeft = scrollerSize - 50;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(50, 20, scrollerSize, scrollerSize));
+  scroller.scrollLeft = scrollerSize - 200;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(200, 20, scrollerSize, scrollerSize));
+
+  // Check the percentage-based ScrollTimeline.
+  scroller.scrollLeft = scrollerSize - (0.19 * scrollerSize);
+  assert_equals(percentageScrollTimeline.currentTime, NaN);
+  scroller.scrollLeft = scrollerSize - (0.20 * scrollerSize);
+  assert_equals(percentageScrollTimeline.currentTime, 0);
+  scroller.scrollLeft = scrollerSize - (0.4 * scrollerSize);
+  assert_equals(
+      percentageScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.4 * scrollerSize, 0.2 * scrollerSize, scrollerSize, scrollerSize));
+
+  // Check the calc-based ScrollTimeline.
+  scroller.scrollLeft = scrollerSize - (0.2 * scrollerSize - 10);
+  assert_equals(calcScrollTimeline.currentTime, NaN);
+  scroller.scrollLeft = scrollerSize - (0.2 * scrollerSize - 5);
+  assert_equals(calcScrollTimeline.currentTime, 0);
+  scroller.scrollLeft = scrollerSize - (0.2 * scrollerSize);
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.2 * scrollerSize, 0.2 * scrollerSize - 5, scrollerSize,
+          scrollerSize));
+  scroller.scrollLeft = scrollerSize - (0.4 * scrollerSize);
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.4 * scrollerSize, 0.2 * scrollerSize - 5, scrollerSize,
+          scrollerSize));
+}, 'currentTime handles startScrollOffset with direction: rtl correctly');
+
+test(function() {
+  const scroller = setupScrollTimelineTest();
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const lengthScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    endScrollOffset: (scrollerSize - 20) + 'px'
+  });
+  const percentageScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    endScrollOffset: '80%'
+  });
+  const calcScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    endScrollOffset: 'calc(80% + 5px)'
+  });
+
+  // Check the length-based ScrollTimeline.
+  scroller.scrollTop = scrollerSize;
+  assert_equals(lengthScrollTimeline.currentTime, NaN);
+  scroller.scrollTop = scrollerSize - 20;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scrollerSize - 20, 0, scrollerSize - 20, scrollerSize));
+  scroller.scrollTop = scrollerSize - 50;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scrollerSize - 50, 0, scrollerSize - 20, scrollerSize));
+  scroller.scrollTop = scrollerSize - 200;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scrollerSize - 200, 0, scrollerSize - 20, scrollerSize));
+
+  // Check the percentage-based ScrollTimeline.
+  scroller.scrollTop = 0.81 * scrollerSize;
+  assert_equals(percentageScrollTimeline.currentTime, NaN);
+  scroller.scrollTop = 0.80 * scrollerSize;
+  assert_equals(
+      percentageScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0, 0.8 * scrollerSize, scrollerSize));
+  scroller.scrollTop = 0.50 * scrollerSize;
+  assert_equals(
+      percentageScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0, 0.8 * scrollerSize, scrollerSize));
+
+  // Check the calc-based ScrollTimeline.
+  scroller.scrollTop = 0.8 * scrollerSize + 6;
+  assert_equals(calcScrollTimeline.currentTime, NaN);
+  scroller.scrollTop = 0.8 * scrollerSize + 5;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0, 0.8 * scrollerSize + 5, scrollerSize));
+  scroller.scrollTop = 0.5 * scrollerSize;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scroller.scrollTop, 0, 0.8 * scrollerSize + 5, scrollerSize));
+}, 'currentTime handles endScrollOffset correctly');
+
+test(function() {
+  const scrollerOverrides = new Map([['direction', 'rtl']]);
+  const scroller = setupScrollTimelineTest(scrollerOverrides);
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const lengthScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal',
+    endScrollOffset: (scrollerSize - 20) + 'px'
+  });
+  const percentageScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal',
+    endScrollOffset: '80%'
+  });
+  const calcScrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'horizontal',
+    endScrollOffset: 'calc(80% + 5px)'
+  });
+
+  // With direction rtl offsets are inverted, such that scrollLeft ==
+  // scrollerSize is the 'zero' point for currentTime. However the
+  // endScrollOffset is an absolute distance along the offset, so doesn't need
+  // adjusting.
+
+  // Check the length-based ScrollTimeline.
+  scroller.scrollLeft = 0;
+  assert_equals(lengthScrollTimeline.currentTime, NaN);
+  scroller.scrollLeft = 20;
+  assert_equals(
+       lengthScrollTimeline.currentTime,
+       calculateCurrentTime(
+         scrollerSize - 20, 0, scrollerSize - 20, scrollerSize));
+  scroller.scrollLeft = 50;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scrollerSize - 50, 0, scrollerSize - 20, scrollerSize));
+  scroller.scrollLeft = 200;
+  assert_equals(
+      lengthScrollTimeline.currentTime,
+      calculateCurrentTime(
+          scrollerSize - 200, 0, scrollerSize - 20, scrollerSize));
+
+  // Check the percentage-based ScrollTimeline.
+  scroller.scrollLeft = 0.19 * scrollerSize;
+  assert_equals(percentageScrollTimeline.currentTime, NaN);
+  scroller.scrollLeft = 0.20 * scrollerSize;
+  assert_equals(
+      percentageScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.8 * scrollerSize, 0, 0.8 * scrollerSize, scrollerSize));
+  scroller.scrollLeft = 0.4 * scrollerSize;
+  assert_equals(
+      percentageScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.6 * scrollerSize, 0, 0.8 * scrollerSize, scrollerSize));
+
+  // Check the calc-based ScrollTimeline. 80% + 5px
+  scroller.scrollLeft = 0.2 * scrollerSize - 10;
+  assert_equals(calcScrollTimeline.currentTime, NaN);
+  scroller.scrollLeft = 0.2 * scrollerSize - 5;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.8 * scrollerSize + 5, 0, 0.8 * scrollerSize + 5, scrollerSize));
+  scroller.scrollLeft = 0.2 * scrollerSize;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.8 * scrollerSize, 0, 0.8 * scrollerSize + 5, scrollerSize));
+  scroller.scrollLeft = 0.6 * scrollerSize;
+  assert_equals(
+      calcScrollTimeline.currentTime,
+      calculateCurrentTime(
+          0.4 * scrollerSize, 0, 0.8 * scrollerSize + 5, scrollerSize));
+}, 'currentTime handles endScrollOffset with direction: rtl correctly');
+
+test(function() {
+  const scroller = setupScrollTimelineTest();
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const scrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    startScrollOffset: '20px',
+    endScrollOffset: (scrollerSize - 50) + 'px'
+  });
+
+  scroller.scrollTop = 150;
+  assert_equals(
+      scrollTimeline.currentTime,
+      calculateCurrentTime(150, 20, scrollerSize - 50, scrollerSize));
+}, 'currentTime handles startScrollOffset and endScrollOffset together correctly');
+
+test(function() {
+  const scroller = setupScrollTimelineTest();
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const scrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    startScrollOffset: '20px',
+    endScrollOffset: '20px',
+  });
+
+  scroller.scrollTop = 150;
+  assert_equals(scrollTimeline.currentTime, NaN);
+}, 'currentTime handles startScrollOffset == endScrollOffset correctly');
+
+test(function() {
+  const scroller = setupScrollTimelineTest();
+  // For simplicity, we set the timeRange such that currentTime maps directly to
+  // the value scrolled. We have a square scroller/contents, so can just compute
+  // one edge and use it for all the timelines;
+  const scrollerSize = scroller.scrollHeight - scroller.clientHeight;
+
+  const scrollTimeline = new ScrollTimeline({
+    scrollSource: scroller,
+    timeRange: scrollerSize,
+    orientation: 'block',
+    startScrollOffset: '50px',
+    endScrollOffset: '10px',
+  });
+
+  scroller.scrollTop = 150;
+  assert_equals(scrollTimeline.currentTime, NaN);
+}, 'currentTime handles startScrollOffset > endScrollOffset correctly');
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index cd288669..1cd2e1e 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -156,6 +156,8 @@
 PASS oldChildWindow.onseeked is newChildWindow.onseeked
 PASS oldChildWindow.onseeking is newChildWindow.onseeking
 PASS oldChildWindow.onselect is newChildWindow.onselect
+PASS oldChildWindow.onselectionchange is newChildWindow.onselectionchange
+PASS oldChildWindow.onselectstart is newChildWindow.onselectstart
 PASS oldChildWindow.onstalled is newChildWindow.onstalled
 PASS oldChildWindow.onstorage is newChildWindow.onstorage
 PASS oldChildWindow.onsubmit is newChildWindow.onsubmit
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index 47c9a74..e6998af8 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -122,6 +122,8 @@
 PASS childWindow.onseeked is null
 PASS childWindow.onseeking is null
 PASS childWindow.onselect is null
+PASS childWindow.onselectionchange is null
+PASS childWindow.onselectstart is null
 PASS childWindow.onstalled is null
 PASS childWindow.onstorage is null
 PASS childWindow.onsubmit is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index ec11869..ab2e94b 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -122,6 +122,8 @@
 PASS childWindow.onseeked is null
 PASS childWindow.onseeking is null
 PASS childWindow.onselect is null
+PASS childWindow.onselectionchange is null
+PASS childWindow.onselectstart is null
 PASS childWindow.onstalled is null
 PASS childWindow.onstorage is null
 PASS childWindow.onsubmit is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/event-attribute-availability-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/event-attribute-availability-expected.txt
index 6029949..3e4da97 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/event-attribute-availability-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/event-attribute-availability-expected.txt
@@ -121,7 +121,7 @@
 FAIL 'onpaste' in window should be true. Was false.
 PASS 'onreset' in window is true
 PASS 'onsearch' in window is true
-FAIL 'onselectstart' in window should be true. Was false.
+PASS 'onselectstart' in window is true
 
 Test Text Node
 PASS 'onabort' in textNode is false
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index 5bf5cf2e..408499a4 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -184,6 +184,7 @@
     property onseeked
     property onseeking
     property onselect
+    property onselectionchange
     property onselectstart
     property onstalled
     property onsubmit
@@ -1270,6 +1271,7 @@
     property onseeked
     property onseeking
     property onselect
+    property onselectionchange
     property onselectstart
     property onstalled
     property onsubmit
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 41106bf4..0b891678 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1530,7 +1530,6 @@
     getter onfullscreenerror
     getter onpaste
     getter onsearch
-    getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
     getter outerHTML
@@ -1609,7 +1608,6 @@
     setter onfullscreenerror
     setter onpaste
     setter onsearch
-    setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
     setter outerHTML
@@ -2161,6 +2159,8 @@
     getter onseeked
     getter onseeking
     getter onselect
+    getter onselectionchange
+    getter onselectstart
     getter onstalled
     getter onsubmit
     getter onsuspend
@@ -2255,6 +2255,8 @@
     setter onseeked
     setter onseeking
     setter onselect
+    setter onselectionchange
+    setter onselectstart
     setter onstalled
     setter onsubmit
     setter onsuspend
@@ -5282,6 +5284,8 @@
     getter onseeked
     getter onseeking
     getter onselect
+    getter onselectionchange
+    getter onselectstart
     getter onstalled
     getter onsubmit
     getter onsuspend
@@ -5364,6 +5368,8 @@
     setter onseeked
     setter onseeking
     setter onselect
+    setter onselectionchange
+    setter onselectstart
     setter onstalled
     setter onsubmit
     setter onsuspend
@@ -8644,6 +8650,8 @@
     getter onseeked
     getter onseeking
     getter onselect
+    getter onselectionchange
+    getter onselectstart
     getter onstalled
     getter onstorage
     getter onsubmit
@@ -8825,6 +8833,8 @@
     setter onseeked
     setter onseeking
     setter onselect
+    setter onselectionchange
+    setter onselectstart
     setter onstalled
     setter onstorage
     setter onsubmit
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver.https-expected.txt
index de3a0d9a..137b243 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-addTransceiver.https-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS addTransceiver() with string argument as invalid kind should throw TypeError
-FAIL addTransceiver('audio') should return an audio transceiver assert_equals: expected true but got false
-FAIL addTransceiver('video') should return a video transceiver assert_equals: expected true but got false
+PASS addTransceiver('audio') should return an audio transceiver
+PASS addTransceiver('video') should return a video transceiver
 PASS addTransceiver() with direction sendonly should have result transceiver.direction be the same
 PASS addTransceiver() with direction inactive should have result transceiver.direction be the same
 PASS addTransceiver() with invalid direction should throw TypeError
-FAIL addTransceiver(track) should have result with sender.track be given track assert_equals: expected true but got false
+PASS addTransceiver(track) should have result with sender.track be given track
 PASS addTransceiver(track) multiple times should create multiple transceivers
 FAIL addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError assert_throws: function "() =>
       pc.addTransceiver('audio', {
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
index 8570ecba..7d03361d 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
@@ -3,7 +3,7 @@
 PASS addTrack: "transceiver == {sender,receiver}"
 PASS addTrack: transceiver.sender is associated with the track
 PASS addTrack: transceiver.receiver has its own track
-FAIL addTrack: transceiver.receiver's track is muted assert_true: expected true got false
+PASS addTrack: transceiver.receiver's track is muted
 PASS addTrack: transceiver is not associated with an m-section
 PASS addTrack: transceiver is not stopped
 PASS addTrack: transceiver's direction is sendrecv
@@ -40,5 +40,6 @@
 PASS addTransceiver does not reuse reusable transceivers
 PASS Can setup two-way call using a single transceiver
 PASS Closing the PC stops the transceivers
+PASS Changing transceiver direction to 'sendrecv' makes ontrack fire
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index bcab700..0fbc43bc 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -234,6 +234,7 @@
     property onseeked
     property onseeking
     property onselect
+    property onselectionchange
     property onselectstart
     property onstalled
     property onsubmit
@@ -1387,6 +1388,7 @@
     property onseeked
     property onseeking
     property onselect
+    property onselectionchange
     property onselectstart
     property onstalled
     property onsubmit
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 537e5a6..d2a485f7 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1907,7 +1907,6 @@
     getter onfullscreenerror
     getter onpaste
     getter onsearch
-    getter onselectstart
     getter onwebkitfullscreenchange
     getter onwebkitfullscreenerror
     getter outerHTML
@@ -2030,7 +2029,6 @@
     setter onfullscreenerror
     setter onpaste
     setter onsearch
-    setter onselectstart
     setter onwebkitfullscreenchange
     setter onwebkitfullscreenerror
     setter outerHTML
@@ -2626,6 +2624,8 @@
     getter onseeked
     getter onseeking
     getter onselect
+    getter onselectionchange
+    getter onselectstart
     getter onstalled
     getter onsubmit
     getter onsuspend
@@ -2724,6 +2724,8 @@
     setter onseeked
     setter onseeking
     setter onselect
+    setter onselectionchange
+    setter onselectstart
     setter onstalled
     setter onsubmit
     setter onsuspend
@@ -5984,6 +5986,8 @@
     getter onseeked
     getter onseeking
     getter onselect
+    getter onselectionchange
+    getter onselectstart
     getter onstalled
     getter onsubmit
     getter onsuspend
@@ -6069,6 +6073,8 @@
     setter onseeked
     setter onseeking
     setter onselect
+    setter onselectionchange
+    setter onselectstart
     setter onstalled
     setter onsubmit
     setter onsuspend
@@ -10581,6 +10587,8 @@
     getter onseeked
     getter onseeking
     getter onselect
+    getter onselectionchange
+    getter onselectstart
     getter onstalled
     getter onstorage
     getter onsubmit
@@ -10769,6 +10777,8 @@
     setter onseeked
     setter onseeking
     setter onselect
+    setter onselectionchange
+    setter onselectstart
     setter onstalled
     setter onstorage
     setter onsubmit
diff --git a/third_party/blink/PRESUBMIT.py b/third_party/blink/PRESUBMIT.py
index d517a74..b08509a7 100644
--- a/third_party/blink/PRESUBMIT.py
+++ b/third_party/blink/PRESUBMIT.py
@@ -94,26 +94,34 @@
     return results
 
 
-def _CheckStyle(input_api, output_api):
-    style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
-                                                'tools', 'check_blink_style.py')
-    args = [input_api.python_executable, style_checker_path, '--diff-files']
+def _FilterPaths(input_api):
+    """Returns input files with certain paths removed."""
     files = []
     for f in input_api.AffectedFiles():
         file_path = f.LocalPath()
-        # Filter out changes in LayoutTests.
-        if 'web_tests' + input_api.os_path.sep in file_path and 'TestExpectations' not in file_path:
+        # Filter out changes in web_tests/.
+        if ('web_tests' + input_api.os_path.sep in file_path
+            and 'TestExpectations' not in file_path):
             continue
         if '/PRESUBMIT' in file_path:
             continue
         files.append(input_api.os_path.join('..', '..', file_path))
+    return files
+
+
+def _CheckStyle(input_api, output_api):
+    files = _FilterPaths(input_api)
     # Do not call check_blink_style.py with empty affected file list if all
     # input_api.AffectedFiles got filtered.
     if not files:
         return []
-    args += files
-    results = []
 
+    style_checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
+                                                'tools', 'check_blink_style.py')
+    args = [input_api.python_executable, style_checker_path, '--diff-files']
+    args += files
+
+    results = []
     try:
         child = input_api.subprocess.Popen(args,
                                            stderr=input_api.subprocess.PIPE)
diff --git a/third_party/blink/PRESUBMIT_test.py b/third_party/blink/PRESUBMIT_test.py
index 2f31b03..2ddf28f 100755
--- a/third_party/blink/PRESUBMIT_test.py
+++ b/third_party/blink/PRESUBMIT_test.py
@@ -70,16 +70,35 @@
         diff_file_chromium2_h = ['another diff']
         diff_file_layout_test_html = ['more diff']
         mock_input_api = MockInputApi()
-        mock_input_api.files = [
-            MockAffectedFile('first_file_chromium.h', diff_file_chromium1_h),
-            MockAffectedFile('second_file_chromium.h', diff_file_chromium2_h),
-            MockAffectedFile('LayoutTests/some_tests.html', diff_file_layout_test_html)
-        ]
+        mock_input_api.files = []
         # Access to a protected member _CheckStyle
         # pylint: disable=W0212
         PRESUBMIT._CheckStyle(mock_input_api, MockOutputApi())
-        # pylint: disable=E1101
-        subprocess.Popen.assert_not_called()
+        self.assertEqual(0, subprocess.Popen.call_count)
+
+    def test_FilterPaths(self):
+        """This verifies that _FilterPaths removes expected paths."""
+        diff_file_chromium1_h = ['some diff']
+        diff_web_tests_html = ['more diff']
+        diff_presubmit = ['morer diff']
+        diff_test_expectations = ['morest diff']
+        mock_input_api = MockInputApi()
+        mock_input_api.files = [
+            MockAffectedFile('file_chromium1.h', diff_file_chromium1_h),
+            MockAffectedFile('web_tests/some_tests.html', diff_web_tests_html),
+            MockAffectedFile('web_tests/TestExpectations', diff_test_expectations),
+            MockAffectedFile('blink/PRESUBMIT', diff_presubmit),
+        ]
+        # Access to a protected member _FilterPaths
+        # pylint: disable=W0212
+        filtered = PRESUBMIT._FilterPaths(mock_input_api)
+        self.assertEqual(2, len(filtered))
+        self.assertEqual(
+            mock_input_api.os_path.join('..', '..', 'file_chromium1.h'),
+            filtered[0])
+        self.assertEqual(
+            mock_input_api.os_path.join('..', '..', 'web_tests/TestExpectations'),
+            filtered[1])
 
     def testCheckPublicHeaderWithBlinkMojo(self):
         """This verifies that _CheckForWrongMojomIncludes detects -blink mojo
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
index 8bbf461..9b8c92b 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/fetch/fetch_data_loader.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
@@ -108,7 +109,7 @@
       streaming_->Abort(v8::Local<v8::Value>());
     }
   }
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
   std::shared_ptr<v8::WasmStreaming> streaming_;
   const Member<ScriptState> script_state_;
@@ -205,7 +206,7 @@
       builder_.Abort(v8::Local<v8::Value>());
     }
   }
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
   v8::WasmModuleObjectBuilderStreaming builder_;
   const Member<ScriptState> script_state_;
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.cc b/third_party/blink/renderer/core/animation/scroll_timeline.cc
index e85a1755..04e2128f 100644
--- a/third_party/blink/renderer/core/animation/scroll_timeline.cc
+++ b/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -4,13 +4,17 @@
 
 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
 
+#include "third_party/blink/renderer/core/css/css_calculation_value.h"
+#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/css/properties/css_parsing_utils.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/platform/length_functions.h"
 
 namespace blink {
 
@@ -159,22 +163,76 @@
     current_offset = scroll_offset.Height();
     max_offset = scroll_dimensions.Height();
   }
+  // When using a rtl direction, current_offset grows correctly from 0 to
+  // max_offset, but is negative. Since our offsets are all just deltas along
+  // the orientation direction, we can just take the absolute current_offset and
+  // use that everywhere.
+  current_offset = std::abs(current_offset);
+
+  double resolved_start_scroll_offset = 0;
+  double resolved_end_scroll_offset = max_offset;
+  ResolveScrollStartAndEnd(layout_box, max_offset, resolved_start_scroll_offset,
+                           resolved_end_scroll_offset);
 
   // 3. If current scroll offset is less than startScrollOffset, return an
   // unresolved time value if fill is none or forwards, or 0 otherwise.
-  // TODO(smcgruer): Implement |startScrollOffset| and |fill|.
+  // TODO(smcgruer): Implement |fill|.
+  if (current_offset < resolved_start_scroll_offset) {
+    return std::numeric_limits<double>::quiet_NaN();
+  }
 
   // 4. If current scroll offset is greater than or equal to endScrollOffset,
   // return an unresolved time value if fill is none or backwards, or the
   // effective time range otherwise.
-  // TODO(smcgruer): Implement |endScrollOffset| and |fill|.
+  //
+  // TODO(smcgruer): Implement |fill|.
+  //
+  // Note we deliberately break the spec here by only returning if the current
+  // offset is strictly greater, as that is more in line with the web animation
+  // spec. See https://github.com/WICG/scroll-animations/issues/19
+  if (current_offset > resolved_end_scroll_offset) {
+    return std::numeric_limits<double>::quiet_NaN();
+  }
+
+  // This is not by the spec, but avoids both negative current time and a
+  // divsion by zero issue. See
+  // https://github.com/WICG/scroll-animations/issues/20 and
+  // https://github.com/WICG/scroll-animations/issues/21
+  if (resolved_start_scroll_offset >= resolved_end_scroll_offset) {
+    return std::numeric_limits<double>::quiet_NaN();
+  }
 
   // 5. Return the result of evaluating the following expression:
   //   ((current scroll offset - startScrollOffset) /
   //      (endScrollOffset - startScrollOffset)) * effective time range
-
   is_null = false;
-  return (std::abs(current_offset) / max_offset) * time_range_;
+  return ((current_offset - resolved_start_scroll_offset) /
+          (resolved_end_scroll_offset - resolved_start_scroll_offset)) *
+         time_range_;
+}
+
+void ScrollTimeline::ResolveScrollStartAndEnd(
+    const LayoutBox* layout_box,
+    double max_offset,
+    double& resolved_start_scroll_offset,
+    double& resolved_end_scroll_offset) {
+  const ComputedStyle& computed_style = layout_box->StyleRef();
+  Document& document = layout_box->GetDocument();
+  const ComputedStyle* root_style =
+      document.documentElement()
+          ? document.documentElement()->GetComputedStyle()
+          : document.GetComputedStyle();
+  CSSToLengthConversionData conversion_data = CSSToLengthConversionData(
+      &computed_style, root_style, document.GetLayoutView(),
+      computed_style.EffectiveZoom());
+  if (start_scroll_offset_) {
+    resolved_start_scroll_offset = FloatValueForLength(
+        start_scroll_offset_->ConvertToLength(conversion_data), max_offset);
+  }
+  if (end_scroll_offset_) {
+    resolved_end_scroll_offset = FloatValueForLength(
+        end_scroll_offset_->ConvertToLength(conversion_data), max_offset);
+  }
 }
 
 Element* ScrollTimeline::scrollSource() {
diff --git a/third_party/blink/renderer/core/animation/scroll_timeline.h b/third_party/blink/renderer/core/animation/scroll_timeline.h
index 397c25f..173af1a 100644
--- a/third_party/blink/renderer/core/animation/scroll_timeline.h
+++ b/third_party/blink/renderer/core/animation/scroll_timeline.h
@@ -78,6 +78,11 @@
                  CSSPrimitiveValue*,
                  double);
 
+  void ResolveScrollStartAndEnd(const LayoutBox*,
+                                double max_offset,
+                                double& resolved_start_scroll_offset,
+                                double& resolved_end_scroll_offset);
+
   Member<Element> scroll_source_;
   ScrollDirection orientation_;
   Member<CSSPrimitiveValue> start_scroll_offset_;
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 1cefa93f..92bd91d 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -310,8 +310,6 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(resume);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(securitypolicyviolation);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(selectionchange);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(visibilitychange);
 
   ViewportData& GetViewportData() const { return *viewport_data_; }
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl
index 5f6ff88..80025e0 100644
--- a/third_party/blink/renderer/core/dom/document.idl
+++ b/third_party/blink/renderer/core/dom/document.idl
@@ -216,8 +216,6 @@
     [RuntimeEnabled=PageLifecycle] attribute EventHandler onresume;
     attribute EventHandler onsearch;
     [RuntimeEnabled=ExperimentalContentSecurityPolicyFeatures] attribute EventHandler onsecuritypolicyviolation;
-    attribute EventHandler onselectionchange;
-    attribute EventHandler onselectstart;
     attribute EventHandler onvisibilitychange;
 };
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 494a938..81d7868 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1636,16 +1636,18 @@
     const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
         string_or_TT,
     ExceptionState& exception_state) {
-  if (GetCheckedAttributeNames().Contains(name)) {
+  // TODO(vogelheim): Check whether this applies to non-HTML documents, too.
+  AtomicString name_lowercase = LowercaseIfNecessary(name);
+  if (GetCheckedAttributeNames().Contains(name_lowercase)) {
     String attr_value =
         GetStringFromTrustedType(string_or_TT, &GetDocument(), exception_state);
     if (!exception_state.HadException())
-      setAttribute(name, AtomicString(attr_value), exception_state);
+      setAttribute(name_lowercase, AtomicString(attr_value), exception_state);
     return;
   }
   AtomicString value_string =
       AtomicString(GetStringFromTrustedTypeWithoutCheck(string_or_TT));
-  setAttribute(name, value_string, exception_state);
+  setAttribute(name_lowercase, value_string, exception_state);
 }
 
 const HashSet<AtomicString>& Element::GetCheckedAttributeNames() const {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index be54612..a75da2d 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -163,11 +163,8 @@
   DEFINE_ATTRIBUTE_EVENT_LISTENER(beforepaste);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(copy);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(cut);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(gotpointercapture);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(lostpointercapture);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(paste);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
 
   bool hasAttribute(const QualifiedName&) const;
   const AtomicString& getAttribute(const QualifiedName&) const;
diff --git a/third_party/blink/renderer/core/dom/element.idl b/third_party/blink/renderer/core/dom/element.idl
index e4359a4..49e0f61 100644
--- a/third_party/blink/renderer/core/dom/element.idl
+++ b/third_party/blink/renderer/core/dom/element.idl
@@ -145,7 +145,6 @@
     attribute EventHandler oncut;
     attribute EventHandler onpaste;
     attribute EventHandler onsearch;
-    attribute EventHandler onselectstart;
 };
 
 Element implements ParentNode;
diff --git a/third_party/blink/renderer/core/dom/global_event_handlers.h b/third_party/blink/renderer/core/dom/global_event_handlers.h
index 8dce1e2..e01c6ca 100644
--- a/third_party/blink/renderer/core/dom/global_event_handlers.h
+++ b/third_party/blink/renderer/core/dom/global_event_handlers.h
@@ -104,6 +104,8 @@
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(seeked);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(seeking);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(select);
+  DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(selectionchange);
+  DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(selectstart);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(stalled);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(submit);
   DEFINE_STATIC_ATTRIBUTE_EVENT_LISTENER(suspend);
diff --git a/third_party/blink/renderer/core/dom/global_event_handlers.idl b/third_party/blink/renderer/core/dom/global_event_handlers.idl
index 5490b60..adff5bb4 100644
--- a/third_party/blink/renderer/core/dom/global_event_handlers.idl
+++ b/third_party/blink/renderer/core/dom/global_event_handlers.idl
@@ -122,4 +122,9 @@
     [OriginTrialEnabled=TouchEventFeatureDetection] attribute EventHandler ontouchend;
     [OriginTrialEnabled=TouchEventFeatureDetection] attribute EventHandler ontouchmove;
     [OriginTrialEnabled=TouchEventFeatureDetection] attribute EventHandler ontouchstart;
+
+    // Selection API
+    // https://w3c.github.io/selection-api/#extensions-to-globaleventhandlers
+    attribute EventHandler onselectstart;
+    attribute EventHandler onselectionchange;
 };
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index cb642b0..9ba51860 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -2044,8 +2044,8 @@
         GetDocument().AddListenerTypeIfNeeded(type, *this);
     }
   }
-
-  old_document.Markers().RemoveMarkersForNode(this);
+  if (IsTextNode())
+    old_document.Markers().RemoveMarkersForNode(*ToText(this));
   if (GetDocument().GetPage() &&
       GetDocument().GetPage() != old_document.GetPage()) {
     GetDocument().GetFrame()->GetEventHandlerRegistry().DidMoveIntoPage(*this);
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
index 8c5ce7f5..fdf850c 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.cc
@@ -221,11 +221,13 @@
     if (!PossiblyHasMarkers(marker_types))
       return;
     DCHECK(!markers_.IsEmpty());
-
+    const Node& node = marked_text.CurrentContainer();
+    if (!node.IsTextNode())
+      continue;
     int start_offset = marked_text.StartOffsetInCurrentContainer();
     int end_offset = marked_text.EndOffsetInCurrentContainer();
-    RemoveMarkersInternal(marked_text.CurrentContainer(), start_offset,
-                          end_offset - start_offset, marker_types);
+    RemoveMarkersInternal(ToText(node), start_offset, end_offset - start_offset,
+                          marker_types);
   }
 }
 
@@ -336,13 +338,10 @@
 }
 
 void DocumentMarkerController::RemoveMarkersInternal(
-    const Node& node,
+    const Text& text,
     unsigned start_offset,
     int length,
     DocumentMarker::MarkerTypes marker_types) {
-  // TODO(yoichio): Make this function to take Text instead of Node.
-  if (!node.IsTextNode())
-    return;
   if (length <= 0)
     return;
 
@@ -350,7 +349,7 @@
     return;
   DCHECK(!(markers_.IsEmpty()));
 
-  MarkerLists* const markers = markers_.at(&ToText(node));
+  MarkerLists* const markers = markers_.at(&text);
   if (!markers)
     return;
 
@@ -377,7 +376,7 @@
   }
 
   if (empty_lists_count == DocumentMarker::kMarkerTypeIndexesCount) {
-    markers_.erase(&ToText(node));
+    markers_.erase(&text);
     if (markers_.IsEmpty()) {
       possibly_existing_marker_types_ = DocumentMarker::MarkerTypes();
       SetContext(nullptr);
@@ -387,7 +386,7 @@
   if (!doc_dirty)
     return;
 
-  InvalidatePaintForNode(node);
+  InvalidatePaintForNode(text);
 }
 
 DocumentMarker* DocumentMarkerController::FirstMarkerIntersectingOffsetRange(
@@ -675,16 +674,13 @@
 }
 
 void DocumentMarkerController::RemoveMarkersForNode(
-    const Node* node,
+    const Text& text,
     DocumentMarker::MarkerTypes marker_types) {
-  // TODO(yoichio): Make this function to take Text instead of Node.
-  if (!node->IsTextNode())
-    return;
   if (!PossiblyHasMarkers(marker_types))
     return;
   DCHECK(!markers_.IsEmpty());
 
-  MarkerMap::iterator iterator = markers_.find(ToText(node));
+  MarkerMap::iterator iterator = markers_.find(&text);
   if (iterator != markers_.end())
     RemoveMarkersFromList(iterator, marker_types);
 }
@@ -707,17 +703,14 @@
   }
 }
 
-void DocumentMarkerController::RemoveSuggestionMarkerByTag(const Node* node,
+void DocumentMarkerController::RemoveSuggestionMarkerByTag(const Text& text,
                                                            int32_t marker_tag) {
-  // TODO(yoichio): Make this function to take Text instead of Node.
-  if (!node->IsTextNode())
-    return;
-  MarkerLists* markers = markers_.at(ToText(node));
+  MarkerLists* markers = markers_.at(&text);
   SuggestionMarkerListImpl* const list = ToSuggestionMarkerListImpl(
       ListForType(markers, DocumentMarker::kSuggestion));
   if (!list->RemoveMarkerByTag(marker_tag))
     return;
-  InvalidatePaintForNode(*node);
+  InvalidatePaintForNode(text);
 }
 
 void DocumentMarkerController::RemoveMarkersOfTypes(
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
index 5496355..1da57c4 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
@@ -79,10 +79,10 @@
   void RemoveMarkersInRange(const EphemeralRange&, DocumentMarker::MarkerTypes);
   void RemoveMarkersOfTypes(DocumentMarker::MarkerTypes);
   void RemoveMarkersForNode(
-      const Node*,
+      const Text&,
       DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All());
   void RemoveSpellingMarkersUnderWords(const Vector<String>& words);
-  void RemoveSuggestionMarkerByTag(const Node*, int32_t marker_tag);
+  void RemoveSuggestionMarkerByTag(const Text&, int32_t marker_tag);
   void RepaintMarkers(
       DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All());
   // Returns true if markers within a range are found.
@@ -154,7 +154,7 @@
   bool PossiblyHasMarkers(DocumentMarker::MarkerType) const;
   void RemoveMarkersFromList(MarkerMap::iterator, DocumentMarker::MarkerTypes);
   void RemoveMarkers(TextIterator&, DocumentMarker::MarkerTypes);
-  void RemoveMarkersInternal(const Node&,
+  void RemoveMarkersInternal(const Text&,
                              unsigned start_offset,
                              int length,
                              DocumentMarker::MarkerTypes);
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
index 3d71f4ec..3474937 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
@@ -366,7 +366,7 @@
   ASSERT_EQ(1u, MarkerController().Markers().size());
   const SuggestionMarker& marker =
       *ToSuggestionMarker(MarkerController().Markers()[0]);
-  MarkerController().RemoveSuggestionMarkerByTag(text, marker.Tag());
+  MarkerController().RemoveSuggestionMarkerByTag(*ToText(text), marker.Tag());
   EXPECT_EQ(0u, MarkerController().Markers().size());
 }
 
diff --git a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
index 9c6a319..2ead505 100644
--- a/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
+++ b/third_party/blink/renderer/core/editing/spellcheck/spell_checker.cc
@@ -416,9 +416,10 @@
   GetFrame().GetDocument()->UpdateStyleAndLayoutTreeForNode(&element);
 
   for (Node& node : NodeTraversal::InclusiveDescendantsOf(element)) {
-    if (elements_type == ElementsType::kAll || !HasEditableStyle(node)) {
+    if ((elements_type == ElementsType::kAll || !HasEditableStyle(node)) &&
+        node.IsTextNode()) {
       GetFrame().GetDocument()->Markers().RemoveMarkersForNode(
-          &node, DocumentMarker::MarkerTypes::Misspelling());
+          ToText(node), DocumentMarker::MarkerTypes::Misspelling());
     }
   }
 }
diff --git a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
index 367427f0..fccf290 100644
--- a/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
+++ b/third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.cc
@@ -296,14 +296,14 @@
           GetFrame().GetDocument()->Markers().MarkersIntersectingRange(
               range_to_check, DocumentMarker::MarkerTypes::Suggestion());
 
-  const Node* marker_text_node = nullptr;
+  const Text* marker_text_node = nullptr;
   SuggestionMarker* marker = nullptr;
   for (const std::pair<Member<Node>, Member<DocumentMarker>>& node_marker_pair :
        node_marker_pairs) {
     SuggestionMarker* suggestion_marker =
         ToSuggestionMarker(node_marker_pair.second);
     if (suggestion_marker->Tag() == marker_tag) {
-      marker_text_node = node_marker_pair.first;
+      marker_text_node = ToText(node_marker_pair.first);
       marker = suggestion_marker;
       break;
     }
@@ -313,7 +313,7 @@
     OnSuggestionMenuClosed();
     return;
   }
-
+  DCHECK(marker_text_node);
   const EphemeralRange& range_to_replace =
       EphemeralRange(Position(marker_text_node, marker->StartOffset()),
                      Position(marker_text_node, marker->EndOffset()));
@@ -328,7 +328,7 @@
 
   if (marker->IsMisspelling()) {
     GetFrame().GetDocument()->Markers().RemoveSuggestionMarkerByTag(
-        marker_text_node, marker->Tag());
+        *marker_text_node, marker->Tag());
   } else {
     marker->SetSuggestion(suggestion_index, new_suggestion);
   }
diff --git a/third_party/blink/renderer/core/fetch/blob_bytes_consumer.h b/third_party/blink/renderer/core/fetch/blob_bytes_consumer.h
index 57927398..e7e4b923 100644
--- a/third_party/blink/renderer/core/fetch/blob_bytes_consumer.h
+++ b/third_party/blink/renderer/core/fetch/blob_bytes_consumer.h
@@ -9,6 +9,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/fetch/bytes_consumer.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
@@ -42,7 +43,7 @@
  private:
   Member<ExecutionContext> execution_context_;
   scoped_refptr<BlobDataHandle> blob_data_handle_;
-  Member<BytesConsumer> nested_consumer_;
+  TraceWrapperMember<BytesConsumer> nested_consumer_;
   Member<BytesConsumer::Client> client_;
 };
 
diff --git a/third_party/blink/renderer/core/fetch/body_stream_buffer.cc b/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
index aabb7b8..aaccc59 100644
--- a/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
+++ b/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
@@ -143,8 +143,9 @@
       script_state_(script_state),
       signal_(nullptr),
       made_from_readable_stream_(true) {
-  // TODO(ricea): Perhaps this is not needed since the caller must have a strong
-  // reference to |stream| anyway?
+  // This is needed because sometimes a BodyStreamBuffer can be detached from
+  // the owner object such as Request. We rely on the wrapper and
+  // HasPendingActivity in such a case.
   RetainWrapperDuringConstruction(this, script_state);
   DCHECK(ReadableStreamOperations::IsReadableStreamForDCheck(script_state,
                                                              stream));
diff --git a/third_party/blink/renderer/core/fetch/body_stream_buffer.h b/third_party/blink/renderer/core/fetch/body_stream_buffer.h
index 8fcd626..febd613 100644
--- a/third_party/blink/renderer/core/fetch/body_stream_buffer.h
+++ b/third_party/blink/renderer/core/fetch/body_stream_buffer.h
@@ -101,9 +101,9 @@
 
   Member<ScriptState> script_state_;
   TraceWrapperV8Reference<v8::Object> stream_;
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   // We need this member to keep it alive while loading.
-  Member<FetchDataLoader> loader_;
+  TraceWrapperMember<FetchDataLoader> loader_;
   // We need this to ensure that we detect that abort has been signalled
   // correctly.
   Member<AbortSignal> signal_;
diff --git a/third_party/blink/renderer/core/fetch/bytes_consumer.cc b/third_party/blink/renderer/core/fetch/bytes_consumer.cc
index 6f87e0c..af91e44 100644
--- a/third_party/blink/renderer/core/fetch/bytes_consumer.cc
+++ b/third_party/blink/renderer/core/fetch/bytes_consumer.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fetch/blob_bytes_consumer.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -301,7 +302,7 @@
     destination2_->Notify();
   }
 
-  Member<BytesConsumer> src_;
+  TraceWrapperMember<BytesConsumer> src_;
   Member<Destination> destination1_;
   Member<Destination> destination2_;
 };
diff --git a/third_party/blink/renderer/core/fetch/bytes_consumer.h b/third_party/blink/renderer/core/fetch/bytes_consumer.h
index de94e3e..96e27de 100644
--- a/third_party/blink/renderer/core/fetch/bytes_consumer.h
+++ b/third_party/blink/renderer/core/fetch/bytes_consumer.h
@@ -24,6 +24,8 @@
 // BytesConsumer has four states: waiting, readable, closed and errored. Once
 // the state becomes closed or errored, it will never change. |readable| means
 // that the BytesConsumer is ready to read non-empty bytes synchronously.
+// A BytesConsumer should be retained by TraceWrapperMember, not Member, as
+// a subclass has a reference to a v8::Value.
 class CORE_EXPORT BytesConsumer
     : public GarbageCollectedFinalized<BytesConsumer> {
  public:
diff --git a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
index c4cd752..4f20b0f 100644
--- a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
@@ -106,7 +106,7 @@
   }
 
  private:
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
 
   String mime_type_;
@@ -179,7 +179,7 @@
   }
 
  private:
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
 
   std::unique_ptr<ArrayBufferBuilder> raw_data_;
@@ -235,7 +235,7 @@
   }
 
  private:
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
 };
 
@@ -405,7 +405,7 @@
     std::unique_ptr<TextResourceDecoder> string_decoder_;
   };
 
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
   Member<FormData> form_data_;
   Member<MultipartParser> multipart_parser_;
@@ -473,7 +473,7 @@
   }
 
  private:
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
 
   std::unique_ptr<TextResourceDecoder> decoder_;
@@ -576,7 +576,7 @@
     out_data_pipe_.reset();
   }
 
-  Member<BytesConsumer> consumer_;
+  TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
 
   mojo::ScopedDataPipeProducerHandle out_data_pipe_;
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index 0aed2a7..b191f93 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -192,7 +192,7 @@
   }
 
  private:
-  Member<BytesConsumer> underlying_;
+  TraceWrapperMember<BytesConsumer> underlying_;
   Member<Client> client_;
   bool is_cancelled_ = false;
 };
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
index 80737ae..e97cf4c1 100644
--- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
+++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -468,7 +468,7 @@
 
  private:
   scoped_refptr<EncodedFormData> form_data_;
-  Member<BytesConsumer> blob_bytes_consumer_;
+  TraceWrapperMember<BytesConsumer> blob_bytes_consumer_;
 };
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h
index b078589..009fe4f 100644
--- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h
+++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/fetch/bytes_consumer.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
@@ -71,7 +72,7 @@
                                     scoped_refptr<EncodedFormData>,
                                     BytesConsumer* consumer_for_testing);
 
-  const Member<BytesConsumer> impl_;
+  const TraceWrapperMember<BytesConsumer> impl_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
index edbc166..2f92f6fb 100644
--- a/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
+++ b/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.cc
@@ -98,7 +98,6 @@
     ScriptValue stream_reader)
     : reader_(script_state->GetIsolate(), stream_reader.V8Value()),
       script_state_(script_state) {
-  reader_.SetPhantom();
 }
 
 ReadableStreamBytesConsumer::~ReadableStreamBytesConsumer() {}
@@ -172,6 +171,7 @@
 }
 
 void ReadableStreamBytesConsumer::Trace(blink::Visitor* visitor) {
+  visitor->Trace(reader_);
   visitor->Trace(client_);
   visitor->Trace(pending_buffer_);
   visitor->Trace(script_state_);
diff --git a/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h b/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h
index 94ec6ea8..0c16774 100644
--- a/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h
+++ b/third_party/blink/renderer/core/fetch/readable_stream_bytes_consumer.h
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/fetch/bytes_consumer.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 
@@ -22,10 +23,6 @@
 // implemented with V8 Extras.
 // The stream will be immediately locked by the consumer and will never be
 // released.
-//
-// The ReadableStreamReader handle held in a ReadableStreamDataConsumerHandle
-// is weak. A user must guarantee that the ReadableStreamReader object is kept
-// alive appropriately.
 class CORE_EXPORT ReadableStreamBytesConsumer final : public BytesConsumer {
   USING_PRE_FINALIZER(ReadableStreamBytesConsumer, Dispose);
 
@@ -55,11 +52,7 @@
   void OnRejected();
   void Notify();
 
-  // |m_reader| is a weak persistent. It should be kept alive by someone
-  // outside of ReadableStreamBytesConsumer.
-  // Holding a ScopedPersistent here is safe in terms of cross-world wrapper
-  // leakage because we read only Uint8Array chunks from the reader.
-  ScopedPersistent<v8::Value> reader_;
+  TraceWrapperV8Reference<v8::Value> reader_;
   Member<ScriptState> script_state_;
   Member<BytesConsumer::Client> client_;
   Member<DOMUint8Array> pending_buffer_;
diff --git a/third_party/blink/renderer/core/html/html_object_element.cc b/third_party/blink/renderer/core/html/html_object_element.cc
index 9babda6..97661052 100644
--- a/third_party/blink/renderer/core/html/html_object_element.cc
+++ b/third_party/blink/renderer/core/html/html_object_element.cc
@@ -72,7 +72,7 @@
 const HashSet<AtomicString>& HTMLObjectElement::GetCheckedAttributeNames()
     const {
   DEFINE_STATIC_LOCAL(HashSet<AtomicString>, attribute_set,
-                      ({"data", "codeBase"}));
+                      ({"data", "codebase"}));
   return attribute_set;
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index 3ecb4fd9..a0da7ada 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -668,7 +668,7 @@
   Document& document = GetDocument();
   if (Node* body = document.body()) {
     // Framesets can't scroll.
-    if (IsHTMLFrameSetElement(body) && body->GetLayoutObject())
+    if (body->GetLayoutObject() && body->GetLayoutObject()->IsFrameSet())
       RETURN_SCROLLBAR_MODE(kScrollbarAlwaysOff);
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
index 3a52900..1fefb93e 100644
--- a/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
@@ -259,40 +259,43 @@
   // NOTE: This could potentially be done lazily when we query the exclusion
   // space for a layout opportunity.
   for (size_t i = 0; i < shelves_.size(); ++i) {
-    // Check if we need to insert a new shelf between two other shelves. E.g.
-    //
-    //    0 1 2 3 4 5 6 7 8
-    // 0  +-----+X----X+---+
-    //    |xxxxx|      |xxx|
-    // 10 +-----+      |xxx|
-    //      +---+      |xxx|
-    // 20   |NEW|      |xxx|
-    //    X-----------X|xxx|
-    // 30              |xxx|
-    //    X----------------X
-    //
-    // In the above example the "NEW" left exclusion creates a shelf between
-    // the two other shelves drawn.
-    //
-    // NOTE: We calculate this upfront as we may remove the shelf we need to
-    // check against.
-    //
-    // NOTE: If there is no "next" shelf, we consider this between shelves.
-    bool is_between_shelves =
-        exclusion_end_offset >= shelves_[i].block_offset &&
-        (i + 1 >= shelves_.size() ||
-         exclusion_end_offset < shelves_[i + 1].block_offset);
-
     // We modify the current shelf in-place. However we need to keep a copy of
     // the shelf if we need to insert a new shelf later in the loop.
     base::Optional<NGShelf> shelf_copy;
-    if (is_between_shelves)
-      shelf_copy.emplace(shelves_[i]);
+
+    bool is_between_shelves;
 
     // A new scope is created as shelf may be removed.
     {
       NGShelf& shelf = shelves_[i];
 
+      // Check if we need to insert a new shelf between two other shelves. E.g.
+      //
+      //    0 1 2 3 4 5 6 7 8
+      // 0  +-----+X----X+---+
+      //    |xxxxx|      |xxx|
+      // 10 +-----+      |xxx|
+      //      +---+      |xxx|
+      // 20   |NEW|      |xxx|
+      //    X-----------X|xxx|
+      // 30              |xxx|
+      //    X----------------X
+      //
+      // In the above example the "NEW" left exclusion creates a shelf between
+      // the two other shelves drawn.
+      //
+      // NOTE: We calculate this upfront as we may remove the shelf we need to
+      // check against.
+      //
+      // NOTE: If there is no "next" shelf, we consider this between shelves.
+      is_between_shelves =
+          exclusion_end_offset >= shelf.block_offset &&
+          (i + 1 >= shelves_.size() ||
+           exclusion_end_offset < shelves_[i + 1].block_offset);
+
+      if (is_between_shelves)
+        shelf_copy.emplace(shelf);
+
       // Check if the new exclusion will be below this shelf. E.g.
       //
       //    0 1 2 3 4 5 6 7 8
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
index 862f6ad..c36ff07b7 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
@@ -56,11 +56,6 @@
     // TODO(mstensho): Inherit all properties listed here:
     // https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements
 
-    // We need to enter legacy layout from this point on, if ...
-    if (!RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled() &&
-        new_style->SpecifiesColumns())
-      new_style->SetForceLegacyLayout(true);
-
     fieldset_content = LayoutBlock::CreateAnonymousWithParentAndDisplay(
         this, new_style->Display());
     fieldset_content->SetStyle(std::move(new_style));
diff --git a/third_party/blink/renderer/core/page/touch_adjustment.cc b/third_party/blink/renderer/core/page/touch_adjustment.cc
index b425547..c476605 100644
--- a/third_party/blink/renderer/core/page/touch_adjustment.cc
+++ b/third_party/blink/renderer/core/page/touch_adjustment.cc
@@ -41,7 +41,7 @@
 
 namespace blink {
 
-namespace TouchAdjustment {
+namespace touch_adjustment {
 
 const float kZeroTolerance = 1e-6f;
 constexpr float kMaxAdjustmentSizeDips = 32.f;
@@ -65,16 +65,16 @@
   FloatQuad quad_;
 };
 
-}  // namespace TouchAdjustment
+}  // namespace touch_adjustment
 
 }  // namespace blink
 
 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
-    blink::TouchAdjustment::SubtargetGeometry)
+    blink::touch_adjustment::SubtargetGeometry)
 
 namespace blink {
 
-namespace TouchAdjustment {
+namespace touch_adjustment {
 
 typedef HeapVector<SubtargetGeometry> SubtargetGeometryList;
 typedef bool (*NodeFilter)(Node*);
@@ -481,7 +481,7 @@
   return (target_node);
 }
 
-}  // namespace TouchAdjustment
+}  // namespace touch_adjustment
 
 bool FindBestClickableCandidate(Node*& target_node,
                                 IntPoint& target_point,
@@ -489,13 +489,13 @@
                                 const IntRect& touch_area,
                                 const HeapVector<Member<Node>>& nodes) {
   IntRect target_area;
-  TouchAdjustment::SubtargetGeometryList subtargets;
-  TouchAdjustment::CompileSubtargetList(
-      nodes, subtargets, TouchAdjustment::NodeRespondsToTapGesture,
-      TouchAdjustment::AppendBasicSubtargetsForNode);
-  return TouchAdjustment::FindNodeWithLowestDistanceMetric(
+  touch_adjustment::SubtargetGeometryList subtargets;
+  touch_adjustment::CompileSubtargetList(
+      nodes, subtargets, touch_adjustment::NodeRespondsToTapGesture,
+      touch_adjustment::AppendBasicSubtargetsForNode);
+  return touch_adjustment::FindNodeWithLowestDistanceMetric(
       target_node, target_point, target_area, touch_hotspot, touch_area,
-      subtargets, TouchAdjustment::HybridDistanceFunction);
+      subtargets, touch_adjustment::HybridDistanceFunction);
 }
 
 bool FindBestContextMenuCandidate(Node*& target_node,
@@ -504,18 +504,18 @@
                                   const IntRect& touch_area,
                                   const HeapVector<Member<Node>>& nodes) {
   IntRect target_area;
-  TouchAdjustment::SubtargetGeometryList subtargets;
-  TouchAdjustment::CompileSubtargetList(
-      nodes, subtargets, TouchAdjustment::ProvidesContextMenuItems,
-      TouchAdjustment::AppendContextSubtargetsForNode);
-  return TouchAdjustment::FindNodeWithLowestDistanceMetric(
+  touch_adjustment::SubtargetGeometryList subtargets;
+  touch_adjustment::CompileSubtargetList(
+      nodes, subtargets, touch_adjustment::ProvidesContextMenuItems,
+      touch_adjustment::AppendContextSubtargetsForNode);
+  return touch_adjustment::FindNodeWithLowestDistanceMetric(
       target_node, target_point, target_area, touch_hotspot, touch_area,
-      subtargets, TouchAdjustment::HybridDistanceFunction);
+      subtargets, touch_adjustment::HybridDistanceFunction);
 }
 
 LayoutSize GetHitTestRectForAdjustment(const LayoutSize& touch_area) {
-  const LayoutSize max_size(TouchAdjustment::kMaxAdjustmentSizeDips,
-                            TouchAdjustment::kMaxAdjustmentSizeDips);
+  const LayoutSize max_size(touch_adjustment::kMaxAdjustmentSizeDips,
+                            touch_adjustment::kMaxAdjustmentSizeDips);
   return touch_area.ShrunkTo(max_size);
 }
 
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index c65e8e9..e05570ab 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -538,18 +538,6 @@
   DCHECK(layout_object.IsInline()) << layout_object;
   if (TryMarkLineBoxDirtyFor(layout_object))
     return;
-  if (layout_object.IsLayoutInline()) {
-    bool marked = false;
-    for (LayoutObject* runner = layout_object.NextInPreOrder(&layout_object);
-         runner; runner = runner->NextInPreOrder(&layout_object)) {
-      if (runner->IsFloatingOrOutOfFlowPositioned())
-        continue;
-      if (TryMarkLineBoxDirtyFor(*runner))
-        marked = true;
-    }
-    if (marked)
-      return;
-  }
   // Since |layout_object| isn't in fragment tree, check preceding siblings.
   // Note: Once we reuse lines below dirty lines, we should check next siblings.
   for (LayoutObject* previous = layout_object.PreviousSibling(); previous;
@@ -589,19 +577,14 @@
 
 bool NGPaintFragment::TryMarkLineBoxDirtyFor(
     const LayoutObject& layout_object) {
-  if (!layout_object.IsInLayoutNGInlineFormattingContext())
-    return false;
-  const auto& range = InlineFragmentsFor(&layout_object);
-  if (range.IsEmpty())
-    return false;
-  NGPaintFragment* last_parent = nullptr;
-  for (NGPaintFragment* fragment : range) {
-    if (last_parent == fragment->Parent())
-      continue;
-    fragment->MarkLineBoxDirty();
-    last_parent = fragment->Parent();
+  // Once we reuse lines below dirty lines, we should mark lines for all
+  // inline fragments.
+  NGPaintFragment* const first_fragment = layout_object.FirstInlineFragment();
+  if (first_fragment) {
+    first_fragment->MarkLineBoxDirty();
+    return true;
   }
-  return true;
+  return false;
 }
 
 void NGPaintFragment::SetShouldDoFullPaintInvalidationRecursively() {
diff --git a/third_party/blink/renderer/core/svg/svg_element.cc b/third_party/blink/renderer/core/svg/svg_element.cc
index 5549886..aab9d982 100644
--- a/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_element.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
 #include "third_party/blink/renderer/core/animation/svg_interpolation_environment.h"
 #include "third_party/blink/renderer/core/animation/svg_interpolation_types_map.h"
+#include "third_party/blink/renderer/core/css/css_property_id_templates.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.cc b/third_party/blink/renderer/core/svg/svg_image_element.cc
index 74bf3da..8c33efde 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_image_element.cc
@@ -223,7 +223,8 @@
   // A previous loader update may have failed to actually fetch the image if
   // the document was inactive. In that case, force a re-update (but don't
   // clear previous errors).
-  if (root_parent.isConnected() && !GetImageLoader().GetContent())
+  if (root_parent.isConnected() && !GetImageLoader().GetContent() &&
+      !GetImageLoader().HasPendingActivity())
     GetImageLoader().UpdateFromElement(ImageLoader::kUpdateNormal);
 
   return SVGGraphicsElement::InsertedInto(root_parent);
diff --git a/third_party/blink/renderer/core/svg/svg_path_parser.cc b/third_party/blink/renderer/core/svg/svg_path_parser.cc
index 4385c43..6d6cb4fb 100644
--- a/third_party/blink/renderer/core/svg/svg_path_parser.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_parser.cc
@@ -291,6 +291,10 @@
 
   if (absolute_segment.command == kPathSegClosePath) {
     current_point_ = sub_path_point_;
+  } else if (absolute_segment.command == kPathSegLineToHorizontalAbs) {
+    current_point_.SetX(absolute_segment.target_point.X());
+  } else if (absolute_segment.command == kPathSegLineToVerticalAbs) {
+    current_point_.SetY(absolute_segment.target_point.Y());
   } else {
     current_point_ = absolute_segment.target_point;
     if (absolute_segment.command == kPathSegMoveToAbs) {
diff --git a/third_party/blink/renderer/core/trustedtypes/OWNERS b/third_party/blink/renderer/core/trustedtypes/OWNERS
new file mode 100644
index 0000000..41f27872
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/OWNERS
@@ -0,0 +1,4 @@
+mkwst@chromium.org
+vogelheim@chromium.org
+
+# COMPONENT: Blink>SecurityFeature
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index f89532a9..0a123f9 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -1928,6 +1928,13 @@
   if (receiver_it == rtp_receivers_.end()) {
     // Create new receiver.
     receiver = new RTCRtpReceiver(std::move(web_receiver), track, {});
+    // Receiving tracks should be muted by default. SetReadyState() propagates
+    // the related state changes to ensure it is muted on all layers. It also
+    // fires events - which is not desired - but because they fire synchronously
+    // there are no listeners to detect this so this is indistinguishable from
+    // having constructed the track in an already muted state.
+    receiver->track()->Component()->Source()->SetReadyState(
+        MediaStreamSource::kReadyStateMuted);
     rtp_receivers_.push_back(receiver);
   } else {
     // Update existing receiver is a no-op.
@@ -2214,9 +2221,20 @@
   }
 
   for (auto& track : mute_tracks) {
+    // Mute the track. Fires "track.onmute" synchronously.
     track->Component()->Source()->SetReadyState(
         MediaStreamSource::kReadyStateMuted);
   }
+  // Remove/add tracks to streams, this fires "stream.onremovetrack" and
+  // "stream.onaddtrack" asynchronously (delayed with ScheduleDispatchEvent()).
+  // This means that the streams will be updated immediately, but the
+  // corresponding events will fire after "pc.ontrack".
+  // TODO(https://crbug.com/788558): These should probably also fire
+  // synchronously (before "pc.ontrack"). The webrtc-pc spec references the
+  // mediacapture-streams spec for adding and removing tracks to streams, which
+  // adds/removes and fires synchronously, but it says to do this in a queued
+  // task, which would lead to unexpected behavior: the streams would be empty
+  // at "pc.ontrack".
   for (auto& pair : remove_list) {
     auto& stream = pair.first;
     auto& track = pair.second;
@@ -2232,10 +2250,20 @@
     }
   }
 
+  // Fire "pc.ontrack" synchronously.
   for (auto& transceiver : track_events) {
-    ScheduleDispatchEvent(new RTCTrackEvent(
+    auto* track_event = new RTCTrackEvent(
         transceiver->receiver(), transceiver->receiver()->track(),
-        transceiver->receiver()->streams(), transceiver));
+        transceiver->receiver()->streams(), transceiver);
+    DispatchEvent(*track_event);
+  }
+
+  // Unmute "pc.ontrack" tracks. Fires "track.onunmute" synchronously.
+  // TODO(https://crbug.com/889487): The correct thing to do is to unmute in
+  // response to receiving RTP packets.
+  for (auto& transceiver : track_events) {
+    transceiver->receiver()->track()->Component()->Source()->SetReadyState(
+        MediaStreamSource::kReadyStateLive);
   }
 }
 
diff --git a/third_party/blink/tools/audit_non_blink_usage.py b/third_party/blink/tools/audit_non_blink_usage.py
index 21957b83..59c7a0dd 100755
--- a/third_party/blink/tools/audit_non_blink_usage.py
+++ b/third_party/blink/tools/audit_non_blink_usage.py
@@ -315,6 +315,12 @@
         ],
     },
     {
+        'paths': ['third_party/blink/renderer/core/page'],
+        'allowed': [
+            'touch_adjustment::.+',
+        ],
+    },
+    {
         'paths': ['third_party/blink/renderer/core/inspector/inspector_memory_agent.cc'],
         'allowed': [
             'base::ModuleCache',
diff --git a/third_party/blink/tools/blinkpy/common/path_finder.py b/third_party/blink/tools/blinkpy/common/path_finder.py
index 8e2a3b6..5fc1f4a 100644
--- a/third_party/blink/tools/blinkpy/common/path_finder.py
+++ b/third_party/blink/tools/blinkpy/common/path_finder.py
@@ -50,6 +50,12 @@
         sys.path.append(path)
 
 
+def add_depot_tools_dir_to_os_path():
+    path = get_depot_tools_dir()
+    if path not in os.environ['PATH']:
+        os.environ['PATH'] += os.pathsep + path
+
+
 def get_bindings_scripts_dir():
     return os.path.join(get_source_dir(), 'bindings', 'scripts')
 
@@ -62,6 +68,10 @@
     return os.path.dirname(os.path.dirname(get_blink_dir()))
 
 
+def get_depot_tools_dir():
+    return os.path.join(get_chromium_src_dir(), 'third_party', 'depot_tools')
+
+
 def get_source_dir():
     return os.path.join(get_chromium_src_dir(), 'third_party', 'blink', 'renderer')
 
diff --git a/third_party/blink/tools/wpt_export.py b/third_party/blink/tools/wpt_export.py
index 7694bff6..ebe8609 100755
--- a/third_party/blink/tools/wpt_export.py
+++ b/third_party/blink/tools/wpt_export.py
@@ -5,15 +5,14 @@
 
 """Pushes changes to web-platform-tests inside Chromium to the upstream repo."""
 
-import os
-import sys
-
 from blinkpy.common import exit_codes
 from blinkpy.common.host import Host
+from blinkpy.common.path_finder import add_depot_tools_dir_to_os_path
 from blinkpy.w3c.test_exporter import TestExporter
 
 
 def main():
+    add_depot_tools_dir_to_os_path()
     host = Host()
     exporter = TestExporter(host)
     try:
diff --git a/third_party/blink/tools/wpt_import.py b/third_party/blink/tools/wpt_import.py
index b80717c..be05072 100755
--- a/third_party/blink/tools/wpt_import.py
+++ b/third_party/blink/tools/wpt_import.py
@@ -5,15 +5,14 @@
 
 """Pulls the latest revisions of the web-platform-tests."""
 
-import os
-import sys
-
 from blinkpy.common import exit_codes
 from blinkpy.common.host import Host
+from blinkpy.common.path_finder import add_depot_tools_dir_to_os_path
 from blinkpy.w3c.test_importer import TestImporter
 
 
 def main():
+    add_depot_tools_dir_to_os_path()
     host = Host()
     importer = TestImporter(host)
     try:
diff --git a/third_party/zlib/zconf.h b/third_party/zlib/zconf.h
index a7a815f5..1843c0a 100644
--- a/third_party/zlib/zconf.h
+++ b/third_party/zlib/zconf.h
@@ -389,6 +389,9 @@
 #ifndef FAR
 #  define FAR
 #endif
+#ifndef far
+#  define far
+#endif
 
 #if !defined(__MACTYPES__)
 typedef unsigned char  Byte;  /* 8 bits */
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 355b042..86eaae3 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -12104,6 +12104,7 @@
   </int>
   <int value="6" label="Virtual Contact File">text/vcard MIME type.</int>
   <int value="7" label="iCalendar">text/calendar MIME type.</int>
+  <int value="8" label="Universal Scene Description">model/usd MIME type.</int>
 </enum>
 
 <enum name="DownloadNotificationForegroundLifecycle">
@@ -14590,6 +14591,7 @@
   <int value="482" label="DeviceUnaffiliatedCrostiniAllowed"/>
   <int value="483" label="EnterpriseHardwarePlatformAPIEnabled"/>
   <int value="484" label="ReportCrostiniUsageEnabled"/>
+  <int value="485" label="VpnConfigAllowed"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ffe858f..56d069a 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -39280,6 +39280,18 @@
   </summary>
 </histogram>
 
+<histogram name="IOS.RestoreNavigationItemTime" units="ms">
+  <owner>eugenebut@chromium.org</owner>
+  <summary>
+    [iOS] Time spent on restoring committed Navigation Manager's items. Recorded
+    once per restoration, as a cumulative time across all items. Restoration is
+    triggered in the following cases (the list is not exhaustive): app cold
+    start, remote tab was open, cookies were cleared, recently closed tab was
+    restored. This metric will be used for monitoring session restoration
+    performance which relies on system's WKWebView.
+  </summary>
+</histogram>
+
 <histogram name="IOS.SearchExtension.Action" enum="IOSSearchExtensionAction">
   <owner>olivierrobin@chromium.org</owner>
   <summary>The action selected by the user in the Search Extension.</summary>
@@ -42016,6 +42028,17 @@
   </summary>
 </histogram>
 
+<histogram name="Media.AudioOutputController.LifeTime" units="ms"
+    expires_after="2019-02-01">
+  <owner>olka@chromium.org</owner>
+  <owner>marinaciocea@chromium.org</owner>
+  <owner>maxmorin@chromium.org</owner>
+  <summary>
+    Time interval from the output stream controller construction to its
+    destruction.
+  </summary>
+</histogram>
+
 <histogram name="Media.AudioOutputController.ProxyStreamCreationResult"
     enum="AudioOutputStreamCreationResult">
   <owner>maxmorin@chromium.org</owner>
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc
index 7c7dbf9..d993a4b6 100644
--- a/ui/events/event_unittest.cc
+++ b/ui/events/event_unittest.cc
@@ -25,6 +25,7 @@
 
 #if defined(USE_X11)
 #include "ui/events/test/events_test_utils_x11.h"
+#include "ui/events/x/events_x_utils.h"  // nogncheck
 #include "ui/gfx/x/x11.h"        // nogncheck
 #include "ui/gfx/x/x11_types.h"  // nogncheck
 #endif
@@ -430,6 +431,15 @@
 #if defined(USE_X11)
 namespace {
 
+class MockTimestampServer : public ui::TimestampServer {
+ public:
+  Time GetCurrentServerTime() override { return base_time_; }
+  void SetBaseTime(Time time) { base_time_ = time; }
+
+ private:
+  Time base_time_ = 0;
+};
+
 void SetKeyEventTimestamp(XEvent* event, int64_t time) {
   event->xkey.time = time & UINT32_MAX;
 }
@@ -440,7 +450,29 @@
 
 }  // namespace
 
-TEST(EventTest, AutoRepeat) {
+class X11EventTest : public testing::Test {
+ public:
+  X11EventTest() {}
+  ~X11EventTest() override {}
+
+  void SetUp() override {
+    SetTimestampServer(&server_);
+    SetUseFixedTimeForXEventTesting(true);
+  }
+
+  void TearDown() override {
+    SetTimestampServer(nullptr);
+    SetUseFixedTimeForXEventTesting(false);
+  }
+
+ protected:
+  MockTimestampServer server_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(X11EventTest);
+};
+
+TEST_F(X11EventTest, AutoRepeat) {
   const uint16_t kNativeCodeA =
       ui::KeycodeConverter::DomCodeToNativeKeycode(DomCode::US_A);
   const uint16_t kNativeCodeB =
@@ -468,6 +500,7 @@
 
   int64_t ticks_base =
       (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds() - 5000;
+  server_.SetBaseTime(static_cast<Time>(ticks_base));
   SetKeyEventTimestamp(native_event_a_pressed, ticks_base);
   SetKeyEventTimestamp(native_event_a_pressed_1500, ticks_base + 1500);
   SetKeyEventTimestamp(native_event_a_pressed_3000, ticks_base + 3000);
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
index 7e9f6df..a68188d 100644
--- a/ui/events/platform/x11/x11_event_source.cc
+++ b/ui/events/platform/x11/x11_event_source.cc
@@ -100,6 +100,7 @@
       distribution_(0, 999) {
   DCHECK(!instance_);
   instance_ = this;
+  SetTimestampServer(this);
 
   DCHECK(delegate_);
   DCHECK(display_);
@@ -110,6 +111,7 @@
 X11EventSource::~X11EventSource() {
   DCHECK_EQ(this, instance_);
   instance_ = nullptr;
+  SetTimestampServer(nullptr);
   if (dummy_initialized_)
     XDestroyWindow(display_, dummy_window_);
 }
diff --git a/ui/events/platform/x11/x11_event_source.h b/ui/events/platform/x11/x11_event_source.h
index e818c4ac..c2ee795 100644
--- a/ui/events/platform/x11/x11_event_source.h
+++ b/ui/events/platform/x11/x11_event_source.h
@@ -14,6 +14,7 @@
 #include "base/optional.h"
 #include "build/build_config.h"
 #include "ui/events/events_export.h"
+#include "ui/events/x/events_x_utils.h"
 #include "ui/gfx/x/x11_types.h"
 
 using Time = unsigned long;
@@ -46,7 +47,7 @@
 
 // Receives X11 events and sends them to X11EventSourceDelegate. Handles
 // receiving, pre-process and post-processing XEvents.
-class EVENTS_EXPORT X11EventSource {
+class EVENTS_EXPORT X11EventSource : TimestampServer {
  public:
   X11EventSource(X11EventSourceDelegate* delegate, XDisplay* display);
   ~X11EventSource();
@@ -82,7 +83,7 @@
 
   // Explicitly asks the X11 server for the current timestamp, and updates
   // |last_seen_server_time_| with this value.
-  Time GetCurrentServerTime();
+  Time GetCurrentServerTime() override;
 
  protected:
   // Extracts cookie data from |xevent| if it's of GenericType, and dispatches
diff --git a/ui/events/x/events_x.cc b/ui/events/x/events_x.cc
index b8df7b0..6253031 100644
--- a/ui/events/x/events_x.cc
+++ b/ui/events/x/events_x.cc
@@ -81,9 +81,7 @@
 }
 
 base::TimeTicks EventTimeFromNative(const PlatformEvent& native_event) {
-  base::TimeTicks timestamp = EventTimeFromXEvent(*native_event);
-  ValidateEventTimeClock(&timestamp);
-  return timestamp;
+  return EventTimeFromXEvent(*native_event);
 }
 
 gfx::PointF EventLocationFromNative(const PlatformEvent& native_event) {
diff --git a/ui/events/x/events_x_unittest.cc b/ui/events/x/events_x_unittest.cc
index 897c5c5..3419309 100644
--- a/ui/events/x/events_x_unittest.cc
+++ b/ui/events/x/events_x_unittest.cc
@@ -76,6 +76,15 @@
   return rotation_angle;
 }
 
+class MockTimestampServer : public ui::TimestampServer {
+ public:
+  Time GetCurrentServerTime() override { return base_time_; }
+  void SetBaseTime(Time time) { base_time_ = time; }
+
+ private:
+  Time base_time_ = 0;
+};
+
 }  // namespace
 
 class EventsXTest : public testing::Test {
@@ -84,13 +93,15 @@
   ~EventsXTest() override {}
 
   void SetUp() override {
+    SetTimestampServer(&server_);
     DeviceDataManagerX11::CreateInstance();
     ui::TouchFactory::GetInstance()->ResetForTest();
-    ResetTimestampRolloverCountersForTesting();
   }
-  void TearDown() override { ResetTimestampRolloverCountersForTesting(); }
+
+  void TearDown() override { SetTimestampServer(nullptr); }
 
  private:
+  MockTimestampServer server_;
   DISALLOW_COPY_AND_ASSIGN(EventsXTest);
 };
 
@@ -542,52 +553,4 @@
   EXPECT_EQ(ui::ET_UNKNOWN, ui::EventTypeFromNative(xev));
 }
 
-namespace {
-
-// Returns a fake TimeTicks based on the given millisecond offset.
-base::TimeTicks TimeTicksFromMillis(int64_t millis) {
-  return base::TimeTicks() + base::TimeDelta::FromMilliseconds(millis);
-}
-
-}  // namespace
-
-TEST_F(EventsXTest, TimestampRolloverAndAdjustWhenDecreasing) {
-  XEvent event;
-  InitButtonEvent(&event, true, gfx::Point(5, 10), 1, 0);
-
-  test::ScopedEventTestTickClock clock;
-  clock.SetNowTicks(TimeTicksFromMillis(0x100000001));
-  ResetTimestampRolloverCountersForTesting();
-
-  event.xbutton.time = 0xFFFFFFFF;
-  EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromNative(&event));
-
-  clock.SetNowTicks(TimeTicksFromMillis(0x100000007));
-  ResetTimestampRolloverCountersForTesting();
-
-  event.xbutton.time = 3;
-  EXPECT_EQ(TimeTicksFromMillis(0x100000000 + 3),
-            ui::EventTimeFromNative(&event));
-}
-
-TEST_F(EventsXTest, NoTimestampRolloverWhenMonotonicIncreasing) {
-  XEvent event;
-  InitButtonEvent(&event, true, gfx::Point(5, 10), 1, 0);
-
-  test::ScopedEventTestTickClock clock;
-  clock.SetNowTicks(TimeTicksFromMillis(10));
-  ResetTimestampRolloverCountersForTesting();
-
-  event.xbutton.time = 6;
-  EXPECT_EQ(TimeTicksFromMillis(6), ui::EventTimeFromNative(&event));
-  event.xbutton.time = 7;
-  EXPECT_EQ(TimeTicksFromMillis(7), ui::EventTimeFromNative(&event));
-
-  clock.SetNowTicks(TimeTicksFromMillis(0x100000005));
-  ResetTimestampRolloverCountersForTesting();
-
-  event.xbutton.time = 0xFFFFFFFF;
-  EXPECT_EQ(TimeTicksFromMillis(0xFFFFFFFF), ui::EventTimeFromNative(&event));
-}
-
 }  // namespace ui
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc
index 86fbd19..8dec888 100644
--- a/ui/events/x/events_x_utils.cc
+++ b/ui/events/x/events_x_utils.cc
@@ -27,6 +27,25 @@
 
 namespace {
 
+ui::TimestampServer* g_timestamp_server = nullptr;
+bool g_use_fixed_time_for_testing = false;
+
+// Clamps a TimeDelta to be within [-30 seconds, 30 seconds].
+base::TimeDelta ClampDeltaFromExternalSource(const base::TimeDelta& delta) {
+  // Ignore pathologically long deltas. External source is probably having
+  // issues.
+  constexpr base::TimeDelta pathologically_long_duration =
+      base::TimeDelta::FromSeconds(30);
+  if (delta > pathologically_long_duration)
+    return base::TimeDelta();
+
+  // Ignore negative deltas. External source is probably having issues.
+  if (delta < -pathologically_long_duration)
+    return base::TimeDelta();
+
+  return delta;
+}
+
 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
 const int kWheelScrollAmount = 53;
 
@@ -308,40 +327,36 @@
   return true;
 }
 
-int64_t g_last_seen_timestamp_ms = 0;
-int64_t g_rollover_ms = 0;
-
-// Takes Xlib Time and returns a time delta that is immune to timer rollover.
-// This function is not thread safe as we do not use a lock.
 base::TimeTicks TimeTicksFromXEventTime(Time timestamp) {
-  int64_t timestamp64 = timestamp;
+  // There's no way to convert from an X time to a base::TimeTicks without
+  // knowing the current X server time.
+  if (!g_timestamp_server)
+    return base::TimeTicks();
 
-  if (!timestamp)
-    return ui::EventTimeForNow();
+  // X11 uses a uint32_t on the wire protocol. Xlib casts this to an unsigned
+  // long by prepending with 0s. We cast back to a uint32_t so that subtraction
+  // works properly when the timestamp overflows back to 0.
+  uint32_t event_server_time_ms = static_cast<uint32_t>(timestamp);
+  uint32_t current_server_time_ms =
+      static_cast<uint32_t>(g_timestamp_server->GetCurrentServerTime());
 
-  // If this is the first event that we get, assume the time stamp roll-over
-  // might have happened before the process was started.
-  // Register a rollover if the distance between last timestamp and current one
-  // is larger than half the width. This avoids false rollovers even in a case
-  // where X server delivers reasonably close events out-of-order.
-  bool had_recent_rollover =
-      !g_last_seen_timestamp_ms ||
-      g_last_seen_timestamp_ms - timestamp64 > (UINT32_MAX >> 1);
+  // On X11, event times are in X11 Server time. To convert to base::TimeTicks,
+  // we perform a round-trip to the X11 Server, subtract the two times to get a
+  // TimeDelta, and then subtract that from base::TimeTicks::Now(). Since we're
+  // working with units of time from an external source, we clamp the TimeDelta
+  // to reasonable values.
+  int64_t delta_ms = static_cast<int64_t>(current_server_time_ms) -
+                     static_cast<int64_t>(event_server_time_ms);
+  base::TimeDelta delta = base::TimeDelta::FromMilliseconds(delta_ms);
+  base::TimeDelta sanitized = ClampDeltaFromExternalSource(delta);
 
-  g_last_seen_timestamp_ms = timestamp64;
-  if (!had_recent_rollover)
-    return base::TimeTicks() +
-        base::TimeDelta::FromMilliseconds(g_rollover_ms + timestamp);
+  base::TimeTicks now;
+  if (g_use_fixed_time_for_testing)
+    now = base::TimeTicks() + base::TimeDelta::FromDays(1);
+  else
+    now = base::TimeTicks::Now();
 
-  DCHECK(timestamp64 <= UINT32_MAX)
-      << "X11 Time does not roll over 32 bit, the below logic is likely wrong";
-
-  base::TimeTicks now_ticks = ui::EventTimeForNow();
-  int64_t now_ms = (now_ticks - base::TimeTicks()).InMilliseconds();
-
-  g_rollover_ms = now_ms & ~static_cast<int64_t>(UINT32_MAX);
-  uint32_t delta = static_cast<uint32_t>(now_ms - timestamp);
-  return base::TimeTicks() + base::TimeDelta::FromMilliseconds(now_ms - delta);
+  return now - sanitized;
 }
 
 }  // namespace
@@ -831,9 +846,16 @@
   return XModifierStateWatcher::GetInstance()->state() & Mod1Mask;
 }
 
-void ResetTimestampRolloverCountersForTesting() {
-  g_last_seen_timestamp_ms = 0;
-  g_rollover_ms = 0;
+void SetTimestampServer(TimestampServer* server) {
+  // This method must be setting or unsetting a timestamp server. It should
+  // never replace an existing timestamp server, nor change from
+  // nullptr->nullptr.
+  CHECK(!!g_timestamp_server ^ !!server);
+  g_timestamp_server = server;
+}
+
+void SetUseFixedTimeForXEventTesting(bool use_fixed_time) {
+  g_use_fixed_time_for_testing = use_fixed_time;
 }
 
 }  // namespace ui
diff --git a/ui/events/x/events_x_utils.h b/ui/events/x/events_x_utils.h
index 64814e87..ad11a08 100644
--- a/ui/events/x/events_x_utils.h
+++ b/ui/events/x/events_x_utils.h
@@ -16,6 +16,8 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/x/x11_types.h"
 
+using Time = unsigned long;
+
 namespace ui {
 
 // Gets the EventType from a XEvent.
@@ -91,6 +93,18 @@
 
 EVENTS_X_EXPORT void ResetTimestampRolloverCountersForTesting();
 
+// Conversion from X Time to base::TimeTicks requires checking the current X
+// Server Time. This functionality is provided by X11EventSource, but due to odd
+// layering that cannot be referenced directly.
+class TimestampServer {
+ public:
+  virtual Time GetCurrentServerTime() = 0;
+};
+EVENTS_X_EXPORT void SetTimestampServer(TimestampServer* server);
+
+// Allows tests to force a fixed time..
+EVENTS_X_EXPORT void SetUseFixedTimeForXEventTesting(bool use_fixed_time);
+
 }  // namespace ui
 
 #endif  // UI_EVENTS_X_EVENTS_X_UTILS_H_
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 02bc6279..10bfb43 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -35,6 +35,7 @@
   public_deps = [
     ":gfx_export",
   ]
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
   deps = [
     "//base",
     "//gpu/vulkan:buildflags",
@@ -231,6 +232,7 @@
 
     # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
     "//build/config/compiler:no_size_t_to_int_warning",
+    "//build/config/compiler:wexit_time_destructors",
   ]
 
   # This is part of the gfx component in the component build.
@@ -404,20 +406,6 @@
   defines = [ "COLOR_SPACE_IMPLEMENTATION" ]
 }
 
-# Depend on this to use half_float.h without pulling in all of gfx.
-source_set("half_float") {
-  sources = [
-    "half_float.h",
-  ]
-
-  defines = [ "GFX_IMPLEMENTATION" ]
-
-  public_deps = [
-    ":gfx_export",
-    "//base",
-  ]
-}
-
 # Depend on this to use native_widget_types.h without pulling in all of gfx.
 source_set("native_widget_types") {
   public = [
@@ -452,6 +440,8 @@
     "selection_bound.h",
   ]
 
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+
   defines = [ "GFX_IMPLEMENTATION" ]
 
   public_deps = [
@@ -519,6 +509,8 @@
     ]
   }
 
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+
   defines = [ "GFX_IMPLEMENTATION" ]
 
   public_deps = [
diff --git a/ui/gfx/harfbuzz_font_skia.cc b/ui/gfx/harfbuzz_font_skia.cc
index cad4334..fe88148 100644
--- a/ui/gfx/harfbuzz_font_skia.cc
+++ b/ui/gfx/harfbuzz_font_skia.cc
@@ -13,6 +13,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "ui/gfx/render_text.h"
@@ -285,10 +286,11 @@
                               SkScalar text_size,
                               const FontRenderParams& params,
                               bool subpixel_rendering_suppressed) {
-  // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache?
-  static std::map<SkFontID, FaceCache> face_caches;
+  // TODO(https://crbug.com/890298): This shouldn't grow indefinitely.
+  // Maybe use base::MRUCache?
+  static base::NoDestructor<std::map<SkFontID, FaceCache>> face_caches;
 
-  FaceCache* face_cache = &face_caches[skia_face->uniqueID()];
+  FaceCache* face_cache = &(*face_caches)[skia_face->uniqueID()];
   if (face_cache->first.get() == NULL)
     face_cache->first.Init(skia_face.get());
 
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.cc b/ui/gfx/mojo/buffer_types_struct_traits.cc
index 534c7f9..bfe71c551 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.cc
+++ b/ui/gfx/mojo/buffer_types_struct_traits.cc
@@ -13,6 +13,10 @@
 #include "mojo/public/cpp/system/scope_to_message_pipe.h"
 #endif
 
+#if !defined(OS_LINUX)
+#include "base/no_destructor.h"
+#endif
+
 namespace mojo {
 
 // static
@@ -74,8 +78,8 @@
 #if defined(OS_LINUX)
   return handle.native_pixmap_handle;
 #else
-  static gfx::NativePixmapHandle pixmap_handle;
-  return pixmap_handle;
+  static base::NoDestructor<gfx::NativePixmapHandle> pixmap_handle;
+  return *pixmap_handle;
 #endif
 }
 
diff --git a/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
index d64b366..110dc9f 100644
--- a/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
+++ b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
@@ -25,12 +25,6 @@
                                 gfx::BufferUsage usage) const override {
     OzonePlatform::PlatformProperties properties =
         OzonePlatform::GetInstance()->GetPlatformProperties();
-    if (properties.supported_buffer_formats.empty()) {
-      // If the compositor did not announce supported buffer formats, do our
-      // best and assume those are supported.
-      return dmabuf_factory_->IsConfigurationSupported(format, usage);
-    }
-
     for (auto buffer_format : properties.supported_buffer_formats) {
       if (buffer_format == format)
         return dmabuf_factory_->IsConfigurationSupported(format, usage);
diff --git a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
index 2e2e352..ce339c39 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_surfaceless_wayland.cc
@@ -59,8 +59,6 @@
 }
 
 bool GbmSurfacelessWayland::SupportsPresentationCallback() {
-  // TODO(msisov): enable a real presentation callback for wayland. For now, we
-  // just blindly say it was successful. https://crbug.com/859012.
   return true;
 }