diff --git a/DEPS b/DEPS
index baabe7b..f2811e5 100644
--- a/DEPS
+++ b/DEPS
@@ -96,11 +96,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': '694ebb348a4487840dcd5a84eb587a7706d50775',
+  'skia_revision': '95e2b91d76d60ae69588ca700211146aabddbe5a',
   # 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': '2839e6855ad88a09f6a8a6a1eeaad98876ac6aa1',
+  'v8_revision': '0cb7b82ecaab1aeb72ec695c0aaaeda26d3513b4',
   # 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.
@@ -156,7 +156,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': '39e3bc6ed30a6c1a1b99c8e82e2956f189b743c4',
+  'catapult_revision': '3059fd7dba63773c249938b1b934b9c10143d684',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -269,7 +269,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '5ee7e2e3a845c5ca7e3d8a5a0d2ab4faddb52da5',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'dc1eae3b21358b4761a09e7c586bc69f3695eb6e',
       'condition': 'checkout_ios',
   },
 
@@ -498,7 +498,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'abd74feb3dc42cfbb69fa139a5616470aa6f9bad',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '5c50bf92e6fb07f43093db44cc230ca8765d216b',
       'condition': 'checkout_linux',
   },
 
@@ -523,7 +523,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '142a92ce8b834a412c16c0451ed8d434ea323e58',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5e5f2d60353bb93898302458f37ae667d60c7b8e',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -860,7 +860,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '66d57768881fc6474a43b1b3903b9ecfbdcebf03',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'a6f6a3133cf76a54b2d9fa6c40605e6919c93d66',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index cde1f9b2..d1da1f06 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -92,8 +92,6 @@
     "app_list/app_list_presenter_impl.h",
     "app_list/app_list_view_delegate_mash.cc",
     "app_list/app_list_view_delegate_mash.h",
-    "ash_constants.cc",
-    "ash_constants.h",
     "ash_export.h",
     "ash_layout_constants.cc",
     "ash_layout_constants.h",
diff --git a/ash/accessibility/accessibility_controller.h b/ash/accessibility/accessibility_controller.h
index c49d1edd..1a9edb7 100644
--- a/ash/accessibility/accessibility_controller.h
+++ b/ash/accessibility/accessibility_controller.h
@@ -7,8 +7,8 @@
 
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/ash_export.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/interfaces/accessibility_controller.mojom.h"
 #include "ash/session/session_observer.h"
 #include "base/macros.h"
diff --git a/ash/accessibility/accessibility_controller_unittest.cc b/ash/accessibility/accessibility_controller_unittest.cc
index 5888d25..e29d7955 100644
--- a/ash/accessibility/accessibility_controller_unittest.cc
+++ b/ash/accessibility/accessibility_controller_unittest.cc
@@ -8,8 +8,8 @@
 
 #include "ash/accessibility/accessibility_observer.h"
 #include "ash/accessibility/test_accessibility_controller_client.h"
-#include "ash/ash_constants.h"
 #include "ash/magnifier/docked_magnifier_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/config.h"
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 6d8f66a..baa606e 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -181,12 +181,17 @@
 void AppListControllerImpl::SetItemMetadata(const std::string& id,
                                             AppListItemMetadataPtr data) {
   app_list::AppListItem* item = model_.FindItem(id);
-  if (item) {
-    // data may not contain valid position. Preserve it in this case.
-    if (!data->position.IsValid())
-      data->position = item->position();
-    item->SetMetadata(std::move(data));
-  }
+  if (!item)
+    return;
+
+  // data may not contain valid position or icon. Preserve it in this case.
+  if (!data->position.IsValid())
+    data->position = item->position();
+  // Folder icon is generated on ash side and chrome side passes a null
+  // icon here. Skip it.
+  if (data->icon.isNull())
+    data->icon = item->icon();
+  item->SetMetadata(std::move(data));
 }
 
 void AppListControllerImpl::SetItemIcon(const std::string& id,
diff --git a/ash/ash_constants.cc b/ash/ash_constants.cc
deleted file mode 100644
index 07ca148..0000000
--- a/ash/ash_constants.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/ash_constants.h"
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/color_palette.h"
-
-namespace ash {
-
-const int kResizeAreaCornerSize = 16;
-const int kResizeOutsideBoundsSize = 6;
-const int kResizeOutsideBoundsScaleForTouch = 5;
-const int kResizeInsideBoundsSize = 1;
-
-const SkColor kChromeOsBootColor = SkColorSetRGB(0xfe, 0xfe, 0xfe);
-
-const int kDefaultLargeCursorSize = 64;
-
-}  // namespace ash
diff --git a/ash/assistant/ash_assistant_controller.cc b/ash/assistant/ash_assistant_controller.cc
index 53304117..005aaf5 100644
--- a/ash/assistant/ash_assistant_controller.cc
+++ b/ash/assistant/ash_assistant_controller.cc
@@ -124,8 +124,13 @@
 
 void AshAssistantController::OnInteractionStateChanged(
     InteractionState interaction_state) {
-  if (interaction_state == InteractionState::kInactive)
+  if (interaction_state == InteractionState::kInactive) {
     assistant_interaction_model_.ClearInteraction();
+
+    // TODO(dmblack): Input modality should default back to the user's
+    // preferred input modality.
+    assistant_interaction_model_.SetInputModality(InputModality::kVoice);
+  }
 }
 
 void AshAssistantController::OnInteractionStarted() {
@@ -147,8 +152,18 @@
 
 void AshAssistantController::OnDialogPlateContentsChanged(
     const std::string& text) {
-  // TODO(dmblack): Close the mic if necessary.
   assistant_bubble_timer_.Stop();
+
+  if (text.empty()) {
+    // Note: This does not open the mic. It only updates the input modality to
+    // voice so that we will show the mic icon in the UI.
+    assistant_interaction_model_.SetInputModality(InputModality::kVoice);
+  } else {
+    // TODO(dmblack): Instruct the underlying service to stop any in flight
+    // voice interaction.
+    assistant_interaction_model_.SetInputModality(InputModality::kKeyboard);
+    assistant_interaction_model_.SetMicState(MicState::kClosed);
+  }
 }
 
 void AshAssistantController::OnDialogPlateContentsCommitted(
@@ -159,6 +174,10 @@
   assistant_interaction_model_.ClearInteraction();
   assistant_interaction_model_.SetQuery(query);
 
+  // Note: This does not open the mic. It only updates the input modality to
+  // voice so that we will show the mic icon in the UI.
+  assistant_interaction_model_.SetInputModality(InputModality::kVoice);
+
   DCHECK(assistant_);
   assistant_->SendTextQuery(text);
 }
@@ -191,6 +210,8 @@
 
 void AshAssistantController::OnSpeechRecognitionStarted() {
   assistant_interaction_model_.ClearInteraction();
+  assistant_interaction_model_.SetInputModality(InputModality::kVoice);
+  assistant_interaction_model_.SetMicState(MicState::kOpen);
 }
 
 void AshAssistantController::OnSpeechRecognitionIntermediateResult(
@@ -201,8 +222,7 @@
 }
 
 void AshAssistantController::OnSpeechRecognitionEndOfUtterance() {
-  // TODO(dmblack): Handle.
-  NOTIMPLEMENTED();
+  assistant_interaction_model_.SetMicState(MicState::kClosed);
 }
 
 void AshAssistantController::OnSpeechRecognitionFinalResult(
diff --git a/ash/assistant/ash_assistant_controller.h b/ash/assistant/ash_assistant_controller.h
index 4d1d4e4..6e6f5c1 100644
--- a/ash/assistant/ash_assistant_controller.h
+++ b/ash/assistant/ash_assistant_controller.h
@@ -38,7 +38,7 @@
   void BindRequest(mojom::AshAssistantControllerRequest request);
 
   // Returns a reference to the underlying interaction model.
-  const AssistantInteractionModel* GetInteractionModel() const {
+  const AssistantInteractionModel* interaction_model() const {
     return &assistant_interaction_model_;
   }
 
diff --git a/ash/assistant/model/assistant_interaction_model.cc b/ash/assistant/model/assistant_interaction_model.cc
index 901c30c..57a9460 100644
--- a/ash/assistant/model/assistant_interaction_model.cc
+++ b/ash/assistant/model/assistant_interaction_model.cc
@@ -49,6 +49,14 @@
   NotifyInputModalityChanged();
 }
 
+void AssistantInteractionModel::SetMicState(MicState mic_state) {
+  if (mic_state == mic_state_)
+    return;
+
+  mic_state_ = mic_state;
+  NotifyMicStateChanged();
+}
+
 void AssistantInteractionModel::AddUiElement(
     std::unique_ptr<AssistantUiElement> ui_element) {
   AssistantUiElement* ptr = ui_element.get();
@@ -89,9 +97,13 @@
 }
 
 void AssistantInteractionModel::NotifyInputModalityChanged() {
-  for (AssistantInteractionModelObserver& observer : observers_) {
+  for (AssistantInteractionModelObserver& observer : observers_)
     observer.OnInputModalityChanged(input_modality_);
-  }
+}
+
+void AssistantInteractionModel::NotifyMicStateChanged() {
+  for (AssistantInteractionModelObserver& observer : observers_)
+    observer.OnMicStateChanged(mic_state_);
 }
 
 void AssistantInteractionModel::NotifyUiElementAdded(
diff --git a/ash/assistant/model/assistant_interaction_model.h b/ash/assistant/model/assistant_interaction_model.h
index a8c3c88d..87fbab16 100644
--- a/ash/assistant/model/assistant_interaction_model.h
+++ b/ash/assistant/model/assistant_interaction_model.h
@@ -33,6 +33,12 @@
   kInactive,
 };
 
+// Enumeration of interaction mic states.
+enum class MicState {
+  kClosed,
+  kOpen,
+};
+
 // TODO(dmblack): It is awkward to use this struct for both text and voice
 // queries. Break this out into a class and subclass TextQuery and VoiceQuery
 // respectively.
@@ -66,21 +72,27 @@
   void AddObserver(AssistantInteractionModelObserver* observer);
   void RemoveObserver(AssistantInteractionModelObserver* observer);
 
+  // Resets the interaction to its initial state.
+  void ClearInteraction();
+
   // Sets the interaction state.
   void SetInteractionState(InteractionState interaction_state);
 
   // Returns the interaction state.
   InteractionState interaction_state() const { return interaction_state_; }
 
-  // Resets the interaction to its initial state.
-  void ClearInteraction();
-
   // Updates the input modality for the interaction.
   void SetInputModality(InputModality input_modality);
 
   // Returns the input modality for the interaction.
   InputModality input_modality() const { return input_modality_; }
 
+  // Updates the mic state for the interaction.
+  void SetMicState(MicState mic_state);
+
+  // Returns the mic state for the interaction.
+  MicState mic_state() const { return mic_state_; }
+
   // Adds the specified |ui_element| that should be rendered for the
   // interaction.
   void AddUiElement(std::unique_ptr<AssistantUiElement> ui_element);
@@ -107,6 +119,7 @@
  private:
   void NotifyInteractionStateChanged();
   void NotifyInputModalityChanged();
+  void NotifyMicStateChanged();
   void NotifyUiElementAdded(const AssistantUiElement* ui_element);
   void NotifyUiElementsCleared();
   void NotifyQueryChanged();
@@ -116,6 +129,7 @@
 
   InteractionState interaction_state_ = InteractionState::kInactive;
   InputModality input_modality_;
+  MicState mic_state_ = MicState::kClosed;
   Query query_;
   std::vector<std::string> suggestions_list_;
   std::vector<std::unique_ptr<AssistantUiElement>> ui_element_list_;
diff --git a/ash/assistant/model/assistant_interaction_model_observer.h b/ash/assistant/model/assistant_interaction_model_observer.h
index feaf226..d0dffa1 100644
--- a/ash/assistant/model/assistant_interaction_model_observer.h
+++ b/ash/assistant/model/assistant_interaction_model_observer.h
@@ -15,6 +15,7 @@
 class AssistantUiElement;
 enum class InputModality;
 enum class InteractionState;
+enum class MicState;
 struct Query;
 
 // An observer which receives notification of changes to an Assistant
@@ -27,6 +28,9 @@
   // Invoked when the input modality associated with the interaction is changed.
   virtual void OnInputModalityChanged(InputModality input_modality) {}
 
+  // Invoked when the mic state associated with the interaction is changed.
+  virtual void OnMicStateChanged(MicState mic_state) {}
+
   // Invoked when a UI element associated with the interaction is added.
   virtual void OnUiElementAdded(const AssistantUiElement* ui_element) {}
 
diff --git a/ash/assistant/ui/assistant_bubble_view.cc b/ash/assistant/ui/assistant_bubble_view.cc
index bab7564..7c2fa3a 100644
--- a/ash/assistant/ui/assistant_bubble_view.cc
+++ b/ash/assistant/ui/assistant_bubble_view.cc
@@ -356,8 +356,8 @@
 AssistantBubbleView::AssistantBubbleView(
     AshAssistantController* assistant_controller)
     : assistant_controller_(assistant_controller),
-      interaction_container_(new InteractionContainer(
-          assistant_controller->GetInteractionModel())),
+      interaction_container_(
+          new InteractionContainer(assistant_controller->interaction_model())),
       ui_element_container_(new UiElementContainer()),
       suggestions_container_(new SuggestionsContainer(this)),
       render_request_weak_factory_(this) {
@@ -431,7 +431,7 @@
 void AssistantBubbleView::OnInputModalityChanged(InputModality input_modality) {
   // If the query for the interaction is empty, we may need to update the prompt
   // to reflect the current input modality.
-  if (assistant_controller_->GetInteractionModel()->query().empty()) {
+  if (assistant_controller_->interaction_model()->query().empty()) {
     interaction_container_->ClearQuery();
   }
 }
diff --git a/ash/assistant/ui/dialog_plate.cc b/ash/assistant/ui/dialog_plate.cc
index ff5015e..177636d0 100644
--- a/ash/assistant/ui/dialog_plate.cc
+++ b/ash/assistant/ui/dialog_plate.cc
@@ -29,9 +29,11 @@
 constexpr SkColor kTextColorHint = SkColorSetA(SK_ColorBLACK, 0x42);
 constexpr SkColor kTextColorPrimary = SkColorSetA(SK_ColorBLACK, 0xDE);
 
-// TODO(dmblack): Remove after removing placeholders.
-// Placeholder.
-constexpr SkColor kPlaceholderColor = SkColorSetA(SK_ColorBLACK, 0x1F);
+// TODO(dmblack): Remove after implementing stateful icon.
+// Background colors to represent icon states.
+constexpr SkColor kKeyboardColor = SkColorSetRGB(0x4C, 0x8B, 0xF5);    // Blue
+constexpr SkColor kMicOpenColor = SkColorSetRGB(0xDD, 0x51, 0x44);     // Red
+constexpr SkColor kMicClosedColor = SkColorSetA(SK_ColorBLACK, 0x1F);  // Grey
 
 // TODO(b/77638210): Replace with localized resource strings.
 constexpr char kHint[] = "Type a message";
@@ -66,11 +68,17 @@
 // DialogPlate -----------------------------------------------------------------
 
 DialogPlate::DialogPlate(AshAssistantController* assistant_controller)
-    : assistant_controller_(assistant_controller) {
+    : assistant_controller_(assistant_controller), icon_(new views::View()) {
   InitLayout();
+
+  // The Assistant controller indirectly owns the view hierarchy to which
+  // DialogPlate belongs, so is guaranteed to outlive it.
+  assistant_controller_->AddInteractionModelObserver(this);
 }
 
-DialogPlate::~DialogPlate() = default;
+DialogPlate::~DialogPlate() {
+  assistant_controller_->RemoveInteractionModelObserver(this);
+}
 
 void DialogPlate::InitLayout() {
   SetBackground(views::CreateSolidBackground(kBackgroundColor));
@@ -99,12 +107,27 @@
   layout->SetFlexForView(textfield, 1);
 
   // TODO(dmblack): Replace w/ stateful icon.
-  // Icon placeholder.
-  views::View* icon_placeholder = new views::View();
-  icon_placeholder->SetBackground(std::make_unique<RoundRectBackground>(
-      kPlaceholderColor, kIconSizeDip / 2));
-  icon_placeholder->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
-  AddChildView(icon_placeholder);
+  // Icon.
+  icon_->SetPreferredSize(gfx::Size(kIconSizeDip, kIconSizeDip));
+  AddChildView(icon_);
+
+  // TODO(dmblack): Remove once the icon has been replaced. Only needed to
+  // force the background for the initial state.
+  UpdateIcon();
+}
+
+void DialogPlate::OnInputModalityChanged(InputModality input_modality) {
+  // TODO(dmblack): When the stylus is selected we will hide the dialog plate
+  // and so should suspend any ongoing animations once the stateful icon is
+  // implemented.
+  if (input_modality == InputModality::kStylus)
+    return;
+
+  UpdateIcon();
+}
+
+void DialogPlate::OnMicStateChanged(MicState mic_state) {
+  UpdateIcon();
 }
 
 void DialogPlate::ContentsChanged(views::Textfield* textfield,
@@ -135,4 +158,32 @@
   return true;
 }
 
+// TODO(dmblack): Revise this method to update the state of the stateful icon
+// once it has been implemented. For the time being, we represent state by
+// modifying the background color of the placeholder icon.
+void DialogPlate::UpdateIcon() {
+  const AssistantInteractionModel* interaction_model =
+      assistant_controller_->interaction_model();
+
+  if (interaction_model->input_modality() == InputModality::kKeyboard) {
+    icon_->SetBackground(std::make_unique<RoundRectBackground>(
+        kKeyboardColor, kIconSizeDip / 2));
+    SchedulePaint();
+    return;
+  }
+
+  switch (interaction_model->mic_state()) {
+    case MicState::kClosed:
+      icon_->SetBackground(std::make_unique<RoundRectBackground>(
+          kMicClosedColor, kIconSizeDip / 2));
+      break;
+    case MicState::kOpen:
+      icon_->SetBackground(std::make_unique<RoundRectBackground>(
+          kMicOpenColor, kIconSizeDip / 2));
+      break;
+  }
+
+  SchedulePaint();
+}
+
 }  // namespace ash
diff --git a/ash/assistant/ui/dialog_plate.h b/ash/assistant/ui/dialog_plate.h
index 9850a6b2..b550a54 100644
--- a/ash/assistant/ui/dialog_plate.h
+++ b/ash/assistant/ui/dialog_plate.h
@@ -5,6 +5,7 @@
 #ifndef ASH_ASSISTANT_UI_DIALOG_PLATE_H_
 #define ASH_ASSISTANT_UI_DIALOG_PLATE_H_
 
+#include "ash/assistant/model/assistant_interaction_model_observer.h"
 #include "base/macros.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/view.h"
@@ -13,11 +14,17 @@
 
 class AshAssistantController;
 
-class DialogPlate : public views::View, public views::TextfieldController {
+class DialogPlate : public views::View,
+                    public views::TextfieldController,
+                    public AssistantInteractionModelObserver {
  public:
   explicit DialogPlate(AshAssistantController* assistant_controller);
   ~DialogPlate() override;
 
+  // AssistantInteractionModelObserver:
+  void OnInputModalityChanged(InputModality input_modality) override;
+  void OnMicStateChanged(MicState mic_state) override;
+
   // views::TextfieldController:
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override;
@@ -26,8 +33,10 @@
 
  private:
   void InitLayout();
+  void UpdateIcon();
 
   AshAssistantController* const assistant_controller_;  // Owned by Shell.
+  views::View* icon_;  // Owned by view hierarchy.
 
   DISALLOW_COPY_AND_ASSIGN(DialogPlate);
 };
diff --git a/ash/autoclick/autoclick_controller.cc b/ash/autoclick/autoclick_controller.cc
index c7be010..020f0cb55 100644
--- a/ash/autoclick/autoclick_controller.cc
+++ b/ash/autoclick/autoclick_controller.cc
@@ -6,6 +6,7 @@
 
 #include "ash/autoclick/common/autoclick_controller_common.h"
 #include "ash/autoclick/common/autoclick_controller_common_delegate.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/wm/root_window_finder.h"
@@ -26,8 +27,6 @@
   return base::TimeDelta::FromMilliseconds(int64_t{kDefaultAutoclickDelayMs});
 }
 
-const int AutoclickController::kDefaultAutoclickDelayMs = 1000;
-
 class AutoclickControllerImpl : public AutoclickController,
                                 public ui::EventHandler,
                                 public AutoclickControllerCommonDelegate,
diff --git a/ash/autoclick/autoclick_controller.h b/ash/autoclick/autoclick_controller.h
index 3c99b30..5b64af5e 100644
--- a/ash/autoclick/autoclick_controller.h
+++ b/ash/autoclick/autoclick_controller.h
@@ -30,10 +30,6 @@
 
   static AutoclickController* CreateInstance();
 
-  // The default wait time between last mouse movement and sending
-  // the autoclick.
-  static const int kDefaultAutoclickDelayMs;
-
   // Gets the default wait time as a base::TimeDelta object.
   static base::TimeDelta GetDefaultAutoclickDelay();
 
diff --git a/ash/components/autoclick/autoclick_application.cc b/ash/components/autoclick/autoclick_application.cc
index b4219f2..5f5ba8e 100644
--- a/ash/components/autoclick/autoclick_application.cc
+++ b/ash/components/autoclick/autoclick_application.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/bind_helpers.h"
 #include "base/macros.h"
@@ -29,13 +30,6 @@
 #include "ui/views/widget/widget_delegate.h"
 
 namespace autoclick {
-namespace {
-
-// The default wait time between last mouse movement and sending
-// the autoclick.
-const int kDefaultAutoclickDelayMs = 1000;
-
-}  // namespace
 
 // AutoclickUI handles events to the autoclick app.
 class AutoclickUI : public views::WidgetDelegateView,
@@ -110,7 +104,8 @@
   }
   autoclick_controller_common_ =
       std::make_unique<ash::AutoclickControllerCommon>(
-          base::TimeDelta::FromMilliseconds(kDefaultAutoclickDelayMs), this);
+          base::TimeDelta::FromMilliseconds(ash::kDefaultAutoclickDelayMs),
+          this);
 }
 
 void AutoclickApplication::OnBindInterface(
diff --git a/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc b/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
index 6c8693b..f4930e2 100644
--- a/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
+++ b/ash/components/shortcut_viewer/views/keyboard_shortcut_item_view.cc
@@ -157,30 +157,45 @@
   if (width <= 0)
     return;
 
-  // The width of |description_label_view_| and |shortcut_label_view_| as a
-  // ratio of its parent view's width. The unused width is to have some spacing
-  // in between the two views.
-  // These values are chosen to put all the bubble views in one line.
-  constexpr float kDescriptionViewPreferredWidthRatio = 0.29f;
+  // The max width of |shortcut_label_view_| as a ratio of its parent view's
+  // width. This value is chosen to put all the bubble views in one line.
   constexpr float kShortcutViewPreferredWidthRatio = 0.69f;
-  const int description_view_preferred_width =
-      width * kDescriptionViewPreferredWidthRatio;
+  // The minimum spacing between |description_label_view_| and
+  // |shortcut_label_view_|.
+  constexpr int kMinimumSpacing = 64;
+
   const int shortcut_view_preferred_width =
       width * kShortcutViewPreferredWidthRatio;
+  const int shortcut_view_height =
+      shortcut_label_view_->GetHeightForWidth(shortcut_view_preferred_width);
+
+  // Sets the bounds and layout in order to get the left most label in the
+  // |shortcut_label_view_|, which is used to calculate the preferred width for
+  // |description_label_view_|.
+  shortcut_label_view_->SetBounds(0, 0, shortcut_view_preferred_width,
+                                  shortcut_view_height);
+  DCHECK(shortcut_label_view_->has_children());
+  // Labels in |shortcut_label_view_| are right aligned, so we need to find the
+  // minimum left coordinates of all the lables.
+  int min_left = shortcut_view_preferred_width;
+  for (int i = 0; i < shortcut_label_view_->child_count(); ++i) {
+    min_left =
+        std::min(min_left, shortcut_label_view_->child_at(i)->bounds().x());
+  }
+
+  // The width of |description_label_view_| will be dynamically adjusted to fill
+  // the spacing.
+  const int description_view_preferred_width =
+      width - (shortcut_view_preferred_width - min_left) - kMinimumSpacing;
   const int description_view_height =
       description_label_view_->GetHeightForWidth(
           description_view_preferred_width);
-  const int shortcut_view_height =
-      shortcut_label_view_->GetHeightForWidth(shortcut_view_preferred_width);
 
   // Sets the bounds and layout in order to get the center points of the views
   // making up the top lines in both the description and shortcut views.
   // We want the center of the top lines in both views to align with each other.
   description_label_view_->SetBounds(0, 0, description_view_preferred_width,
                                      description_view_height);
-  shortcut_label_view_->SetBounds(0, 0, shortcut_view_preferred_width,
-                                  shortcut_view_height);
-
   DCHECK(shortcut_label_view_->has_children() &&
          description_label_view_->has_children());
   const int description_view_top_line_center_offset_y =
diff --git a/ash/components/shortcut_viewer_strings.grdp b/ash/components/shortcut_viewer_strings.grdp
index 5b94efaa..1ee8445d 100644
--- a/ash/components/shortcut_viewer_strings.grdp
+++ b/ash/components/shortcut_viewer_strings.grdp
@@ -97,10 +97,10 @@
 
   <!-- Shortcuts descriptions -->
   <message name="IDS_KSV_DESCRIPTION_TOGGLE_DOCKED_MAGNIFIER" desc="Description of the command in keyboard shortcut viewer.">
-    Toggle the Docked Magnifier on or off.
+    Toggle the Docked Magnifier on or off
   </message>
   <message name="IDS_KSV_DESCRIPTION_TOGGLE_FULLSCREEN_MAGNIFIER" desc="Description of the command in keyboard shortcut viewer.">
-    Toggle the Fullscreen Magnifier on or off.
+    Toggle the Fullscreen Magnifier on or off
   </message>
   <message name="IDS_KSV_DESCRIPTION_LOCK_SCREEN" desc="Description of the command in keyboard shortcut viewer.">
     Lock screen
diff --git a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
index dd50062..753e05f 100644
--- a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
@@ -174,15 +174,15 @@
 
 std::unique_ptr<content::WebContents>
 ScreenOrientationControllerTest::CreateWebContents() {
-  return base::WrapUnique(content::WebContentsTester::CreateTestWebContents(
-      ShellContentState::GetInstance()->GetActiveBrowserContext(), nullptr));
+  return content::WebContentsTester::CreateTestWebContents(
+      ShellContentState::GetInstance()->GetActiveBrowserContext(), nullptr);
 }
 
 std::unique_ptr<content::WebContents>
 ScreenOrientationControllerTest::CreateSecondaryWebContents() {
   secondary_browser_context_.reset(new content::TestBrowserContext());
-  return base::WrapUnique(content::WebContentsTester::CreateTestWebContents(
-      secondary_browser_context_.get(), nullptr));
+  return content::WebContentsTester::CreateTestWebContents(
+      secondary_browser_context_.get(), nullptr);
 }
 
 void ScreenOrientationControllerTest::SetUp() {
diff --git a/ash/display/cursor_window_controller.cc b/ash/display/cursor_window_controller.cc
index d7aa1a6..b028491a 100644
--- a/ash/display/cursor_window_controller.cc
+++ b/ash/display/cursor_window_controller.cc
@@ -4,12 +4,12 @@
 
 #include "ash/display/cursor_window_controller.h"
 
-#include "ash/ash_constants.h"
 #include "ash/components/cursor/cursor_view.h"
 #include "ash/display/display_color_manager.h"
 #include "ash/display/mirror_window_controller.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/magnifier/magnification_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/shell_window_ids.h"
diff --git a/ash/display/cursor_window_controller.h b/ash/display/cursor_window_controller.h
index 3cbf6dc..9b1c6ce 100644
--- a/ash/display/cursor_window_controller.h
+++ b/ash/display/cursor_window_controller.h
@@ -7,8 +7,8 @@
 
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/ash_export.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "base/macros.h"
 #include "ui/aura/window.h"
 #include "ui/base/cursor/cursor.h"
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc
index fe6c13e9..d357ba7 100644
--- a/ash/frame/caption_buttons/frame_caption_button.cc
+++ b/ash/frame/caption_buttons/frame_caption_button.cc
@@ -4,7 +4,7 @@
 
 #include "ash/frame/caption_buttons/frame_caption_button.h"
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/animation/throb_animation.h"
 #include "ui/gfx/canvas.h"
diff --git a/ash/frame/frame_border_hit_test.cc b/ash/frame/frame_border_hit_test.cc
index d174386d..d3cf03b1 100644
--- a/ash/frame/frame_border_hit_test.cc
+++ b/ash/frame/frame_border_hit_test.cc
@@ -4,8 +4,8 @@
 
 #include "ash/frame/frame_border_hit_test.h"
 
-#include "ash/ash_constants.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/shell_port.h"
 #include "ui/base/hit_test.h"
 #include "ui/views/widget/widget.h"
diff --git a/ash/login/ui/login_bubble.cc b/ash/login/ui/login_bubble.cc
index ed4da72..b804f7f2 100644
--- a/ash/login/ui/login_bubble.cc
+++ b/ash/login/ui/login_bubble.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "ash/ash_constants.h"
 #include "ash/focus_cycler.h"
 #include "ash/login/ui/layout_util.h"
 #include "ash/login/ui/lock_screen.h"
@@ -15,6 +14,7 @@
 #include "ash/login/ui/login_button.h"
 #include "ash/login/ui/login_menu_view.h"
 #include "ash/login/ui/non_accessible_view.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/login/ui/login_button.cc b/ash/login/ui/login_button.cc
index bea98eff..9b1ae0f3 100644
--- a/ash/login/ui/login_button.cc
+++ b/ash/login/ui/login_button.cc
@@ -4,7 +4,7 @@
 
 #include "ash/login/ui/login_button.h"
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_highlight.h"
 #include "ui/views/animation/ink_drop_impl.h"
diff --git a/ash/login/ui/login_pin_view.cc b/ash/login/ui/login_pin_view.cc
index 443a5bd1..eec6593 100644
--- a/ash/login/ui/login_pin_view.cc
+++ b/ash/login/ui/login_pin_view.cc
@@ -6,8 +6,8 @@
 
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/login/ui/login_button.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/login_constants.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
diff --git a/ash/login/ui/login_user_view.cc b/ash/login/ui/login_user_view.cc
index 59aa0c5..3b3f768 100644
--- a/ash/login/ui/login_user_view.cc
+++ b/ash/login/ui/login_user_view.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/login/ui/animated_rounded_image_view.h"
 #include "ash/login/ui/hover_notifier.h"
 #include "ash/login/ui/image_parser.h"
@@ -15,6 +14,7 @@
 #include "ash/login/ui/login_button.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/login/ui/user_switch_flip_animation.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/login_constants.h"
 #include "ash/public/interfaces/user_info.mojom.h"
 #include "ash/resources/vector_icons/vector_icons.h"
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 455bbdf0..11df2f3 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -30,6 +30,7 @@
     "app_list/tokenized_string_match.cc",
     "app_list/tokenized_string_match.h",
     "app_types.h",
+    "ash_constants.h",
     "ash_features.cc",
     "ash_features.h",
     "ash_pref_names.cc",
diff --git a/ash/ash_constants.h b/ash/public/cpp/ash_constants.h
similarity index 63%
rename from ash/ash_constants.h
rename to ash/public/cpp/ash_constants.h
index fc30bec..0c42973 100644
--- a/ash/ash_constants.h
+++ b/ash/public/cpp/ash_constants.h
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_ASH_CONSTANTS_H_
-#define ASH_ASH_CONSTANTS_H_
-
-#include "ash/ash_export.h"
+#ifndef ASH_PUBLIC_CPP_ASH_CONSTANTS_H_
+#define ASH_PUBLIC_CPP_ASH_CONSTANTS_H_
 
 #include "third_party/skia/include/core/SkColor.h"
 
@@ -15,25 +13,28 @@
 
 // In the window corners, the resize areas don't actually expand bigger, but the
 // 16 px at the end of each edge triggers diagonal resizing.
-ASH_EXPORT extern const int kResizeAreaCornerSize;
+constexpr int kResizeAreaCornerSize = 16;
 
 // Ash windows do not have a traditional visible window frame. Window content
 // extends to the edge of the window. We consider a small region outside the
 // window bounds and an even smaller region overlapping the window to be the
 // "non-client" area and use it for resizing.
-ASH_EXPORT extern const int kResizeOutsideBoundsSize;
-ASH_EXPORT extern const int kResizeOutsideBoundsScaleForTouch;
-ASH_EXPORT extern const int kResizeInsideBoundsSize;
+constexpr int kResizeOutsideBoundsSize = 6;
+constexpr int kResizeOutsideBoundsScaleForTouch = 5;
+constexpr int kResizeInsideBoundsSize = 1;
 
 // Background color used for the Chrome OS boot splash screen.
-extern const SkColor kChromeOsBootColor;
+constexpr SkColor kChromeOsBootColor = SkColorSetRGB(0xfe, 0xfe, 0xfe);
 
 // The border color of keyboard focus for launcher items and system tray.
 constexpr SkColor kFocusBorderColor = SK_ColorTRANSPARENT;
 constexpr int kFocusBorderThickness = 0;
 
-ASH_EXPORT extern const int kDefaultLargeCursorSize;
+constexpr int kDefaultLargeCursorSize = 64;
+
+// The default wait time between last mouse movement and sending autoclick.
+constexpr int kDefaultAutoclickDelayMs = 1000;
 
 }  // namespace ash
 
-#endif  // ASH_ASH_CONSTANTS_H_
+#endif  // ASH_PUBLIC_CPP_ASH_CONSTANTS_H_
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index c25651585..9f297a2 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -12,12 +12,12 @@
 #include "ash/accessibility/accessibility_panel_layout_manager.h"
 #include "ash/accessibility/touch_exploration_controller.h"
 #include "ash/accessibility/touch_exploration_manager.h"
-#include "ash/ash_constants.h"
 #include "ash/focus_cycler.h"
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/host/ash_window_tree_host.h"
 #include "ash/lock_screen_action/lock_screen_action_background_controller.h"
 #include "ash/login_status.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shelf_types.h"
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index b6cd2945c..afb0651 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -7,13 +7,13 @@
 #include <memory>
 #include <utility>
 
-#include "ash/ash_constants.h"
 #include "ash/focus_cycler.h"
 #include "ash/lock_screen_action/lock_screen_action_background_controller.h"
 #include "ash/lock_screen_action/lock_screen_action_background_state.h"
 #include "ash/login/login_screen_controller.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/login/ui/lock_window.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc
index afddd54..95b555d6 100644
--- a/ash/shelf/shelf_button.cc
+++ b/ash/shelf/shelf_button.cc
@@ -7,7 +7,7 @@
 #include <algorithm>
 #include <memory>
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/shelf/ink_drop_button_listener.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 185fe63..2e6d3e6 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -7,9 +7,9 @@
 #include <algorithm>
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/drag_drop/drag_image_view.h"
 #include "ash/metrics/user_metrics_recorder.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/scoped_root_window_for_new_windows.h"
diff --git a/ash/shell.cc b/ash/shell.cc
index 7115bb5..fda0577 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -19,7 +19,6 @@
 #include "ash/accessibility/accessibility_focus_ring_controller.h"
 #include "ash/accessibility/key_accessibility_enabler.h"
 #include "ash/app_list/app_list_controller_impl.h"
-#include "ash/ash_constants.h"
 #include "ash/assistant/ash_assistant_controller.h"
 #include "ash/autoclick/autoclick_controller.h"
 #include "ash/cast_config_controller.h"
@@ -66,6 +65,7 @@
 #include "ash/multi_device_setup/multi_device_notification_presenter.h"
 #include "ash/new_window_controller.h"
 #include "ash/note_taking_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/config.h"
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index 3bb44a8..562517d 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -5,8 +5,8 @@
 #include "ash/system/ime_menu/ime_menu_tray.h"
 
 #include "ash/accessibility/accessibility_controller.h"
-#include "ash/ash_constants.h"
 #include "ash/ime/ime_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc
index 93b54129..65e4b0fa1 100644
--- a/ash/system/tray/actionable_view.cc
+++ b/ash/system/tray/actionable_view.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/tray/actionable_view.h"
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/system/tray/tray_constants.h"
diff --git a/ash/system/tray/system_menu_button.cc b/ash/system/tray/system_menu_button.cc
index e45756a..7ec1b44 100644
--- a/ash/system/tray/system_menu_button.cc
+++ b/ash/system/tray/system_menu_button.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/tray/system_menu_button.h"
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/tray_constants.h"
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 3cc1862..7852b9e 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -7,10 +7,10 @@
 #include <algorithm>
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/focus_cycler.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/login/ui/lock_window.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc
index c7571196..9b309b0 100644
--- a/ash/system/tray/tray_popup_utils.cc
+++ b/ash/system/tray/tray_popup_utils.cc
@@ -8,8 +8,8 @@
 #include <memory>
 #include <utility>
 
-#include "ash/ash_constants.h"
 #include "ash/ash_view_ids.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
diff --git a/ash/system/user/button_from_view.cc b/ash/system/user/button_from_view.cc
index 2afb7f5..fa6b3f2e 100644
--- a/ash/system/user/button_from_view.cc
+++ b/ash/system/user/button_from_view.cc
@@ -6,7 +6,7 @@
 
 #include "ash/system/user/button_from_view.h"
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
diff --git a/ash/test/ash_test_environment_content.cc b/ash/test/ash_test_environment_content.cc
index 05c1547..b924426 100644
--- a/ash/test/ash_test_environment_content.cc
+++ b/ash/test/ash_test_environment_content.cc
@@ -16,8 +16,8 @@
 
 std::unique_ptr<content::WebContents> CreateWebContents(
     content::BrowserContext* browser_context) {
-  return base::WrapUnique(content::WebContentsTester::CreateTestWebContents(
-      browser_context, nullptr));
+  return content::WebContentsTester::CreateTestWebContents(browser_context,
+                                                           nullptr);
 }
 
 }  // namespace
diff --git a/ash/wm/non_client_frame_controller.cc b/ash/wm/non_client_frame_controller.cc
index 091ef45..308e183 100644
--- a/ash/wm/non_client_frame_controller.cc
+++ b/ash/wm/non_client_frame_controller.cc
@@ -10,10 +10,10 @@
 #include <string>
 #include <vector>
 
-#include "ash/ash_constants.h"
 #include "ash/ash_layout_constants.h"
 #include "ash/frame/custom_frame_view_ash.h"
 #include "ash/frame/detached_title_area_renderer.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
 #include "ash/window_manager.h"
 #include "ash/wm/move_event_handler.h"
diff --git a/ash/wm/resize_handle_window_targeter.cc b/ash/wm/resize_handle_window_targeter.cc
index 146be4b..03e5910 100644
--- a/ash/wm/resize_handle_window_targeter.cc
+++ b/ash/wm/resize_handle_window_targeter.cc
@@ -4,7 +4,7 @@
 
 #include "ash/wm/resize_handle_window_targeter.h"
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 #include "ash/wm/window_state.h"
 #include "ui/aura/window.h"
diff --git a/ash/wm/resize_shadow_and_cursor_unittest.cc b/ash/wm/resize_shadow_and_cursor_unittest.cc
index b479f1d..9153c4e 100644
--- a/ash/wm/resize_shadow_and_cursor_unittest.cc
+++ b/ash/wm/resize_shadow_and_cursor_unittest.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/ash_constants.h"
 #include "ash/frame/custom_frame_view_ash.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/cursor_manager_test_api.h"
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index 7b6558b..1f4a93c 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -6,8 +6,8 @@
 
 #include <memory>
 
-#include "ash/ash_constants.h"
 #include "ash/display/screen_orientation_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/wm/overview/rounded_rect_view.h"
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 946477a..3a763d5 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include <vector>
 
-#include "ash/ash_constants.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index f94350b..9ac4839 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "ash/wm/workspace/multi_window_resize_controller.h"
 
-#include "ash/ash_constants.h"
 #include "ash/frame/custom_frame_view_ash.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/shell.h"
 #include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 8d9a08e..5f04e581 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -729,6 +729,7 @@
     "sha1.h",
     "single_thread_task_runner.h",
     "stl_util.h",
+    "strings/char_traits.h",
     "strings/latin1_string_conversions.cc",
     "strings/latin1_string_conversions.h",
     "strings/nullable_string16.cc",
@@ -2306,6 +2307,7 @@
     "sequenced_task_runner_unittest.cc",
     "sha1_unittest.cc",
     "stl_util_unittest.cc",
+    "strings/char_traits_unittest.cc",
     "strings/nullable_string16_unittest.cc",
     "strings/pattern_unittest.cc",
     "strings/safe_sprintf_unittest.cc",
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
index d39bf6ba..43ae2591 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
@@ -13,11 +13,12 @@
 import android.os.Looper;
 
 import org.chromium.base.Log;
-import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Queue;
 
 /**
  * This class is responsible for allocating and managing connections to child
@@ -27,17 +28,6 @@
 public class ChildConnectionAllocator {
     private static final String TAG = "ChildConnAllocator";
 
-    /** Listener that clients can use to get notified when connections get allocated/freed. */
-    public abstract static class Listener {
-        /** Called when a connection has been allocated, before it gets bound. */
-        public void onConnectionAllocated(
-                ChildConnectionAllocator allocator, ChildProcessConnection connection) {}
-
-        /** Called when a connection has been freed. */
-        public void onConnectionFreed(
-                ChildConnectionAllocator allocator, ChildProcessConnection connection) {}
-    }
-
     /** Factory interface. Used by tests to specialize created connections. */
     @VisibleForTesting
     public interface ConnectionFactory {
@@ -64,6 +54,9 @@
     // Connections to services. Indices of the array correspond to the service numbers.
     private final ChildProcessConnection[] mChildProcessConnections;
 
+    // Runnable which will be called when allocator wants to allocate a new connection, but does
+    // not have any more free slots. May be null.
+    private final Runnable mFreeSlotCallback;
     private final String mPackageName;
     private final String mServiceClassName;
     private final boolean mBindToCaller;
@@ -73,7 +66,7 @@
     // The list of free (not bound) service indices.
     private final ArrayList<Integer> mFreeConnectionIndices;
 
-    private final ObserverList<Listener> mListeners = new ObserverList<>();
+    private final Queue<Runnable> mPendingAllocations = new ArrayDeque<>();
 
     private ConnectionFactory mConnectionFactory = new ConnectionFactoryImpl();
 
@@ -82,8 +75,9 @@
      * AndroidManifest.xml.
      */
     public static ChildConnectionAllocator create(Context context, Handler launcherHandler,
-            String packageName, String serviceClassName, String numChildServicesManifestKey,
-            boolean bindToCaller, boolean bindAsExternalService, boolean useStrongBinding) {
+            Runnable freeSlotCallback, String packageName, String serviceClassName,
+            String numChildServicesManifestKey, boolean bindToCaller, boolean bindAsExternalService,
+            boolean useStrongBinding) {
         int numServices = -1;
         PackageManager packageManager = context.getPackageManager();
         try {
@@ -109,28 +103,9 @@
             throw new RuntimeException("Illegal meta data value: the child service doesn't exist");
         }
 
-        return new ChildConnectionAllocator(launcherHandler, packageName, serviceClassName,
-                bindToCaller, bindAsExternalService, useStrongBinding, numServices);
-    }
-
-    // TODO(jcivelli): remove this method once crbug.com/693484 has been addressed.
-    public static int getNumberOfServices(
-            Context context, String packageName, String numChildServicesManifestKey) {
-        int numServices = -1;
-        try {
-            PackageManager packageManager = context.getPackageManager();
-            ApplicationInfo appInfo =
-                    packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
-            if (appInfo.metaData != null) {
-                numServices = appInfo.metaData.getInt(numChildServicesManifestKey, -1);
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new RuntimeException("Could not get application info", e);
-        }
-        if (numServices < 0) {
-            throw new RuntimeException("Illegal meta data value for number of child services");
-        }
-        return numServices;
+        return new ChildConnectionAllocator(launcherHandler, freeSlotCallback, packageName,
+                serviceClassName, bindToCaller, bindAsExternalService, useStrongBinding,
+                numServices);
     }
 
     /**
@@ -138,16 +113,18 @@
      * instead of being retrieved from the AndroidManifest.xml.
      */
     @VisibleForTesting
-    public static ChildConnectionAllocator createForTest(String packageName,
-            String serviceClassName, int serviceCount, boolean bindToCaller,
+    public static ChildConnectionAllocator createForTest(Runnable freeSlotCallback,
+            String packageName, String serviceClassName, int serviceCount, boolean bindToCaller,
             boolean bindAsExternalService, boolean useStrongBinding) {
-        return new ChildConnectionAllocator(new Handler(), packageName, serviceClassName,
-                bindToCaller, bindAsExternalService, useStrongBinding, serviceCount);
+        return new ChildConnectionAllocator(new Handler(), freeSlotCallback, packageName,
+                serviceClassName, bindToCaller, bindAsExternalService, useStrongBinding,
+                serviceCount);
     }
 
-    private ChildConnectionAllocator(Handler launcherHandler, String packageName,
-            String serviceClassName, boolean bindToCaller, boolean bindAsExternalService,
-            boolean useStrongBinding, int numChildServices) {
+    private ChildConnectionAllocator(Handler launcherHandler, Runnable freeSlotCallback,
+            String packageName, String serviceClassName, boolean bindToCaller,
+            boolean bindAsExternalService, boolean useStrongBinding, int numChildServices) {
+        mFreeSlotCallback = freeSlotCallback;
         mLauncherHandler = launcherHandler;
         assert isRunningOnLauncherThread();
         mPackageName = packageName;
@@ -242,10 +219,6 @@
                 context, serviceName, mBindToCaller, mBindAsExternalService, serviceBundle);
         mChildProcessConnections[slot] = connection;
 
-        for (Listener listener : mListeners) {
-            listener.onConnectionAllocated(this, connection);
-        }
-
         connection.start(mUseStrongBinding, serviceCallbackWrapper);
         Log.d(TAG, "Allocator allocated and bound a connection, name: %s, slot: %d",
                 mServiceClassName, slot);
@@ -269,9 +242,20 @@
             Log.d(TAG, "Allocator freed a connection, name: %s, slot: %d", mServiceClassName, slot);
         }
 
-        for (Listener listener : mListeners) {
-            listener.onConnectionFreed(this, connection);
-        }
+        if (mPendingAllocations.isEmpty()) return;
+        mPendingAllocations.remove().run();
+        assert mFreeConnectionIndices.isEmpty();
+        if (!mPendingAllocations.isEmpty() && mFreeSlotCallback != null) mFreeSlotCallback.run();
+    }
+
+    // Can only be called once all slots are full, ie when allocate returns null.
+    // The callback will be called when a slot becomes free, and should synchronous call
+    // allocate to take the slot.
+    public void queueAllocation(Runnable runnable) {
+        assert mFreeConnectionIndices.isEmpty();
+        boolean wasEmpty = mPendingAllocations.isEmpty();
+        mPendingAllocations.add(runnable);
+        if (wasEmpty && mFreeSlotCallback != null) mFreeSlotCallback.run();
     }
 
     public String getPackageName() {
@@ -291,16 +275,6 @@
         return mChildProcessConnections.length;
     }
 
-    public void addListener(Listener listener) {
-        assert !mListeners.hasObserver(listener);
-        mListeners.addObserver(listener);
-    }
-
-    public void removeListener(Listener listener) {
-        boolean removed = mListeners.removeObserver(listener);
-        assert removed;
-    }
-
     public boolean isConnectionFromAllocator(ChildProcessConnection connection) {
         for (ChildProcessConnection existingConnection : mChildProcessConnections) {
             if (existingConnection == connection) return true;
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java
index 556270e..7cdc852 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessLauncher.java
@@ -200,19 +200,9 @@
                 Log.d(TAG, "Failed to allocate a child connection (no queuing).");
                 return false;
             }
-            // No connection is available at this time. Add a listener so when one becomes
-            // available we can create the service.
-            mConnectionAllocator.addListener(new ChildConnectionAllocator.Listener() {
-                @Override
-                public void onConnectionFreed(
-                        ChildConnectionAllocator allocator, ChildProcessConnection connection) {
-                    assert allocator == mConnectionAllocator;
-                    if (!allocator.isFreeConnectionAvailable()) return;
-                    allocator.removeListener(this);
-                    allocateAndSetupConnection(
-                            serviceCallback, setupConnection, queueIfNoFreeConnection);
-                }
-            });
+            mConnectionAllocator.queueAllocation(
+                    () -> allocateAndSetupConnection(
+                                    serviceCallback, setupConnection, queueIfNoFreeConnection));
             return false;
         }
 
diff --git a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
index 4e24d05..5c5bca9 100644
--- a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
+++ b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
@@ -132,9 +132,9 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mAllocator = ChildConnectionAllocator.createForTest(TEST_PACKAGE_NAME, "AllocatorTest",
-                MAX_CONNECTION_NUMBER, true /* bindToCaller */, false /* bindAsExternalService */,
-                false /* useStrongBinding */);
+        mAllocator = ChildConnectionAllocator.createForTest(null, TEST_PACKAGE_NAME,
+                "AllocatorTest", MAX_CONNECTION_NUMBER, true /* bindToCaller */,
+                false /* bindAsExternalService */, false /* useStrongBinding */);
         mAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
     }
 
@@ -144,9 +144,6 @@
         assertFalse(mAllocator.anyConnectionAllocated());
         assertEquals(MAX_CONNECTION_NUMBER, mAllocator.getNumberOfServices());
 
-        ChildConnectionAllocator.Listener listener = mock(ChildConnectionAllocator.Listener.class);
-        mAllocator.addListener(listener);
-
         ChildProcessConnection connection =
                 mAllocator.allocate(null /* context */, null /* serviceBundle */, mServiceCallback);
         assertNotNull(connection);
@@ -154,7 +151,6 @@
         verify(connection, times(1))
                 .start(eq(false) /* useStrongBinding */,
                         any(ChildProcessConnection.ServiceCallback.class));
-        verify(listener, times(1)).onConnectionAllocated(mAllocator, connection);
         assertTrue(mAllocator.anyConnectionAllocated());
     }
 
@@ -177,6 +173,44 @@
                 null /* context */, null /* serviceBundle */, mServiceCallback));
     }
 
+    @Test
+    @Feature({"ProcessManagement"})
+    public void testQueueAllocation() {
+        Runnable freeConnectionCallback = mock(Runnable.class);
+        mAllocator = ChildConnectionAllocator.createForTest(freeConnectionCallback,
+                TEST_PACKAGE_NAME, "AllocatorTest", 1, true /* bindToCaller */,
+                false /* bindAsExternalService */, false /* useStrongBinding */);
+        mAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
+        // Occupy all slots.
+        ChildProcessConnection connection =
+                mAllocator.allocate(null /* context */, null /* serviceBundle */, mServiceCallback);
+        assertNotNull(connection);
+        assertFalse(mAllocator.isFreeConnectionAvailable());
+
+        final ChildProcessConnection newConnection[] = new ChildProcessConnection[2];
+        Runnable allocate1 = () -> {
+            newConnection[0] = mAllocator.allocate(
+                    null /* context */, null /* serviceBundle */, mServiceCallback);
+        };
+        Runnable allocate2 = () -> {
+            newConnection[1] = mAllocator.allocate(
+                    null /* context */, null /* serviceBundle */, mServiceCallback);
+        };
+        mAllocator.queueAllocation(allocate1);
+        mAllocator.queueAllocation(allocate2);
+        verify(freeConnectionCallback, times(1)).run();
+        assertNull(newConnection[0]);
+
+        mTestConnectionFactory.simulateServiceProcessDying();
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        assertNotNull(newConnection[0]);
+        assertNull(newConnection[1]);
+
+        mTestConnectionFactory.simulateServiceProcessDying();
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        assertNotNull(newConnection[1]);
+    }
+
     /**
      * Tests that the connection is created with the useStrongBinding parameter specified in the
      * allocator.
@@ -185,7 +219,7 @@
     @Feature({"ProcessManagement"})
     public void testStrongBindingParam() {
         for (boolean useStrongBinding : new boolean[] {true, false}) {
-            ChildConnectionAllocator allocator = ChildConnectionAllocator.createForTest(
+            ChildConnectionAllocator allocator = ChildConnectionAllocator.createForTest(null,
                     TEST_PACKAGE_NAME, "AllocatorTest", MAX_CONNECTION_NUMBER,
                     true /* bindToCaller */, false /* bindAsExternalService */, useStrongBinding);
             allocator.setConnectionFactoryForTesting(mTestConnectionFactory);
@@ -242,12 +276,9 @@
     }
 
     /**
-     * Tests that the allocator clears the connection when it fails to bind/process dies and that
-     * the listener gets invoked.
+     * Tests that the allocator clears the connection when it fails to bind/process dies.
      */
     private void testFreeConnection(int callbackType) {
-        ChildConnectionAllocator.Listener listener = mock(ChildConnectionAllocator.Listener.class);
-        mAllocator.addListener(listener);
         ChildProcessConnection connection =
                 mAllocator.allocate(null /* context */, null /* serviceBundle */, mServiceCallback);
 
@@ -274,7 +305,6 @@
         }
         ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
         assertFalse(mAllocator.anyConnectionAllocated());
-        verify(listener, times(1)).onConnectionFreed(mAllocator, connection);
         verify(mServiceCallback, never()).onChildStarted();
         verify(mServiceCallback, times(onChildStartFailedExpectedCount))
                 .onChildStartFailed(connection);
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc
index f7c8af6..d2a7d89 100644
--- a/base/memory/weak_ptr.cc
+++ b/base/memory/weak_ptr.cc
@@ -70,9 +70,13 @@
 WeakPtrBase::~WeakPtrBase() = default;
 
 WeakPtrBase::WeakPtrBase(const WeakReference& ref, uintptr_t ptr)
-    : ref_(ref), ptr_(ptr) {}
+    : ref_(ref), ptr_(ptr) {
+  DCHECK(ptr_);
+}
 
-WeakPtrFactoryBase::WeakPtrFactoryBase(uintptr_t ptr) : ptr_(ptr) {}
+WeakPtrFactoryBase::WeakPtrFactoryBase(uintptr_t ptr) : ptr_(ptr) {
+  DCHECK(ptr_);
+}
 
 WeakPtrFactoryBase::~WeakPtrFactoryBase() {
   ptr_ = 0;
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index a7be14af..34e7d2e 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -307,7 +307,6 @@
   ~WeakPtrFactory() = default;
 
   WeakPtr<T> GetWeakPtr() {
-    DCHECK(ptr_);
     return WeakPtr<T>(weak_reference_owner_.GetRef(),
                       reinterpret_cast<T*>(ptr_));
   }
diff --git a/base/strings/char_traits.h b/base/strings/char_traits.h
new file mode 100644
index 0000000..6cfbad5af
--- /dev/null
+++ b/base/strings/char_traits.h
@@ -0,0 +1,90 @@
+// 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_STRINGS_CHAR_TRAITS_H_
+#define BASE_STRINGS_CHAR_TRAITS_H_
+
+#include <stddef.h>
+
+namespace base {
+
+// constexpr version of http://en.cppreference.com/w/cpp/string/char_traits.
+// This currently just implements the bits needed to support a (mostly)
+// constexpr StringPiece.
+//
+// TODO(dcheng): Once we switch to C++17, most methods will become constexpr and
+// we can switch over to using the one in the standard library.
+template <typename T>
+struct CharTraits {
+  // Performs a lexographical comparison of the first N characters of |s1| and
+  // |s2|. Returns 0 if equal, -1 if |s1| is less than |s2|, and 1 if |s1| is
+  // greater than |s2|.
+  static constexpr int compare(const T* s1, const T* s2, size_t n) noexcept;
+
+  // Returns the length of |s|, assuming null termination (and not including the
+  // terminating null).
+  static constexpr size_t length(const T* s) noexcept;
+};
+
+template <typename T>
+constexpr int CharTraits<T>::compare(const T* s1,
+                                     const T* s2,
+                                     size_t n) noexcept {
+  for (; n; --n, ++s1, ++s2) {
+    if (*s1 < *s2)
+      return -1;
+    if (*s1 > *s2)
+      return 1;
+  }
+  return 0;
+}
+
+template <typename T>
+constexpr size_t CharTraits<T>::length(const T* s) noexcept {
+  size_t i = 0;
+  for (; *s; ++s)
+    ++i;
+  return i;
+}
+
+// char specialization of CharTraits that can use clang's constexpr instrinsics,
+// where available.
+template <>
+struct CharTraits<char> {
+  static constexpr int compare(const char* s1,
+                               const char* s2,
+                               size_t n) noexcept;
+  static constexpr size_t length(const char* s) noexcept;
+};
+
+constexpr int CharTraits<char>::compare(const char* s1,
+                                        const char* s2,
+                                        size_t n) noexcept {
+#if __has_feature(cxx_constexpr_string_builtins)
+  return __builtin_memcmp(s1, s2, n);
+#else
+  for (; n; --n, ++s1, ++s2) {
+    if (*s1 < *s2)
+      return -1;
+    if (*s1 > *s2)
+      return 1;
+  }
+  return 0;
+#endif
+}
+
+constexpr size_t CharTraits<char>::length(const char* s) noexcept {
+#if defined(__clang__)
+  return __builtin_strlen(s);
+#else
+  size_t i = 0;
+  for (; *s; ++s)
+    ++i;
+  return i;
+#endif
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_CHAR_TRAITS_H_
diff --git a/base/strings/char_traits_unittest.cc b/base/strings/char_traits_unittest.cc
new file mode 100644
index 0000000..31c421b
--- /dev/null
+++ b/base/strings/char_traits_unittest.cc
@@ -0,0 +1,32 @@
+// 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/strings/char_traits.h"
+#include "base/strings/string16.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(CharTraitsTest, CharCompare) {
+  static_assert(CharTraits<char>::compare("abc", "def", 3) == -1, "");
+  static_assert(CharTraits<char>::compare("def", "def", 3) == 0, "");
+  static_assert(CharTraits<char>::compare("ghi", "def", 3) == 1, "");
+}
+
+TEST(CharTraitsTest, CharLength) {
+  static_assert(CharTraits<char>::length("") == 0, "");
+  static_assert(CharTraits<char>::length("abc") == 3, "");
+}
+
+TEST(CharTraitsTest, Char16TCompare) {
+  static_assert(CharTraits<char16_t>::compare(u"abc", u"def", 3) == -1, "");
+  static_assert(CharTraits<char16_t>::compare(u"def", u"def", 3) == 0, "");
+  static_assert(CharTraits<char16_t>::compare(u"ghi", u"def", 3) == 1, "");
+}
+
+TEST(CharTraitsTest, Char16TLength) {
+  static_assert(CharTraits<char16_t>::length(u"abc") == 3, "");
+}
+
+}  // namespace base
diff --git a/base/strings/string_piece.cc b/base/strings/string_piece.cc
index c26bb36..c82a223 100644
--- a/base/strings/string_piece.cc
+++ b/base/strings/string_piece.cc
@@ -44,7 +44,8 @@
   if (x.size() != y.size())
     return false;
 
-  return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+  return CharTraits<StringPiece::value_type>::compare(x.data(), y.data(),
+                                                      x.size()) == 0;
 }
 
 std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index 8a7d0d8..775ea7c 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -29,6 +29,7 @@
 
 #include "base/base_export.h"
 #include "base/logging.h"
+#include "base/strings/char_traits.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece_forward.h"
 
@@ -176,9 +177,12 @@
   // in a "const char*" or a "string" wherever a "StringPiece" is
   // expected (likewise for char16, string16, StringPiece16).
   constexpr BasicStringPiece() : ptr_(NULL), length_(0) {}
-  BasicStringPiece(const value_type* str)
-      : ptr_(str),
-        length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
+  // TODO(dcheng): Construction from nullptr is not allowed for
+  // std::basic_string_view, so remove the special handling for it.
+  // Note: This doesn't just use STRING_TYPE::traits_type::length(), since that
+  // isn't constexpr until C++17.
+  constexpr BasicStringPiece(const value_type* str)
+      : ptr_(str), length_(!str ? 0 : CharTraits<value_type>::length(str)) {}
   BasicStringPiece(const STRING_TYPE& str)
       : ptr_(str.data()), length_(str.size()) {}
   constexpr BasicStringPiece(const value_type* offset, size_type len)
@@ -245,8 +249,8 @@
     length_ -= n;
   }
 
-  int compare(const BasicStringPiece<STRING_TYPE>& x) const {
-    int r = wordmemcmp(
+  constexpr int compare(BasicStringPiece x) const noexcept {
+    int r = CharTraits<value_type>::compare(
         ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
     if (r == 0) {
       if (length_ < x.length_) r = -1;
@@ -275,12 +279,6 @@
   size_type max_size() const { return length_; }
   size_type capacity() const { return length_; }
 
-  static int wordmemcmp(const value_type* p,
-                        const value_type* p2,
-                        size_type N) {
-    return STRING_TYPE::traits_type::compare(p, p2, N);
-  }
-
   // Sets the value of the given string target type to be the current string.
   // This saves a temporary over doing |a = b.as_string()|
   void CopyToString(STRING_TYPE* target) const {
@@ -296,16 +294,18 @@
   }
 
   // Does "this" start with "x"
-  bool starts_with(const BasicStringPiece& x) const {
-    return ((this->length_ >= x.length_) &&
-            (wordmemcmp(this->ptr_, x.ptr_, x.length_) == 0));
+  constexpr bool starts_with(BasicStringPiece x) const noexcept {
+    return (
+        (this->length_ >= x.length_) &&
+        (CharTraits<value_type>::compare(this->ptr_, x.ptr_, x.length_) == 0));
   }
 
   // Does "this" end with "x"
-  bool ends_with(const BasicStringPiece& x) const {
+  constexpr bool ends_with(BasicStringPiece x) const noexcept {
     return ((this->length_ >= x.length_) &&
-            (wordmemcmp(this->ptr_ + (this->length_-x.length_),
-                        x.ptr_, x.length_) == 0));
+            (CharTraits<value_type>::compare(
+                 this->ptr_ + (this->length_ - x.length_), x.ptr_, x.length_) ==
+             0));
   }
 
   // find: Search for a character or substring at a given offset.
@@ -395,7 +395,7 @@
 }
 
 inline bool operator<(const StringPiece& x, const StringPiece& y) {
-  const int r = StringPiece::wordmemcmp(
+  const int r = CharTraits<StringPiece::value_type>::compare(
       x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
   return ((r < 0) || ((r == 0) && (x.size() < y.size())));
 }
@@ -418,7 +418,8 @@
   if (x.size() != y.size())
     return false;
 
-  return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+  return CharTraits<StringPiece16::value_type>::compare(x.data(), y.data(),
+                                                        x.size()) == 0;
 }
 
 inline bool operator!=(const StringPiece16& x, const StringPiece16& y) {
@@ -426,7 +427,7 @@
 }
 
 inline bool operator<(const StringPiece16& x, const StringPiece16& y) {
-  const int r = StringPiece16::wordmemcmp(
+  const int r = CharTraits<StringPiece16::value_type>::compare(
       x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
   return ((r < 0) || ((r == 0) && (x.size() < y.size())));
 }
diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc
index 40e21e9..17d0897 100644
--- a/base/strings/string_piece_unittest.cc
+++ b/base/strings/string_piece_unittest.cc
@@ -706,4 +706,100 @@
   ASSERT_EQ(empty, BasicStringPiece<TypeParam>(empty.begin(), empty.end()));
 }
 
+TEST(StringPieceTest, ConstexprCtor) {
+  {
+    constexpr StringPiece piece;
+    std::ignore = piece;
+  }
+
+  {
+    constexpr StringPiece piece("abc");
+    std::ignore = piece;
+  }
+
+  {
+    constexpr StringPiece piece("abc", 2);
+    std::ignore = piece;
+  }
+}
+
+TEST(StringPieceTest, ConstexprData) {
+  {
+    constexpr StringPiece piece;
+    static_assert(piece.data() == nullptr, "");
+  }
+
+  {
+    constexpr StringPiece piece("abc");
+    static_assert(piece.data()[0] == 'a', "");
+    static_assert(piece.data()[1] == 'b', "");
+    static_assert(piece.data()[2] == 'c', "");
+  }
+
+  {
+    constexpr StringPiece piece("def", 2);
+    static_assert(piece.data()[0] == 'd', "");
+    static_assert(piece.data()[1] == 'e', "");
+  }
+}
+
+TEST(StringPieceTest, ConstexprSize) {
+  {
+    constexpr StringPiece piece;
+    static_assert(piece.size() == 0, "");
+  }
+
+  {
+    constexpr StringPiece piece("abc");
+    static_assert(piece.size() == 3, "");
+  }
+
+  {
+    constexpr StringPiece piece("def", 2);
+    static_assert(piece.size() == 2, "");
+  }
+}
+
+TEST(StringPieceTest, Compare) {
+  constexpr StringPiece piece = "def";
+
+  static_assert(piece.compare("ab") == 1, "");
+  static_assert(piece.compare("abc") == 1, "");
+  static_assert(piece.compare("abcd") == 1, "");
+  static_assert(piece.compare("de") == 1, "");
+  static_assert(piece.compare("def") == 0, "");
+  static_assert(piece.compare("defg") == -1, "");
+  static_assert(piece.compare("gh") == -1, "");
+  static_assert(piece.compare("ghi") == -1, "");
+  static_assert(piece.compare("ghij") == -1, "");
+}
+
+TEST(StringPieceTest, StartsWith) {
+  constexpr StringPiece piece("abc");
+
+  static_assert(piece.starts_with(""), "");
+  static_assert(piece.starts_with("a"), "");
+  static_assert(piece.starts_with("ab"), "");
+  static_assert(piece.starts_with("abc"), "");
+
+  static_assert(!piece.starts_with("b"), "");
+  static_assert(!piece.starts_with("bc"), "");
+
+  static_assert(!piece.starts_with("abcd"), "");
+}
+
+TEST(StringPieceTest, EndsWith) {
+  constexpr StringPiece piece("abc");
+
+  static_assert(piece.ends_with(""), "");
+  static_assert(piece.ends_with("c"), "");
+  static_assert(piece.ends_with("bc"), "");
+  static_assert(piece.ends_with("abc"), "");
+
+  static_assert(!piece.ends_with("a"), "");
+  static_assert(!piece.ends_with("ab"), "");
+
+  static_assert(!piece.ends_with("abcd"), "");
+}
+
 }  // namespace base
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc
index 67c1368..ec3f997 100644
--- a/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc
+++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager.cc
@@ -76,9 +76,8 @@
 
 class SchedulerWorkerDelegate : public SchedulerWorker::Delegate {
  public:
-  SchedulerWorkerDelegate(const std::string& thread_name,
-                          SchedulerWorker::ThreadLabel thread_label)
-      : thread_name_(thread_name), thread_label_(thread_label) {}
+  SchedulerWorkerDelegate(const std::string& thread_name)
+      : thread_name_(thread_name) {}
 
   void set_worker(SchedulerWorker* worker) {
     DCHECK(!worker_);
@@ -92,10 +91,6 @@
     worker_->WakeUp();
   }
 
-  SchedulerWorker::ThreadLabel GetThreadLabel() const final {
-    return thread_label_;
-  }
-
   void OnMainEntry(const SchedulerWorker* /* worker */) override {
     thread_ref_checker_.Set();
     PlatformThread::SetName(thread_name_);
@@ -154,7 +149,6 @@
 
  private:
   const std::string thread_name_;
-  const SchedulerWorker::ThreadLabel thread_label_;
 
   // The SchedulerWorker that has |this| as a delegate. Must be set before
   // starting or posting a task to the SchedulerWorker, because it's used in
@@ -177,9 +171,8 @@
 class SchedulerWorkerCOMDelegate : public SchedulerWorkerDelegate {
  public:
   SchedulerWorkerCOMDelegate(const std::string& thread_name,
-                             SchedulerWorker::ThreadLabel thread_label,
                              TrackedRef<TaskTracker> task_tracker)
-      : SchedulerWorkerDelegate(thread_name, thread_label),
+      : SchedulerWorkerDelegate(thread_name),
         task_tracker_(std::move(task_tracker)) {}
 
   ~SchedulerWorkerCOMDelegate() override { DCHECK(!scoped_com_initializer_); }
@@ -487,7 +480,7 @@
         worker_name += "Shared";
       worker_name += environment_params.name_suffix;
       worker = CreateAndRegisterSchedulerWorker<DelegateType>(
-          worker_name, thread_mode, environment_params.priority_hint);
+          worker_name, environment_params.priority_hint);
       new_worker = true;
     }
     started = started_;
@@ -526,28 +519,18 @@
 template <>
 std::unique_ptr<SchedulerWorkerDelegate>
 SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate<
-    SchedulerWorkerDelegate>(const std::string& name,
-                             int id,
-                             SingleThreadTaskRunnerThreadMode thread_mode) {
+    SchedulerWorkerDelegate>(const std::string& name, int id) {
   return std::make_unique<SchedulerWorkerDelegate>(
-      StringPrintf("TaskSchedulerSingleThread%s%d", name.c_str(), id),
-      thread_mode == SingleThreadTaskRunnerThreadMode::DEDICATED
-          ? SchedulerWorker::ThreadLabel::DEDICATED
-          : SchedulerWorker::ThreadLabel::SHARED);
+      StringPrintf("TaskSchedulerSingleThread%s%d", name.c_str(), id));
 }
 
 #if defined(OS_WIN)
 template <>
 std::unique_ptr<SchedulerWorkerDelegate>
 SchedulerSingleThreadTaskRunnerManager::CreateSchedulerWorkerDelegate<
-    SchedulerWorkerCOMDelegate>(const std::string& name,
-                                int id,
-                                SingleThreadTaskRunnerThreadMode thread_mode) {
+    SchedulerWorkerCOMDelegate>(const std::string& name, int id) {
   return std::make_unique<SchedulerWorkerCOMDelegate>(
       StringPrintf("TaskSchedulerSingleThreadCOMSTA%s%d", name.c_str(), id),
-      thread_mode == SingleThreadTaskRunnerThreadMode::DEDICATED
-          ? SchedulerWorker::ThreadLabel::DEDICATED_COM
-          : SchedulerWorker::ThreadLabel::SHARED_COM,
       task_tracker_);
 }
 #endif  // defined(OS_WIN)
@@ -556,12 +539,11 @@
 SchedulerWorker*
 SchedulerSingleThreadTaskRunnerManager::CreateAndRegisterSchedulerWorker(
     const std::string& name,
-    SingleThreadTaskRunnerThreadMode thread_mode,
     ThreadPriority priority_hint) {
   lock_.AssertAcquired();
   int id = next_worker_id_++;
   std::unique_ptr<SchedulerWorkerDelegate> delegate =
-      CreateSchedulerWorkerDelegate<DelegateType>(name, id, thread_mode);
+      CreateSchedulerWorkerDelegate<DelegateType>(name, id);
   SchedulerWorkerDelegate* delegate_raw = delegate.get();
   scoped_refptr<SchedulerWorker> worker = MakeRefCounted<SchedulerWorker>(
       priority_hint, std::move(delegate), task_tracker_);
diff --git a/base/task_scheduler/scheduler_single_thread_task_runner_manager.h b/base/task_scheduler/scheduler_single_thread_task_runner_manager.h
index 80b081c..f0b99d73 100644
--- a/base/task_scheduler/scheduler_single_thread_task_runner_manager.h
+++ b/base/task_scheduler/scheduler_single_thread_task_runner_manager.h
@@ -98,13 +98,11 @@
   template <typename DelegateType>
   std::unique_ptr<SchedulerWorkerDelegate> CreateSchedulerWorkerDelegate(
       const std::string& name,
-      int id,
-      SingleThreadTaskRunnerThreadMode thread_mode);
+      int id);
 
   template <typename DelegateType>
   SchedulerWorker* CreateAndRegisterSchedulerWorker(
       const std::string& name,
-      SingleThreadTaskRunnerThreadMode thread_mode,
       ThreadPriority priority_hint);
 
   template <typename DelegateType>
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc
index 123b3849..7111522 100644
--- a/base/task_scheduler/scheduler_worker.cc
+++ b/base/task_scheduler/scheduler_worker.cc
@@ -8,8 +8,6 @@
 
 #include <utility>
 
-#include "base/compiler_specific.h"
-#include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/task_scheduler/task_tracker.h"
 #include "base/trace_event/trace_event.h"
@@ -162,112 +160,6 @@
 }
 
 void SchedulerWorker::ThreadMain() {
-  if (priority_hint_ == ThreadPriority::BACKGROUND) {
-    switch (delegate_->GetThreadLabel()) {
-      case ThreadLabel::POOLED:
-        RunBackgroundPooledWorker();
-        return;
-      case ThreadLabel::SHARED:
-        RunBackgroundSharedWorker();
-        return;
-      case ThreadLabel::DEDICATED:
-        RunBackgroundDedicatedWorker();
-        return;
-#if defined(OS_WIN)
-      case ThreadLabel::SHARED_COM:
-        RunBackgroundSharedCOMWorker();
-        return;
-      case ThreadLabel::DEDICATED_COM:
-        RunBackgroundDedicatedCOMWorker();
-        return;
-#endif  // defined(OS_WIN)
-    }
-  }
-
-  switch (delegate_->GetThreadLabel()) {
-    case ThreadLabel::POOLED:
-      RunPooledWorker();
-      return;
-    case ThreadLabel::SHARED:
-      RunSharedWorker();
-      return;
-    case ThreadLabel::DEDICATED:
-      RunDedicatedWorker();
-      return;
-#if defined(OS_WIN)
-    case ThreadLabel::SHARED_COM:
-      RunSharedCOMWorker();
-      return;
-    case ThreadLabel::DEDICATED_COM:
-      RunDedicatedCOMWorker();
-      return;
-#endif  // defined(OS_WIN)
-  }
-}
-
-NOINLINE void SchedulerWorker::RunPooledWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunBackgroundPooledWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunSharedWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunBackgroundSharedWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunDedicatedWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunBackgroundDedicatedWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-#if defined(OS_WIN)
-NOINLINE void SchedulerWorker::RunSharedCOMWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunBackgroundSharedCOMWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunDedicatedCOMWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-
-NOINLINE void SchedulerWorker::RunBackgroundDedicatedCOMWorker() {
-  const int line_number = __LINE__;
-  RunWorker();
-  base::debug::Alias(&line_number);
-}
-#endif  // defined(OS_WIN)
-
-void SchedulerWorker::RunWorker() {
   DCHECK_EQ(self_, this);
   TRACE_EVENT_BEGIN0("task_scheduler", "SchedulerWorkerThread active");
 
diff --git a/base/task_scheduler/scheduler_worker.h b/base/task_scheduler/scheduler_worker.h
index b964b59..62257cd 100644
--- a/base/task_scheduler/scheduler_worker.h
+++ b/base/task_scheduler/scheduler_worker.h
@@ -44,19 +44,6 @@
     : public RefCountedThreadSafe<SchedulerWorker>,
       public PlatformThread::Delegate {
  public:
-  // Labels this SchedulerWorker's association. This doesn't affect any logic
-  // but will add a stack frame labeling this thread for ease of stack trace
-  // identification.
-  enum class ThreadLabel {
-    POOLED,
-    SHARED,
-    DEDICATED,
-#if defined(OS_WIN)
-    SHARED_COM,
-    DEDICATED_COM,
-#endif  // defined(OS_WIN)
-  };
-
   // Delegate interface for SchedulerWorker. All methods except
   // OnCanScheduleSequence() (inherited from CanScheduleSequenceObserver) are
   // called from the thread managed by the SchedulerWorker instance.
@@ -64,10 +51,6 @@
    public:
     ~Delegate() override = default;
 
-    // Returns the ThreadLabel the Delegate wants its SchedulerWorkers' stacks
-    // to be labeled with.
-    virtual ThreadLabel GetThreadLabel() const = 0;
-
     // Called by |worker|'s thread when it enters its main function.
     virtual void OnMainEntry(const SchedulerWorker* worker) = 0;
 
@@ -173,27 +156,6 @@
   // PlatformThread::Delegate:
   void ThreadMain() override;
 
-  // Dummy frames to act as "RunLabeledWorker()" (see RunMain() below). Their
-  // impl is aliased to prevent compiler/linker from optimizing them out.
-  void RunPooledWorker();
-  void RunBackgroundPooledWorker();
-  void RunSharedWorker();
-  void RunBackgroundSharedWorker();
-  void RunDedicatedWorker();
-  void RunBackgroundDedicatedWorker();
-#if defined(OS_WIN)
-  void RunSharedCOMWorker();
-  void RunBackgroundSharedCOMWorker();
-  void RunDedicatedCOMWorker();
-  void RunBackgroundDedicatedCOMWorker();
-#endif  // defined(OS_WIN)
-
-  // The real main, invoked through :
-  //     ThreadMain() -> RunLabeledWorker() -> RunWorker().
-  // "RunLabeledWorker()" is a dummy frame based on ThreadLabel+ThreadPriority
-  // and used to easily identify threads in stack traces.
-  void RunWorker();
-
   // Self-reference to prevent destruction of |this| while the thread is alive.
   // Set in Start() before creating the thread. Reset in ThreadMain() before the
   // thread exits. No lock required because the first access occurs before the
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.cc b/base/task_scheduler/scheduler_worker_pool_impl.cc
index eaed9c2..434f4d08 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task_scheduler/scheduler_worker_pool_impl.cc
@@ -73,7 +73,6 @@
 
   // SchedulerWorker::Delegate:
   void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override;
-  SchedulerWorker::ThreadLabel GetThreadLabel() const override;
   void OnMainEntry(const SchedulerWorker* worker) override;
   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override;
   void DidRunTask() override;
@@ -385,11 +384,6 @@
   outer_->OnCanScheduleSequence(std::move(sequence));
 }
 
-SchedulerWorker::ThreadLabel
-SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetThreadLabel() const {
-  return SchedulerWorker::ThreadLabel::POOLED;
-}
-
 void SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::OnMainEntry(
     const SchedulerWorker* worker) {
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
diff --git a/base/task_scheduler/scheduler_worker_stack_unittest.cc b/base/task_scheduler/scheduler_worker_stack_unittest.cc
index 8707874f..2908a558 100644
--- a/base/task_scheduler/scheduler_worker_stack_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_stack_unittest.cc
@@ -25,9 +25,6 @@
   void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override {
     ADD_FAILURE() << "Unexpected call to OnCanScheduleSequence().";
   }
-  SchedulerWorker::ThreadLabel GetThreadLabel() const override {
-    return SchedulerWorker::ThreadLabel::DEDICATED;
-  }
   void OnMainEntry(const SchedulerWorker* worker) override {}
   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
     return nullptr;
diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc
index 71642bf..0127ad0d 100644
--- a/base/task_scheduler/scheduler_worker_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_unittest.cc
@@ -53,9 +53,6 @@
   void OnCanScheduleSequence(scoped_refptr<Sequence> sequence) override {
     ADD_FAILURE() << "Unexpected call to OnCanScheduleSequence().";
   }
-  SchedulerWorker::ThreadLabel GetThreadLabel() const override {
-    return SchedulerWorker::ThreadLabel::DEDICATED;
-  }
   void OnMainEntry(const SchedulerWorker* worker) override {}
   scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override {
     return nullptr;
diff --git a/base/task_scheduler/task_scheduler_impl_unittest.cc b/base/task_scheduler/task_scheduler_impl_unittest.cc
index d3674f5d..89640cf 100644
--- a/base/task_scheduler/task_scheduler_impl_unittest.cc
+++ b/base/task_scheduler/task_scheduler_impl_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
-#include "base/debug/stack_trace.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
@@ -642,83 +641,5 @@
   EXPECT_TRUE(called_back);
 }
 
-namespace {
-
-// Verifies that |query| is found on the current stack. Ignores failures if this
-// configuration doesn't have symbols.
-void VerifyHasStringOnStack(const std::string& query) {
-  const std::string stack = debug::StackTrace().ToString();
-  SCOPED_TRACE(stack);
-  const bool found_on_stack = stack.find(query) != std::string::npos;
-  const bool stack_has_symbols =
-      stack.find("SchedulerWorker") != std::string::npos;
-  EXPECT_TRUE(found_on_stack || !stack_has_symbols) << query;
-}
-
-}  // namespace
-
-// Integration test that verifies that workers have a frame on their stacks
-// which easily identifies the type of worker (useful to diagnose issues from
-// logs without memory dumps).
-TEST_F(TaskSchedulerImplTest, IdentifiableStacks) {
-  StartTaskScheduler();
-
-  scheduler_.CreateSequencedTaskRunnerWithTraits({})->PostTask(
-      FROM_HERE, BindOnce(&VerifyHasStringOnStack, "RunPooledWorker"));
-  scheduler_.CreateSequencedTaskRunnerWithTraits({TaskPriority::BACKGROUND})
-      ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
-                                     "RunBackgroundPooledWorker"));
-
-  scheduler_
-      .CreateSingleThreadTaskRunnerWithTraits(
-          {}, SingleThreadTaskRunnerThreadMode::SHARED)
-      ->PostTask(FROM_HERE,
-                 BindOnce(&VerifyHasStringOnStack, "RunSharedWorker"));
-  scheduler_
-      .CreateSingleThreadTaskRunnerWithTraits(
-          {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED)
-      ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
-                                     "RunBackgroundSharedWorker"));
-
-  scheduler_
-      .CreateSingleThreadTaskRunnerWithTraits(
-          {}, SingleThreadTaskRunnerThreadMode::DEDICATED)
-      ->PostTask(FROM_HERE,
-                 BindOnce(&VerifyHasStringOnStack, "RunDedicatedWorker"));
-  scheduler_
-      .CreateSingleThreadTaskRunnerWithTraits(
-          {TaskPriority::BACKGROUND},
-          SingleThreadTaskRunnerThreadMode::DEDICATED)
-      ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
-                                     "RunBackgroundDedicatedWorker"));
-
-#if defined(OS_WIN)
-  scheduler_
-      .CreateCOMSTATaskRunnerWithTraits(
-          {}, SingleThreadTaskRunnerThreadMode::SHARED)
-      ->PostTask(FROM_HERE,
-                 BindOnce(&VerifyHasStringOnStack, "RunSharedCOMWorker"));
-  scheduler_
-      .CreateCOMSTATaskRunnerWithTraits(
-          {TaskPriority::BACKGROUND}, SingleThreadTaskRunnerThreadMode::SHARED)
-      ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
-                                     "RunBackgroundSharedCOMWorker"));
-
-  scheduler_
-      .CreateCOMSTATaskRunnerWithTraits(
-          {}, SingleThreadTaskRunnerThreadMode::DEDICATED)
-      ->PostTask(FROM_HERE,
-                 BindOnce(&VerifyHasStringOnStack, "RunDedicatedCOMWorker"));
-  scheduler_
-      .CreateCOMSTATaskRunnerWithTraits(
-          {TaskPriority::BACKGROUND},
-          SingleThreadTaskRunnerThreadMode::DEDICATED)
-      ->PostTask(FROM_HERE, BindOnce(&VerifyHasStringOnStack,
-                                     "RunBackgroundDedicatedCOMWorker"));
-#endif  // defined(OS_WIN)
-
-  scheduler_.FlushForTesting();
-}
-
 }  // namespace internal
 }  // namespace base
diff --git a/base/test/OWNERS b/base/test/OWNERS
index 8b59305..68077483 100644
--- a/base/test/OWNERS
+++ b/base/test/OWNERS
@@ -1,10 +1,13 @@
 per-file *task_scheduler*=file://base/task_scheduler/OWNERS
 
-# Metrics-related test utilties:
+# Metrics-related test utilites:
 per-file *histogram_tester*=file://base/metrics/OWNERS
 per-file *scoped_feature_list*=file://base/metrics/OWNERS
 per-file *user_action_tester*=file://base/metrics/OWNERS
 
+# Tracing test utilities:
+per-file trace_*=file://base/trace_event/OWNERS
+
 # For Android-specific changes:
 per-file *android*=file://base/test/android/OWNERS
 per-file BUILD.gn=file://base/test/android/OWNERS
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
index 54ced40..d0b1850b 100644
--- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
+++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
@@ -134,7 +134,7 @@
 
         if (sConnectionAllocator == null) {
             sConnectionAllocator = ChildConnectionAllocator.create(
-                    ContextUtils.getApplicationContext(), sLauncherHandler,
+                    ContextUtils.getApplicationContext(), sLauncherHandler, null,
                     "org.chromium.native_test", "org.chromium.base.MultiprocessTestClientService",
                     "org.chromium.native_test.NUM_TEST_CLIENT_SERVICES", false /* bindToCaller */,
                     false /* bindAsExternalService */, false /* useStrongBinding */);
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index a822aee..cab2899 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -110,6 +110,19 @@
     return false;
   }
 
+  dictionary->GetDouble("tdur", &thread_duration);
+  dictionary->GetDouble("tts", &thread_timestamp);
+  dictionary->GetString("scope", &scope);
+  dictionary->GetString("bind_id", &bind_id);
+  dictionary->GetBoolean("flow_out", &flow_out);
+  dictionary->GetBoolean("flow_in", &flow_in);
+
+  const base::DictionaryValue* id2;
+  if (dictionary->GetDictionary("id2", &id2)) {
+    id2->GetString("global", &global_id2);
+    id2->GetString("local", &local_id2);
+  }
+
   // For each argument, copy the type and create a trace_analyzer::TraceValue.
   for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
        it.Advance()) {
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
index ea716bc3..dcdd2e4 100644
--- a/base/test/trace_event_analyzer.h
+++ b/base/test/trace_event_analyzer.h
@@ -182,6 +182,14 @@
   std::string category;
   std::string name;
   std::string id;
+  double thread_duration = 0.0;
+  double thread_timestamp = 0.0;
+  std::string scope;
+  std::string bind_id;
+  bool flow_out = false;
+  bool flow_in = false;
+  std::string global_id2;
+  std::string local_id2;
 
   // All numbers and bool values from TraceEvent args are cast to double.
   // bool becomes 1.0 (true) or 0.0 (false).
@@ -507,7 +515,6 @@
   // This is a recursive method that walks the query tree.
   bool Evaluate(const TraceEvent& event) const;
 
- private:
   enum TraceEventMember {
     EVENT_INVALID,
     EVENT_PID,
@@ -646,6 +653,7 @@
   const Query& left() const;
   const Query& right() const;
 
+ private:
   QueryType type_;
   Operator operator_;
   scoped_refptr<QueryNode> left_;
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 4bf3e83..b1c67b1 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -142,6 +142,10 @@
 
   const char* name() const { return name_; }
 
+  unsigned char arg_type(size_t index) const { return arg_types_[index]; }
+  const char* arg_name(size_t index) const { return arg_names_[index]; }
+  const TraceValue& arg_value(size_t index) const { return arg_values_[index]; }
+
 #if defined(OS_ANDROID)
   void SendToATrace();
 #endif
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index 9e97b7ae..c63be913 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-5e56edb6c1a07d13fcab888cc5e2a753a61af349
\ No newline at end of file
+f5a0f7997831243e9b67627a6616e9e928c20736
\ No newline at end of file
diff --git a/cc/animation/worklet_animation.cc b/cc/animation/worklet_animation.cc
index 5a79260b..a905b94ce 100644
--- a/cc/animation/worklet_animation.cc
+++ b/cc/animation/worklet_animation.cc
@@ -11,11 +11,13 @@
 WorkletAnimation::WorkletAnimation(
     int id,
     const std::string& name,
-    std::unique_ptr<ScrollTimeline> scroll_timeline)
+    std::unique_ptr<ScrollTimeline> scroll_timeline,
+    bool is_controlling_instance)
     : SingleKeyframeEffectAnimation(id),
       name_(name),
       scroll_timeline_(std::move(scroll_timeline)),
-      last_current_time_(base::nullopt) {}
+      last_current_time_(base::nullopt),
+      is_impl_instance_(is_controlling_instance) {}
 
 WorkletAnimation::~WorkletAnimation() = default;
 
@@ -24,7 +26,7 @@
     const std::string& name,
     std::unique_ptr<ScrollTimeline> scroll_timeline) {
   return WrapRefCounted(
-      new WorkletAnimation(id, name, std::move(scroll_timeline)));
+      new WorkletAnimation(id, name, std::move(scroll_timeline), false));
 }
 
 scoped_refptr<Animation> WorkletAnimation::CreateImplInstance() const {
@@ -33,7 +35,7 @@
     impl_timeline = scroll_timeline_->CreateImplInstance();
 
   return WrapRefCounted(
-      new WorkletAnimation(id(), name(), std::move(impl_timeline)));
+      new WorkletAnimation(id(), name(), std::move(impl_timeline), true));
 }
 
 void WorkletAnimation::SetLocalTime(base::TimeDelta local_time) {
@@ -42,6 +44,10 @@
 }
 
 void WorkletAnimation::Tick(base::TimeTicks monotonic_time) {
+  // Do not tick worklet animations on main thread. This should be removed if we
+  // skip ticking all animations on main thread in http://crbug.com/762717.
+  if (!is_impl_instance_)
+    return;
   // As the output of a WorkletAnimation is driven by a script-provided local
   // time, we don't want the underlying effect to participate in the normal
   // animations lifecycle. To avoid this we pause the underlying keyframe effect
diff --git a/cc/animation/worklet_animation.h b/cc/animation/worklet_animation.h
index d98ee88..cdde572 100644
--- a/cc/animation/worklet_animation.h
+++ b/cc/animation/worklet_animation.h
@@ -23,7 +23,8 @@
  public:
   WorkletAnimation(int id,
                    const std::string& name,
-                   std::unique_ptr<ScrollTimeline> scroll_timeline);
+                   std::unique_ptr<ScrollTimeline> scroll_timeline,
+                   bool is_controlling_instance);
   static scoped_refptr<WorkletAnimation> Create(
       int id,
       const std::string& name,
@@ -66,6 +67,8 @@
   base::TimeDelta local_time_;
 
   base::Optional<double> last_current_time_;
+
+  bool is_impl_instance_;
 };
 
 }  // namespace cc
diff --git a/cc/animation/worklet_animation_unittest.cc b/cc/animation/worklet_animation_unittest.cc
index e112fb4..5e3020b 100644
--- a/cc/animation/worklet_animation_unittest.cc
+++ b/cc/animation/worklet_animation_unittest.cc
@@ -75,6 +75,10 @@
   worklet_animation_impl_->SetLocalTime(local_time);
 
   TickAnimationsTransferEvents(base::TimeTicks(), 0u);
+
+  TestLayer* layer =
+      client_.FindTestLayer(element_id_, ElementListType::ACTIVE);
+  EXPECT_FALSE(layer->is_property_mutated(TargetProperty::OPACITY));
   client_impl_.ExpectOpacityPropertyMutated(
       element_id_, ElementListType::ACTIVE, expected_opacity);
 }
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 8548d81a..6bc62e0 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -36,12 +36,9 @@
 
 namespace cc_blink {
 
-WebLayerImpl::WebLayerImpl()
-    : layer_(Layer::Create()), contents_opaque_is_fixed_(false) {}
+WebLayerImpl::WebLayerImpl() : layer_(Layer::Create()) {}
 
-WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer)
-    : layer_(layer), contents_opaque_is_fixed_(false) {
-}
+WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) : layer_(layer) {}
 
 WebLayerImpl::~WebLayerImpl() = default;
 
@@ -129,8 +126,6 @@
 }
 
 void WebLayerImpl::SetOpaque(bool opaque) {
-  if (contents_opaque_is_fixed_)
-    return;
   layer_->SetContentsOpaque(opaque);
 }
 
@@ -369,10 +364,6 @@
   return layer_.get();
 }
 
-void WebLayerImpl::SetContentsOpaqueIsFixed(bool fixed) {
-  contents_opaque_is_fixed_ = fixed;
-}
-
 void WebLayerImpl::SetHasWillChangeTransformHint(bool has_will_change) {
   layer_->SetHasWillChangeTransformHint(has_will_change);
 }
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index 2c6107f..1f0f445 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -52,7 +52,6 @@
   void SetMaskLayer(blink::WebLayer* mask) override;
   void SetOpacity(float opacity) override;
   float Opacity() const override;
-  void SetContentsOpaqueIsFixed(bool fixed) override;
 
   void SetBlendMode(SkBlendMode blend_mode) override;
   SkBlendMode BlendMode() const override;
@@ -129,8 +128,6 @@
  protected:
   scoped_refptr<cc::Layer> layer_;
 
-  bool contents_opaque_is_fixed_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(WebLayerImpl);
 };
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 3c898c8..3d73714 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -65,6 +65,20 @@
       grand_child->layer_tree_host()->LayerNeedsPushPropertiesForTesting(   \
           grand_child.get()));
 
+#define EXECUTE_AND_VERIFY_SUBTREE_NOT_CHANGED(code_to_test)                 \
+  code_to_test;                                                              \
+  root->layer_tree_host()->BuildPropertyTreesForTesting();                   \
+  EXPECT_FALSE(root->subtree_property_changed());                            \
+  EXPECT_FALSE(root->layer_tree_host()->LayerNeedsPushPropertiesForTesting(  \
+      root.get()));                                                          \
+  EXPECT_FALSE(child->subtree_property_changed());                           \
+  EXPECT_FALSE(child->layer_tree_host()->LayerNeedsPushPropertiesForTesting( \
+      child.get()));                                                         \
+  EXPECT_FALSE(grand_child->subtree_property_changed());                     \
+  EXPECT_FALSE(                                                              \
+      grand_child->layer_tree_host()->LayerNeedsPushPropertiesForTesting(    \
+          grand_child.get()));
+
 #define EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(code_to_test)               \
   code_to_test;                                                              \
   EXPECT_FALSE(root->subtree_property_changed());                            \
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 3b1e14c4..efac77af 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -1345,16 +1345,8 @@
                     image_info.minRowBytes());
 
     // Set |pixmap| to the desired colorspace to decode into.
-    if (!SupportsColorSpaceConversion()) {
-      pixmap.setColorSpace(nullptr);
-    } else if (image_data->mode == DecodedDataMode::kCpu) {
-      pixmap.setColorSpace(draw_image.target_color_space().ToSkColorSpace());
-    } else {
-      // For kGpu or kTransferCache images color conversion is handled during
-      // upload, so keep the original colorspace here.
-      pixmap.setColorSpace(sk_ref_sp(draw_image.paint_image().color_space()));
-    }
-
+    pixmap.setColorSpace(
+        ColorSpaceForImageDecode(draw_image, image_data->mode));
     if (!DrawAndScaleImage(draw_image, &pixmap)) {
       DLOG(ERROR) << "DrawAndScaleImage failed.";
       backing_memory->Unlock();
@@ -1514,14 +1506,24 @@
   }
 
   size_t data_size = image_info.computeMinByteSize();
+
+  // We need to cache the result of color conversion on the cpu if the image
+  // will be color converted during the decode.
+  auto decode_color_space = ColorSpaceForImageDecode(draw_image, mode);
+  const bool cache_color_conversion_on_cpu =
+      decode_color_space &&
+      !SkColorSpace::Equals(decode_color_space.get(),
+                            draw_image.paint_image().color_space());
+
   // |is_bitmap_backed| specifies whether the image has pixel data which can
   // directly be used for the upload. This will be the case for non-lazy images
   // used at the original scale. In these cases, we don't internally cache any
   // cpu component for the image.
-  // However, if the image will be scaled, we consider it a lazy image and cache
-  // the scaled result in discardable memory.
-  const bool is_bitmap_backed =
-      !draw_image.paint_image().IsLazyGenerated() && mip_level == 0;
+  // However, if the image will be scaled or color converts on the cpu, we
+  // consider it a lazy image and cache the scaled result in discardable memory.
+  const bool is_bitmap_backed = !draw_image.paint_image().IsLazyGenerated() &&
+                                mip_level == 0 &&
+                                !cache_color_conversion_on_cpu;
   return base::WrapRefCounted(new ImageData(
       mode, data_size, draw_image.target_color_space(),
       CalculateDesiredFilterQuality(draw_image), mip_level, is_bitmap_backed));
@@ -1818,6 +1820,20 @@
   }
 }
 
+sk_sp<SkColorSpace> GpuImageDecodeCache::ColorSpaceForImageDecode(
+    const DrawImage& image,
+    DecodedDataMode mode) const {
+  if (!SupportsColorSpaceConversion())
+    return nullptr;
+
+  if (mode == DecodedDataMode::kCpu)
+    return image.target_color_space().ToSkColorSpace();
+
+  // For kGpu or kTransferCache images color conversion is handled during
+  // upload, so keep the original colorspace here.
+  return sk_ref_sp(image.paint_image().color_space());
+}
+
 void GpuImageDecodeCache::CheckContextLockAcquiredIfNecessary() {
   if (!context_->GetLock())
     return;
diff --git a/cc/tiles/gpu_image_decode_cache.h b/cc/tiles/gpu_image_decode_cache.h
index 8063575..90374d7a 100644
--- a/cc/tiles/gpu_image_decode_cache.h
+++ b/cc/tiles/gpu_image_decode_cache.h
@@ -426,6 +426,9 @@
 
   void CheckContextLockAcquiredIfNecessary();
 
+  sk_sp<SkColorSpace> ColorSpaceForImageDecode(const DrawImage& image,
+                                               DecodedDataMode mode) const;
+
   // |persistent_cache_| represents the long-lived cache, keeping a certain
   // budget of ImageDatas alive even when their ref count reaches zero.
   using PersistentCache = base::HashingMRUCache<PaintImage::FrameKey,
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index c304be03..91fc94f 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -2301,6 +2301,36 @@
   cache->UnrefImage(draw_image);
 }
 
+TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) {
+  auto cache = CreateCache();
+  const bool should_cache_sw_image =
+      cache->SupportsColorSpaceConversion() && !use_transfer_cache_;
+
+  bool is_decomposable = true;
+  SkFilterQuality quality = kHigh_SkFilterQuality;
+
+  PaintImage image = CreateBitmapImage(gfx::Size(10, 24000));
+  DrawImage draw_image(
+      image, SkIRect::MakeWH(image.width(), image.height()), quality,
+      CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+      PaintImage::kDefaultFrameIndex, gfx::ColorSpace::CreateDisplayP3D65());
+  viz::ContextProvider::ScopedContextLock context_lock(context_provider());
+  DecodedDrawImage decoded_draw_image =
+      EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+  EXPECT_TRUE(decoded_draw_image.image());
+  EXPECT_TRUE(decoded_draw_image.is_budgeted());
+  cache->DrawWithImageFinished(draw_image, decoded_draw_image);
+  // For non-lazy images color converted during scaling, cpu component should be
+  // cached.
+  auto sw_image = cache->GetSWImageDecodeForTesting(draw_image);
+  ASSERT_EQ(!!sw_image, should_cache_sw_image);
+  if (should_cache_sw_image) {
+    EXPECT_TRUE(SkColorSpace::Equals(
+        sw_image->colorSpace(),
+        gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace().get()));
+  }
+}
+
 TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) {
   auto cache = CreateCache();
   bool is_decomposable = true;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 6caae2e0..a8772a5c3 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1892,6 +1892,12 @@
       gfx::ScrollOffsetToVector2dF(active_tree_->TotalScrollOffset());
   metadata.root_background_color = active_tree_->background_color();
   metadata.is_scroll_offset_at_top = active_tree_->TotalScrollOffset().y() == 0;
+  metadata.device_scale_factor = active_tree_->painted_device_scale_factor() *
+                                 active_tree_->device_scale_factor();
+  metadata.viewport_size_in_pixels = device_viewport_size();
+  if (active_tree()->local_surface_id().is_valid())
+    metadata.local_surface_id = active_tree()->local_surface_id();
+
   active_tree_->GetViewportSelection(&metadata.selection);
   metadata.is_mobile_optimized = IsMobileOptimized(active_tree_.get());
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 82d50cc8..4aab626 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -531,7 +531,9 @@
   ManagedMemoryPolicy ActualManagedMemoryPolicy() const;
 
   void SetViewportSize(const gfx::Size& device_viewport_size);
-  gfx::Size device_viewport_size() const { return device_viewport_size_; }
+  const gfx::Size& device_viewport_size() const {
+    return device_viewport_size_;
+  }
 
   void SetViewportVisibleRect(const gfx::Rect& visible_rect);
   gfx::Rect viewport_visible_rect() const { return viewport_visible_rect_; }
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 410e493..34cc3a3 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -65,6 +65,7 @@
 #include "components/viz/service/display/output_surface.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "components/viz/test/fake_output_surface.h"
+#include "components/viz/test/test_gles2_interface.h"
 #include "components/viz/test/test_layer_tree_frame_sink.h"
 #include "components/viz/test/test_web_graphics_context_3d.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -8143,8 +8144,30 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSubmitFrameMetadata);
 
+class VideoGLES2Interface : public viz::TestGLES2Interface {
+ public:
+  VideoGLES2Interface() = default;
+
+  void InitializeTestContext(viz::TestWebGraphicsContext3D* context) override {
+    context->set_have_extension_egl_image(true);
+  }
+};
+
 class LayerTreeHostTestSubmitFrameResources : public LayerTreeHostTest {
  protected:
+  std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+      const viz::RendererSettings& renderer_settings,
+      double refresh_rate,
+      scoped_refptr<viz::ContextProvider> compositor_context_provider,
+      scoped_refptr<viz::RasterContextProvider> worker_context_provider)
+      override {
+    auto provider = viz::TestContextProvider::Create(
+        std::make_unique<VideoGLES2Interface>());
+    return LayerTreeTest::CreateLayerTreeFrameSink(
+        renderer_settings, refresh_rate, std::move(provider),
+        std::move(worker_context_provider));
+  }
+
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 7aab1e5f..66d838c5 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -34,6 +34,7 @@
 #include "cc/trees/single_thread_proxy.h"
 #include "components/viz/common/resources/single_release_callback.h"
 #include "components/viz/test/test_context_provider.h"
+#include "components/viz/test/test_gles2_interface.h"
 #include "components/viz/test/test_layer_tree_frame_sink.h"
 #include "components/viz/test/test_shared_bitmap_manager.h"
 #include "components/viz/test/test_web_graphics_context_3d.h"
@@ -51,12 +52,27 @@
   return base::TimeTicks() + base::TimeDelta::FromMicroseconds(micros);
 }
 
+class IOSurfaceGLES2Interface : public viz::TestGLES2Interface {
+ public:
+  explicit IOSurfaceGLES2Interface(bool context_should_support_io_surface)
+      : context_should_support_io_surface_(context_should_support_io_surface) {}
+
+  void InitializeTestContext(viz::TestWebGraphicsContext3D* context) override {
+    if (context_should_support_io_surface_) {
+      context->set_have_extension_io_surface(true);
+      context->set_have_extension_egl_image(true);
+    }
+  }
+
+ private:
+  bool context_should_support_io_surface_;
+};
+
 // These tests deal with losing the 3d graphics context.
 class LayerTreeHostContextTest : public LayerTreeTest {
  public:
   LayerTreeHostContextTest()
       : LayerTreeTest(),
-        context3d_(nullptr),
         times_to_fail_create_(0),
         times_to_lose_during_commit_(0),
         times_to_lose_during_draw_(0),
@@ -72,15 +88,15 @@
 
   void LoseContext() {
     // CreateDisplayLayerTreeFrameSink happens on a different thread, so lock
-    // context3d_ to make sure we don't set it to null after recreating it
+    // gl_ to make sure we don't set it to null after recreating it
     // there.
-    base::AutoLock lock(context3d_lock_);
+    base::AutoLock lock(gl_lock_);
     // For sanity-checking tests, they should only call this when the
     // context is not lost.
-    CHECK(context3d_);
-    context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                                    GL_INNOCENT_CONTEXT_RESET_ARB);
-    context3d_ = nullptr;
+    CHECK(gl_);
+    gl_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                             GL_INNOCENT_CONTEXT_RESET_ARB);
+    gl_ = nullptr;
   }
 
   std::unique_ptr<viz::TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
@@ -89,26 +105,22 @@
       scoped_refptr<viz::ContextProvider> compositor_context_provider,
       scoped_refptr<viz::RasterContextProvider> worker_context_provider)
       override {
-    base::AutoLock lock(context3d_lock_);
+    base::AutoLock lock(gl_lock_);
 
-    std::unique_ptr<viz::TestWebGraphicsContext3D> compositor_context3d =
-        viz::TestWebGraphicsContext3D::Create();
-    if (context_should_support_io_surface_) {
-      compositor_context3d->set_have_extension_io_surface(true);
-      compositor_context3d->set_have_extension_egl_image(true);
-    }
-    context3d_ = compositor_context3d.get();
+    auto gl_owned = std::make_unique<IOSurfaceGLES2Interface>(
+        context_should_support_io_surface_);
+    gl_ = gl_owned.get();
 
+    auto provider = viz::TestContextProvider::Create(std::move(gl_owned));
     if (times_to_fail_create_) {
       --times_to_fail_create_;
       ExpectCreateToFail();
-      context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                                      GL_INNOCENT_CONTEXT_RESET_ARB);
+      gl_->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                               GL_INNOCENT_CONTEXT_RESET_ARB);
     }
 
     return LayerTreeTest::CreateLayerTreeFrameSink(
-        renderer_settings, refresh_rate,
-        viz::TestContextProvider::Create(std::move(compositor_context3d)),
+        renderer_settings, refresh_rate, std::move(provider),
         std::move(worker_context_provider));
   }
 
@@ -158,10 +170,10 @@
   void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
 
  protected:
-  // Protects use of context3d_ so LoseContext and
+  // Protects use of gl_ so LoseContext and
   // CreateDisplayLayerTreeFrameSink can both use it on different threads.
-  base::Lock context3d_lock_;
-  viz::TestWebGraphicsContext3D* context3d_;
+  base::Lock gl_lock_;
+  viz::TestGLES2Interface* gl_ = nullptr;
 
   int times_to_fail_create_;
   int times_to_lose_during_commit_;
@@ -1008,7 +1020,7 @@
     if (host_impl->active_tree()->source_frame_number() == 2) {
       // Lose the context after draw on the second commit. This will cause
       // a third commit to recover.
-      context3d_->set_times_bind_texture_succeeds(0);
+      gl_->set_times_bind_texture_succeeds(0);
     }
     return draw_result;
   }
@@ -1480,7 +1492,7 @@
   void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl, bool visible) override {
     if (!visible) {
       // All resources should have been evicted.
-      ASSERT_EQ(0u, context3d_->NumTextures());
+      ASSERT_EQ(0u, gl_->NumTextures());
       EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
       EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
       EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource3_->id()));
@@ -1500,7 +1512,7 @@
       case 1:
         // The first two resources should have been created on LTHI after the
         // commit.
-        ASSERT_EQ(2u, context3d_->NumTextures());
+        ASSERT_EQ(2u, gl_->NumTextures());
         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
         EXPECT_EQ(1, ui_resource_->resource_create_count);
@@ -1508,7 +1520,7 @@
         EXPECT_TRUE(impl->CanDraw());
         // Evict all UI resources. This will trigger a commit.
         impl->EvictAllUIResources();
-        ASSERT_EQ(0u, context3d_->NumTextures());
+        ASSERT_EQ(0u, gl_->NumTextures());
         EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
         EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
         EXPECT_EQ(1, ui_resource_->resource_create_count);
@@ -1517,7 +1529,7 @@
         break;
       case 2:
         // The first two resources should have been recreated.
-        ASSERT_EQ(2u, context3d_->NumTextures());
+        ASSERT_EQ(2u, gl_->NumTextures());
         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
         EXPECT_EQ(2, ui_resource_->resource_create_count);
         EXPECT_EQ(1, ui_resource_->lost_resource_count);
@@ -1529,7 +1541,7 @@
       case 3:
         // The first resource should have been recreated after visibility was
         // restored.
-        ASSERT_EQ(2u, context3d_->NumTextures());
+        ASSERT_EQ(2u, gl_->NumTextures());
         EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
         EXPECT_EQ(3, ui_resource_->resource_create_count);
         EXPECT_EQ(2, ui_resource_->lost_resource_count);
diff --git a/cc/trees/render_frame_metadata.cc b/cc/trees/render_frame_metadata.cc
index 9283520..2559925 100644
--- a/cc/trees/render_frame_metadata.cc
+++ b/cc/trees/render_frame_metadata.cc
@@ -22,7 +22,10 @@
   return rfm1.root_background_color != rfm2.root_background_color ||
          rfm1.is_scroll_offset_at_top != rfm2.is_scroll_offset_at_top ||
          rfm1.selection != rfm2.selection ||
-         rfm1.is_mobile_optimized != rfm2.is_mobile_optimized;
+         rfm1.is_mobile_optimized != rfm2.is_mobile_optimized ||
+         rfm1.device_scale_factor != rfm2.device_scale_factor ||
+         rfm1.viewport_size_in_pixels != rfm2.viewport_size_in_pixels ||
+         rfm1.local_surface_id != rfm2.local_surface_id;
 }
 
 RenderFrameMetadata& RenderFrameMetadata::operator=(
@@ -36,7 +39,10 @@
          root_background_color == other.root_background_color &&
          is_scroll_offset_at_top == other.is_scroll_offset_at_top &&
          selection == other.selection &&
-         is_mobile_optimized == other.is_mobile_optimized;
+         is_mobile_optimized == other.is_mobile_optimized &&
+         device_scale_factor == other.device_scale_factor &&
+         viewport_size_in_pixels == other.viewport_size_in_pixels &&
+         local_surface_id == other.local_surface_id;
 }
 
 bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) {
diff --git a/cc/trees/render_frame_metadata.h b/cc/trees/render_frame_metadata.h
index 98013a2..c76d498 100644
--- a/cc/trees/render_frame_metadata.h
+++ b/cc/trees/render_frame_metadata.h
@@ -8,7 +8,9 @@
 #include "base/optional.h"
 #include "cc/cc_export.h"
 #include "components/viz/common/quads/selection.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/gfx/selection_bound.h"
 
@@ -55,6 +57,15 @@
   // - page prevents zooming in or out (i.e. min and max page scale factors
   // are the same).
   bool is_mobile_optimized = false;
+
+  // The device scale factor used to generate a CompositorFrame.
+  float device_scale_factor = 1.f;
+
+  // The size of the viewport used to generate a CompositorFrame.
+  gfx::Size viewport_size_in_pixels;
+
+  // The last viz::LocalSurfaceId used to submit a CompositorFrame.
+  base::Optional<viz::LocalSurfaceId> local_surface_id;
 };
 
 }  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index 610b552..bc1886a 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=68
 MINOR=0
-BUILD=3421
+BUILD=3423
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeHomeFeedbackSource.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeHomeFeedbackSource.java
deleted file mode 100644
index a9bf26da..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeHomeFeedbackSource.java
+++ /dev/null
@@ -1,39 +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.feedback;
-
-import android.util.Pair;
-
-import org.chromium.base.CollectionUtil;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.util.FeatureUtilities;
-
-import java.util.Map;
-
-/** Grabs feedback about the current opt-in/out state of Chrome Home. */
-class ChromeHomeFeedbackSource implements FeedbackSource {
-    /** A user visible string describing Chrome Home's current enabled state. */
-    @VisibleForTesting
-    static final String CHROME_HOME_STATE_KEY = "Chrome Home State";
-    private static final String CHROME_HOME_ENABLED_VALUE = "Enabled";
-    private static final String CHROME_HOME_DISABLED_VALUE = "Disabled";
-
-    private final boolean mIsOffTheRecord;
-
-    ChromeHomeFeedbackSource(Profile profile) {
-        mIsOffTheRecord = profile.isOffTheRecord();
-    }
-
-    @Override
-    public Map<String, String> getFeedback() {
-        if (mIsOffTheRecord) return null;
-
-        String value = FeatureUtilities.isChromeHomeEnabled() ? CHROME_HOME_ENABLED_VALUE
-                                                              : CHROME_HOME_DISABLED_VALUE;
-
-        return CollectionUtil.newHashMap(Pair.create(CHROME_HOME_STATE_KEY, value));
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java
index 363cc24..6991b90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java
@@ -80,7 +80,6 @@
         sources.add(new VariationsFeedbackSource(profile));
         sources.add(new DataReductionProxyFeedbackSource(profile));
         sources.add(new HistogramFeedbackSource(profile));
-        sources.add(new ChromeHomeFeedbackSource(profile));
         sources.add(new LowEndDeviceFeedbackSource());
         sources.add(new IMEFeedbackSource());
         sources.add(new PermissionFeedbackSource());
@@ -225,4 +224,4 @@
         CollectionUtil.forEach(mSynchronousSources, worker);
         CollectionUtil.forEach(mAsynchronousSources, worker);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java
index ae134398..355c3265 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfo.java
@@ -112,8 +112,6 @@
     public Boolean isContextMenuItemSupported(@ContextMenuItemId int menuItemId) {
         if (menuItemId == ContextMenuManager.ID_REMOVE) return null;
 
-        if (mCategory == KnownCategories.RECENT_TABS) return false;
-
         if (mCategory == KnownCategories.DOWNLOADS) {
             if (menuItemId == ContextMenuManager.ID_OPEN_IN_INCOGNITO_TAB) return false;
             if (menuItemId == ContextMenuManager.ID_SAVE_FOR_OFFLINE) return false;
@@ -137,7 +135,7 @@
                 navigationDelegate.navigateToRecentTabs();
                 break;
             case KnownCategories.PHYSICAL_WEB_PAGES_DEPRECATED:
-            case KnownCategories.RECENT_TABS:
+            case KnownCategories.RECENT_TABS_DEPRECATED:
             case KnownCategories.ARTICLES:
             default:
                 Log.wtf(TAG, "'Empty State' action called for unsupported category: %d", mCategory);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
index 61f4be50..65bc4601 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
@@ -242,30 +242,7 @@
 
     @Override
     public boolean requiresExactOfflinePage() {
-        return isDownload() || isRecentTab();
-    }
-
-    public boolean isRecentTab() {
-        return mCategory == KnownCategories.RECENT_TABS;
-    }
-
-    /**
-     * @return the corresponding recent tab id. May only be called if this snippet is a recent tab
-     * article.
-     */
-    public int getRecentTabId() {
-        assert isRecentTab();
-        return mRecentTabId;
-    }
-
-    /**
-     * Sets tab id and offline page id for recent tab articles. May only be called if this snippet
-     * is a recent tab article.
-     */
-    public void setRecentTabData(int tabId, long offlinePageId) {
-        assert isRecentTab();
-        mRecentTabId = tabId;
-        setOfflinePageOfflineId(offlinePageId);
+        return isDownload();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index 6594ff7..97d3923 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -219,12 +219,6 @@
     }
 
     @CalledByNative
-    private static void setRecentTabDataForSuggestion(
-            SnippetArticle suggestion, int tabId, long offlinePageId) {
-        suggestion.setRecentTabData(tabId, offlinePageId);
-    }
-
-    @CalledByNative
     private static SuggestionsCategoryInfo createSuggestionsCategoryInfo(int category, String title,
             @ContentSuggestionsCardLayout int cardLayout,
             @ContentSuggestionsAdditionalAction int additionalAction, boolean showIfEmpty,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 505c95c..ad6c9fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -612,21 +612,11 @@
         return nativeIsShowingDownloadButtonInErrorPage(mNativeOfflinePageBridge, webContents);
     }
 
-    /** Tells the native side that a new tab has been added for this profile. */
-    void registerRecentTab(int tabId) {
-        nativeRegisterRecentTab(mNativeOfflinePageBridge, tabId);
-    }
-
     /** Tells the native side that the tab of |webContents| will be closed. */
     void willCloseTab(WebContents webContents) {
         nativeWillCloseTab(mNativeOfflinePageBridge, webContents);
     }
 
-    /** Tells the native side that a new tab has been removed for this profile. */
-    void unregisterRecentTab(int tabId) {
-        nativeUnregisterRecentTab(mNativeOfflinePageBridge, tabId);
-    }
-
     /**
      * Schedules to download a page from |url| and categorize under |nameSpace|.
      * The duplicate pages or requests will be checked.
@@ -829,9 +819,7 @@
     @VisibleForTesting
     native void nativeGetAllPages(long nativeOfflinePageBridge, List<OfflinePageItem> offlinePages,
             final Callback<List<OfflinePageItem>> callback);
-    private native void nativeRegisterRecentTab(long nativeOfflinePageBridge, int tabId);
     private native void nativeWillCloseTab(long nativeOfflinePageBridge, WebContents webContents);
-    private native void nativeUnregisterRecentTab(long nativeOfflinePageBridge, int tabId);
 
     @VisibleForTesting
     native void nativeGetRequestsInQueue(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index 3ab6f42..3d45e94 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -689,11 +689,6 @@
         @Override
         public void didAddTab(Tab tab, TabModel.TabLaunchType type) {
             tab.addObserver(sTabRestoreTracker);
-
-            Profile profile = mTabModelSelector.getModel(tab.isIncognito()).getProfile();
-            OfflinePageBridge bridge = OfflinePageBridge.getForProfile(profile);
-            if (bridge == null) return;
-            bridge.registerRecentTab(tab.getId());
         }
 
         @Override
@@ -712,10 +707,7 @@
             OfflinePageBridge bridge = OfflinePageBridge.getForProfile(profile);
             if (bridge == null) return;
 
-            // First, unregister the tab with the UI.
-            bridge.unregisterRecentTab(tabId);
-
-            // Then, delete any "Last N" offline pages as well.  This is an optimization because
+            // Delete any "Last N" offline pages as well. This is an optimization because
             // the UI will no longer show the page, and the page would also be cleaned up by GC
             // given enough time.
             ClientId clientId =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsEventReporterBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsEventReporterBridge.java
index 9b167d8..7cf2731 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsEventReporterBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsEventReporterBridge.java
@@ -61,9 +61,8 @@
             case KnownCategories.BOOKMARKS:
                 NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARKS_MANAGER);
                 break;
-            // MORE button in both categories leads to the recent tabs manager
+            // MORE button leads to the recent tabs manager
             case KnownCategories.FOREIGN_TABS:
-            case KnownCategories.RECENT_TABS:
                 NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_RECENT_TABS_MANAGER);
                 break;
             case KnownCategories.DOWNLOADS:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
index 1f61d29f..1215d57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -27,10 +27,8 @@
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
-import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.common.Referrer;
@@ -119,13 +117,6 @@
             return;
         }
 
-        if (article.isRecentTab()) {
-            assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TAB;
-            boolean success = openRecentTabSnippet(article);
-            assert success;
-            return;
-        }
-
         // We explicitly open an offline page only for offline page downloads or for prefetched
         // offline pages when Data Reduction Proxy is enabled. For all other
         // sections the URL is opened and it is up to Offline Pages whether to open its offline
@@ -204,15 +195,6 @@
         return loadingTab;
     }
 
-    private boolean openRecentTabSnippet(SnippetArticle article) {
-        TabModel tabModel = mTabModelSelector.getModel(false);
-        int tabId = article.getRecentTabId();
-        int tabIndex = TabModelUtils.getTabIndexById(tabModel, tabId);
-        if (tabIndex == TabModel.INVALID_TAB_INDEX) return false;
-        TabModelUtils.setIndex(tabModel, tabIndex);
-        return true;
-    }
-
     private void openUrlInNewWindow(LoadUrlParams loadUrlParams) {
         TabDelegate tabDelegate = new TabDelegate(false);
         tabDelegate.createTabInOtherWindow(loadUrlParams, mActivity, mHost.getParentId());
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 5e7fff4..e8c6bd97 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -448,7 +448,6 @@
   "java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitorDelegate.java",
   "java/src/org/chromium/chrome/browser/feedback/AsyncFeedbackSource.java",
   "java/src/org/chromium/chrome/browser/feedback/AsyncFeedbackSourceAdapter.java",
-  "java/src/org/chromium/chrome/browser/feedback/ChromeHomeFeedbackSource.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityFeedbackSource.java",
   "java/src/org/chromium/chrome/browser/feedback/ConnectivityTask.java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfoTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfoTest.java
index 3b25ea2..d30deb23 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfoTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsCategoryInfoTest.java
@@ -42,24 +42,6 @@
     }
 
     @Test
-    public void testRecentTabContextMenu() {
-        SuggestionsCategoryInfo categoryInfo =
-                new CategoryInfoBuilder(KnownCategories.RECENT_TABS).build();
-        assertThat(
-                categoryInfo.isContextMenuItemSupported(ContextMenuManager.ID_OPEN_IN_NEW_WINDOW),
-                is(false));
-        assertThat(categoryInfo.isContextMenuItemSupported(ContextMenuManager.ID_OPEN_IN_NEW_TAB),
-                is(false));
-        assertThat(categoryInfo.isContextMenuItemSupported(
-                           ContextMenuManager.ID_OPEN_IN_INCOGNITO_TAB),
-                is(false));
-        assertThat(categoryInfo.isContextMenuItemSupported(ContextMenuManager.ID_SAVE_FOR_OFFLINE),
-                is(false));
-        assertThat(
-                categoryInfo.isContextMenuItemSupported(ContextMenuManager.ID_REMOVE), nullValue());
-    }
-
-    @Test
     public void testArticleContextMenu() {
         SuggestionsCategoryInfo categoryInfo =
                 new CategoryInfoBuilder(KnownCategories.ARTICLES).build();
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index e09cead..3ecb095 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-68.0.3420.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-68.0.3422.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ba8fc60d..74a2e57 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2887,6 +2887,7 @@
       "//services/ui/public/cpp/input_devices",
       "//services/ui/public/cpp/input_devices:input_device_controller",
       "//services/ui/public/interfaces",
+      "//services/ui/ws2:lib",
       "//ui/ozone",
     ]
     allow_circular_includes_from += [ "//chrome/browser/chromeos" ]
@@ -3793,7 +3794,6 @@
       "//components/offline_pages/core/background:background_offliner",
       "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
       "//components/offline_pages/core/prefetch",
-      "//components/offline_pages/core/recent_tabs",
       "//components/offline_pages/core/renovations",
       "//components/offline_pages/core/request_header:request_header",
     ]
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index db2bd6a..fc9672c 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -209,8 +209,15 @@
 ]
 
 specific_include_rules = {
-  "browser_process_platform_part_chromeos\.cc": [
-    # AshService is necessary while Ash runs in process.
+  "ash_service_registry\.cc": [
+    # The following are needed for classic mode to create the WindowService.
+    # Once Ash runs out of process no longer needed.
+    "+ash/content/content_gpu_support.h",
+    "+ash/shell.h",
+    "+ash/ws/window_service_delegate_impl.h",
+    "+services/ui/ws2/window_service.h",
+
+    # Needed for classic mode.
     "+ash/ash_service.h",
   ],
   # TODO(mash): see bugs 768439 and 768395.
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index 6d583d4c..b2921e1 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -92,14 +92,6 @@
             suggestion.download_suggestion_extra()->offline_page_id);
       }
     }
-    if (suggestion.id().category().IsKnownCategory(
-            KnownCategories::RECENT_TABS) &&
-        suggestion.recent_tab_suggestion_extra() != nullptr) {
-      Java_SnippetsBridge_setRecentTabDataForSuggestion(
-          env, java_suggestion,
-          suggestion.recent_tab_suggestion_extra()->tab_id,
-          suggestion.recent_tab_suggestion_extra()->offline_page_id);
-    }
   }
 
   return result;
diff --git a/chrome/browser/ash_service_registry.cc b/chrome/browser/ash_service_registry.cc
index 96e4a26..e3b6462 100644
--- a/chrome/browser/ash_service_registry.cc
+++ b/chrome/browser/ash_service_registry.cc
@@ -4,13 +4,21 @@
 
 #include "chrome/browser/ash_service_registry.h"
 
+#include "ash/ash_service.h"
 #include "ash/components/quick_launch/public/mojom/constants.mojom.h"
+#include "ash/content/content_gpu_support.h"
 #include "ash/public/interfaces/constants.mojom.h"
+#include "ash/shell.h"
+#include "ash/ws/window_service_delegate_impl.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "chrome/browser/chromeos/prefs/pref_connector_service.h"
 #include "components/services/font/public/interfaces/constants.mojom.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
+#include "services/ui/ws2/window_service.h"
+#include "ui/base/ui_base_features.h"
 
 using content::ContentBrowserClient;
 
@@ -23,42 +31,106 @@
   const char* process_group;  // If null, uses a separate process.
 };
 
-constexpr Service kServices[] = {
+// Services shared between mash and non-mash configs.
+constexpr Service kCommonServices[] = {
     {quick_launch::mojom::kServiceName, "Quick Launch", nullptr},
-    {ui::mojom::kServiceName, "UI Service", kAshAndUiProcessGroup},
-    {ash::mojom::kServiceName, "Ash Window Manager and Shell",
-     kAshAndUiProcessGroup},
     {"autoclick_app", "Accessibility Autoclick", nullptr},
     {"touch_hud_app", "Touch HUD", nullptr},
     {font_service::mojom::kServiceName, "Font Service", nullptr},
 };
 
-}  // namespace
+// Services unique to mash. Note that the non-mash case also has an Ash service,
+// it's just registered differently (see RegisterInProcessServices()).
+constexpr Service kMashServices[] = {
+    {ui::mojom::kServiceName, "UI Service", kAshAndUiProcessGroup},
+    {ash::mojom::kServiceName, "Ash Window Manager and Shell",
+     kAshAndUiProcessGroup},
+};
 
-void RegisterOutOfProcessServices(
-    ContentBrowserClient::OutOfProcessServiceMap* services) {
-  for (const auto& service : kServices) {
+void RegisterOutOfProcessServicesImpl(
+    const Service* services,
+    size_t num_services,
+    ContentBrowserClient::OutOfProcessServiceMap* services_map) {
+  for (size_t i = 0; i < num_services; ++i) {
+    const Service& service = services[i];
     base::string16 display_name = base::ASCIIToUTF16(service.display_name);
     if (service.process_group) {
-      (*services)[service.name] = ContentBrowserClient::OutOfProcessServiceInfo(
-          display_name, service.process_group);
+      (*services_map)[service.name] =
+          ContentBrowserClient::OutOfProcessServiceInfo(display_name,
+                                                        service.process_group);
     } else {
-      (*services)[service.name] =
+      (*services_map)[service.name] =
           ContentBrowserClient::OutOfProcessServiceInfo(display_name);
     }
   }
 }
 
+std::unique_ptr<service_manager::Service> CreateEmbeddedWindowService() {
+  return std::make_unique<ui::ws2::WindowService>(
+      ash::Shell::Get()->window_service_delegate(),
+      std::make_unique<ash::ContentGpuSupport>());
+}
+
+}  // namespace
+
+void RegisterOutOfProcessServices(
+    ContentBrowserClient::OutOfProcessServiceMap* services) {
+  if (base::FeatureList::IsEnabled(features::kMash)) {
+    RegisterOutOfProcessServicesImpl(kCommonServices,
+                                     base::size(kCommonServices), services);
+    RegisterOutOfProcessServicesImpl(kMashServices, base::size(kMashServices),
+                                     services);
+  } else {
+    RegisterOutOfProcessServicesImpl(kCommonServices,
+                                     base::size(kCommonServices), services);
+  }
+}
+
+void RegisterInProcessServices(
+    content::ContentBrowserClient::StaticServiceMap* services) {
+  {
+    service_manager::EmbeddedServiceInfo info;
+    info.factory =
+        base::BindRepeating([]() -> std::unique_ptr<service_manager::Service> {
+          return std::make_unique<AshPrefConnector>();
+        });
+    info.task_runner = base::ThreadTaskRunnerHandle::Get();
+    (*services)[ash::mojom::kPrefConnectorServiceName] = info;
+  }
+
+  if (base::FeatureList::IsEnabled(features::kMash))
+    return;
+
+  (*services)[ash::mojom::kServiceName] =
+      ash::AshService::CreateEmbeddedServiceInfo();
+
+  service_manager::EmbeddedServiceInfo ui_service_info;
+  ui_service_info.factory = base::BindRepeating(&CreateEmbeddedWindowService);
+  ui_service_info.task_runner = base::ThreadTaskRunnerHandle::Get();
+  (*services)[ui::mojom::kServiceName] = ui_service_info;
+}
+
 bool IsAshRelatedServiceName(const std::string& name) {
-  for (size_t i = 0; i < base::size(kServices); ++i) {
-    if (name == kServices[i].name)
+  for (const Service& service : kMashServices) {
+    if (name == service.name)
+      return true;
+  }
+  for (const Service& service : kCommonServices) {
+    if (name == service.name)
       return true;
   }
   return false;
 }
 
 std::string GetAshRelatedServiceLabel(const std::string& service_name) {
-  for (const Service& service : kServices) {
+  for (const Service& service : kMashServices) {
+    if (service_name == service.name) {
+      // Use the process group name when available because that makes it more
+      // obvious that multiple services are running in the same process.
+      return service.process_group ? service.process_group : service.name;
+    }
+  }
+  for (const Service& service : kCommonServices) {
     if (service_name == service.name) {
       // Use the process group name when available because that makes it more
       // obvious that multiple services are running in the same process.
diff --git a/chrome/browser/ash_service_registry.h b/chrome/browser/ash_service_registry.h
index 0672c3f..91aef2e 100644
--- a/chrome/browser/ash_service_registry.h
+++ b/chrome/browser/ash_service_registry.h
@@ -14,10 +14,14 @@
 // Process group used for the ash service and the ui service. Visible for test.
 constexpr char kAshAndUiProcessGroup[] = "ash_and_ui";
 
-// Starts one of Mash's embedded services.
+// Registers the set of Ash related services that run out of process.
 void RegisterOutOfProcessServices(
     content::ContentBrowserClient::OutOfProcessServiceMap* services);
 
+// Registers the set of Ash related services that run in process.
+void RegisterInProcessServices(
+    content::ContentBrowserClient::StaticServiceMap* services);
+
 // Returns true if |name| identifies an Ash related service.
 bool IsAshRelatedServiceName(const std::string& name);
 
diff --git a/chrome/browser/ash_service_registry_unittest.cc b/chrome/browser/ash_service_registry_unittest.cc
index dc80a75d..c2633e8 100644
--- a/chrome/browser/ash_service_registry_unittest.cc
+++ b/chrome/browser/ash_service_registry_unittest.cc
@@ -6,11 +6,15 @@
 
 #include "ash/public/interfaces/constants.mojom.h"
 #include "base/stl_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "content/public/browser/content_browser_client.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_features.h"
 
 TEST(AshServiceRegistryTest, AshAndUiInSameProcess) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(features::kMash);
   content::ContentBrowserClient::OutOfProcessServiceMap services;
   ash_service_registry::RegisterOutOfProcessServices(&services);
 
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc
index f09f5088..0f464f1 100644
--- a/chrome/browser/browser_process_platform_part_chromeos.cc
+++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -6,11 +6,11 @@
 
 #include <utility>
 
-#include "ash/ash_service.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "base/logging.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/tick_clock.h"
+#include "chrome/browser/ash_service_registry.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/chrome_service_name.h"
@@ -18,7 +18,6 @@
 #include "chrome/browser/chromeos/login/users/chrome_user_manager_impl.h"
 #include "chrome/browser/chromeos/net/delay_network_call.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
-#include "chrome/browser/chromeos/prefs/pref_connector_service.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
@@ -28,7 +27,6 @@
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
 #include "chrome/browser/component_updater/cros_component_installer.h"
-#include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/account_manager/account_manager_factory.h"
@@ -182,22 +180,7 @@
 
 void BrowserProcessPlatformPart::RegisterInProcessServices(
     content::ContentBrowserClient::StaticServiceMap* services) {
-  {
-    service_manager::EmbeddedServiceInfo info;
-    info.factory = base::Bind([] {
-      return std::unique_ptr<service_manager::Service>(
-          std::make_unique<AshPrefConnector>());
-    });
-    info.task_runner = base::ThreadTaskRunnerHandle::Get();
-    services->insert(
-        std::make_pair(ash::mojom::kPrefConnectorServiceName, info));
-  }
-
-  if (!ash_util::IsRunningInMash()) {
-    services->insert(
-        std::make_pair(ash::mojom::kServiceName,
-                       ash::AshService::CreateEmbeddedServiceInfo()));
-  }
+  ash_service_registry::RegisterInProcessServices(services);
 }
 
 chromeos::system::SystemClock* BrowserProcessPlatformPart::GetSystemClock() {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 31968d2e..7fa08b7 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2079,6 +2079,12 @@
     command_line->AppendSwitchASCII(
         switches::kMashServiceName,
         ash_service_registry::GetAshRelatedServiceLabel(identity.name()));
+    if (!base::FeatureList::IsEnabled(features::kMash)) {
+      // TODO(sky): this is necessary because WindowTreeClient only connects to
+      // the gpu related interfaces if Mash is set.
+      command_line->AppendSwitchASCII(switches::kEnableFeatures,
+                                      features::kMash.name);
+    }
   }
 #endif
   // TODO(sky): move to a whitelist, but currently the set of flags is rather
@@ -3426,8 +3432,7 @@
       l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_UNZIP_NAME);
 
 #if defined(OS_CHROMEOS)
-  if (base::FeatureList::IsEnabled(features::kMash))
-    ash_service_registry::RegisterOutOfProcessServices(services);
+  ash_service_registry::RegisterOutOfProcessServices(services);
 #endif
 }
 
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 59fe529..f3830d91 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -411,8 +411,6 @@
 
 #if defined(OS_CHROMEOS)
 
-// This behavior only matters on Chrome OS, which is why this isn't wrapped in
-// ENABLE_MASH_PACKAGED_SERVICES (which is used for Linux Ozone).
 TEST(ChromeContentBrowserClientTest, ShouldTerminateOnServiceQuit) {
   const struct {
     std::string service_name;
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index 080e5f8..a185c4c 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -914,7 +914,8 @@
   user_context.SetKey(Key(kPassword));
   user_context.SetUserIDHash(ad_account_id_.GetUserEmail());
   user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
-  user_context.SetUserType(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
+  ASSERT_EQ(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
+            user_context.GetUserType());
   content::WindowedNotificationObserver profile_prepared_observer(
       chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
       content::NotificationService::AllSources());
@@ -933,7 +934,8 @@
   user_context.SetKey(Key(kPassword));
   user_context.SetUserIDHash(ad_account_id_.GetUserEmail());
   user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
-  user_context.SetUserType(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
+  ASSERT_EQ(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
+            user_context.GetUserType());
   content::WindowedNotificationObserver profile_prepared_observer(
       chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
       content::NotificationService::AllSources());
@@ -957,7 +959,8 @@
   UserContext user_context(ad_account_id_);
   user_context.SetKey(Key(kPassword));
   user_context.SetUserIDHash(ad_account_id_.GetUserEmail());
-  user_context.SetUserType(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
+  ASSERT_EQ(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
+            user_context.GetUserType());
 
   content::WindowedNotificationObserver profile_prepared_observer(
       chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
@@ -986,7 +989,8 @@
   user_context.SetKey(Key(kPassword));
   user_context.SetUserIDHash(ad_account_id_.GetUserEmail());
   user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
-  user_context.SetUserType(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
+  ASSERT_EQ(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
+            user_context.GetUserType());
   content::WindowedNotificationObserver profile_prepared_observer(
       chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
       content::NotificationService::AllSources());
@@ -1005,7 +1009,8 @@
   user_context.SetKey(Key(kPassword));
   user_context.SetUserIDHash(account_id.GetUserEmail());
   user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
-  user_context.SetUserType(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
+  ASSERT_EQ(user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY,
+            user_context.GetUserType());
   existing_user_controller()->CompleteLogin(user_context);
 }
 
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index 813e842d..61630bb 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -693,7 +693,7 @@
     return;
   }
 
-  UserContext user_context(active_user->GetAccountId());
+  UserContext user_context(active_user->GetType(), active_user->GetAccountId());
   if (!base::ContainsKey(matches, active_user->username_hash())) {
     OnFingerprintAuthFailure(*active_user);
     return;
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index e6bb57fb..923ea9be 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -179,8 +179,12 @@
   user_context.SetKey(Key(key_type, std::string(), hashed_password));
   user_context.SetIsUsingPin(authenticated_by_pin);
   user_context.SetSyncPasswordData(sync_password_data);
-  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
-    user_context.SetUserType(user_manager::USER_TYPE_ACTIVE_DIRECTORY);
+  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY &&
+      (user_context.GetUserType() !=
+       user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY)) {
+    LOG(FATAL) << "Incorrect Active Directory user type "
+               << user_context.GetUserType();
+  }
   ScreenLocker::default_screen_locker()->Authenticate(user_context,
                                                       std::move(callback));
   UpdatePinKeyboardState(account_id);
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
index 493b7c8..36628166 100644
--- a/chrome/browser/chromeos/login/login_utils_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -71,7 +71,7 @@
         static_cast<LoginDisplayWebUI*>(controller->login_display());
     ASSERT_TRUE(login_display);
 
-    login_display->ShowSigninScreenForCreds(username, "password");
+    login_display->ShowSigninScreenForTest(username, "password", "[]");
 
     // Wait for the session to start after submitting the credentials. This
     // will wait until all the background requests are done.
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index 473f060..9441f05 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -75,8 +75,9 @@
       chrome::NOTIFICATION_SESSION_STARTED,
       content::NotificationService::AllSources());
 
-  GetLoginDisplay()->ShowSigninScreenForCreds(OobeBaseTest::kFakeUserEmail,
-                                              OobeBaseTest::kFakeUserPassword);
+  GetLoginDisplay()->ShowSigninScreenForTest(OobeBaseTest::kFakeUserEmail,
+                                             OobeBaseTest::kFakeUserPassword,
+                                             OobeBaseTest::kEmptyUserServices);
 
   session_start_waiter.Wait();
 }
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index 6ed03fef..f9d476d 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -121,10 +121,14 @@
 constexpr char kTestAuthLSIDCookie1[] = "fake-auth-LSID-cookie-1";
 constexpr char kTestAuthLSIDCookie2[] = "fake-auth-LSID-cookie-2";
 
-constexpr char kFirstSAMLUserEmail[] = "bob@example.com";
-constexpr char kSecondSAMLUserEmail[] = "alice@example.com";
-constexpr char kHTTPSAMLUserEmail[] = "carol@example.com";
-constexpr char kNonSAMLUserEmail[] = "dan@example.com";
+// Note: SAML account cannot be @gmail or @example.com account.  The former by
+// design, the latter because @example.com is used in another tests as regular
+// user. So we use @corp.example.com and @example.test, so that we can handle
+// it specially in embedded_setup_chromeos.html .
+constexpr char kFirstSAMLUserEmail[] = "bob@corp.example.com";
+constexpr char kSecondSAMLUserEmail[] = "alice@corp.example.com";
+constexpr char kHTTPSAMLUserEmail[] = "carol@corp.example.com";
+constexpr char kNonSAMLUserEmail[] = "dan@corp.example.com";
 constexpr char kDifferentDomainSAMLUserEmail[] = "eve@example.test";
 
 constexpr char kFirstSAMLUserGaiaId[] = "bob-gaia";
@@ -133,8 +137,8 @@
 constexpr char kNonSAMLUserGaiaId[] = "dan-gaia";
 constexpr char kDifferentDomainSAMLUserGaiaId[] = "eve-gaia";
 
-constexpr char kIdPHost[] = "login.example.com";
-constexpr char kAdditionalIdPHost[] = "login2.example.com";
+constexpr char kIdPHost[] = "login.corp.example.com";
+constexpr char kAdditionalIdPHost[] = "login2.corp.example.com";
 
 constexpr char kSAMLIdPCookieName[] = "saml";
 constexpr char kSAMLIdPCookieValue1[] = "value-1";
@@ -332,7 +336,7 @@
         kHTTPSAMLUserEmail,
         embedded_test_server()->base_url().Resolve("/SAML"));
     fake_gaia_->RegisterSamlUser(kDifferentDomainSAMLUserEmail, saml_idp_url);
-    fake_gaia_->RegisterSamlDomainRedirectUrl("example.com", saml_idp_url);
+    fake_gaia_->RegisterSamlDomainRedirectUrl("corp.example.com", saml_idp_url);
 
     OobeBaseTest::SetUpCommandLine(command_line);
   }
@@ -372,7 +376,7 @@
     SetupAuthFlowChangeListener();
 
     content::DOMMessageQueue message_queue;  // Start observe before SAML.
-    GetLoginDisplay()->ShowSigninScreenForCreds(gaia_email, "");
+    GetLoginDisplay()->ShowSigninScreenForTest(gaia_email, "", "[]");
 
     std::string message;
     ASSERT_TRUE(message_queue.WaitForMessage(&message));
@@ -638,9 +642,9 @@
   session_start_waiter.Wait();
 }
 
-// Types |bob@example.com| into the GAIA login form but then authenticates as
-// |alice@example.com| via SAML. Verifies that the logged-in user is correctly
-// identified as Alice.
+// Types |bob@corp.example.com| into the GAIA login form but then authenticates
+// as |alice@corp.example.com| via SAML. Verifies that the logged-in user is
+// correctly identified as Alice.
 //
 // Disabled since it's occasionally timed out: https://crbug.com/830322.
 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER)
@@ -651,12 +655,12 @@
 #endif
 IN_PROC_BROWSER_TEST_F(SamlTest, MAYBE_UseAutenticatedUserEmailAddress) {
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
-  // Type |bob@example.com| into the GAIA login form.
+  // Type |bob@corp.example.com| into the GAIA login form.
   StartSamlAndWaitForIdpPageLoad(kSecondSAMLUserEmail);
 
-  // Authenticate as alice@example.com via SAML (the |Email| provided here is
-  // irrelevant - the authenticated user's e-mail address that FakeGAIA
-  // reports was set via |SetFakeMergeSessionParams|.
+  // Authenticate as alice@corp.example.com via SAML (the |Email| provided here
+  // is irrelevant - the authenticated user's e-mail address that FakeGAIA
+  // reports was set via |SetFakeMergeSessionParams|).
   SetSignFormField("Email", "fake_user");
   SetSignFormField("Password", "fake_password");
 
@@ -787,7 +791,7 @@
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
 
   WaitForSigninScreen();
-  GetLoginDisplay()->ShowSigninScreenForCreds(kHTTPSAMLUserEmail, "");
+  GetLoginDisplay()->ShowSigninScreenForTest(kHTTPSAMLUserEmail, "", "[]");
 
   const GURL url = embedded_test_server()->base_url().Resolve("/SAML");
   EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_LOGIN_FATAL_ERROR_TEXT_INSECURE_URL,
@@ -811,7 +815,7 @@
   fake_saml_idp()->SetRefreshURL(url);
 
   WaitForSigninScreen();
-  GetLoginDisplay()->ShowSigninScreenForCreds(kFirstSAMLUserEmail, "");
+  GetLoginDisplay()->ShowSigninScreenForTest(kFirstSAMLUserEmail, "", "[]");
 
   EXPECT_EQ(l10n_util::GetStringFUTF8(IDS_LOGIN_FATAL_ERROR_TEXT_INSECURE_URL,
                                       base::UTF8ToUTF16(url.spec())),
@@ -1305,7 +1309,8 @@
   SetupFakeGaiaForLogin(kNonSAMLUserEmail, "", kTestRefreshToken);
 
   // Log in without SAML.
-  GetLoginDisplay()->ShowSigninScreenForCreds(kNonSAMLUserEmail, "password");
+  GetLoginDisplay()->ShowSigninScreenForTest(kNonSAMLUserEmail, "password",
+                                             "[]");
 
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_SESSION_STARTED,
@@ -1498,7 +1503,7 @@
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
 
   const GURL url1("https://google.com");
-  const GURL url2("https://example.com");
+  const GURL url2("https://corp.example.com");
   const GURL url3("https://not-allowed.com");
   SetLoginVideoCaptureAllowedUrls({url1, url2});
   WaitForSigninScreen();
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
index d13771ee..b8833192 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager_browsertest.cc
@@ -105,7 +105,8 @@
 
   LoginDisplayWebUI* login_display = static_cast<LoginDisplayWebUI*>(
       ExistingUserController::current_controller()->login_display());
-  login_display->ShowSigninScreenForCreds(kTestUsers[0].email, "fake_password");
+  login_display->ShowSigninScreenForTest(kTestUsers[0].email, "fake_password",
+                                         "[]");
 
   session_start_waiter.Wait();
 
diff --git a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
index 5d157905..b113f54 100644
--- a/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/device_id_browsertest.cc
@@ -111,7 +111,7 @@
     fake_gaia_->UpdateMergeSessionParams(params);
     fake_gaia_->MapEmailToGaiaId(user_id, gaia_id);
 
-    GetLoginDisplay()->ShowSigninScreenForCreds(user_id, password);
+    GetLoginDisplay()->ShowSigninScreenForTest(user_id, password, "[]");
     WaitForSessionStart();
   }
 
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index 2ba818e..03b0bc4c 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -69,6 +69,7 @@
 const char kTestEmail[] = "username@gmail.com";
 const char kTestRawEmail[] = "User.Name@gmail.com";
 const char kTestAccountPassword[] = "fake-password";
+const char kTestAccountServices[] = "[]";
 const char kTestAuthCode[] = "fake-auth-code";
 const char kTestGaiaUberToken[] = "fake-uber-token";
 const char kTestAuthLoginAccessToken[] = "fake-access-token";
@@ -381,8 +382,8 @@
 
     // Use capitalized and dotted user name on purpose to make sure
     // our email normalization kicks in.
-    GetLoginDisplay()->ShowSigninScreenForCreds(kTestRawEmail,
-                                                kTestAccountPassword);
+    GetLoginDisplay()->ShowSigninScreenForTest(
+        kTestRawEmail, kTestAccountPassword, kTestAccountServices);
     session_start_waiter.Wait();
 
     if (wait_for_merge) {
@@ -620,7 +621,8 @@
   fake_gaia_->SetMergeSessionParams(params);
 
   // Simulate an online sign-in.
-  GetLoginDisplay()->ShowSigninScreenForCreds(kTestEmail, kTestAccountPassword);
+  GetLoginDisplay()->ShowSigninScreenForTest(kTestEmail, kTestAccountPassword,
+                                             kTestAccountServices);
 
   // User session should be terminated.
   termination_waiter.Wait();
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
index 00a988d3..2a2624e 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
@@ -31,8 +31,12 @@
   user_context_.SetAuthCode(std::string());
   user_context_.SetRefreshToken(result.refresh_token);
   user_context_.SetAccessToken(result.access_token);
-  if (result.is_child_account) {
-    user_context_.SetUserType(user_manager::USER_TYPE_CHILD);
+  if (result.is_child_account &&
+      user_context_.GetUserType() != user_manager::USER_TYPE_CHILD) {
+    LOG(FATAL) << "Incorrect child user type " << user_context_.GetUserType();
+  } else if (user_context_.GetUserType() == user_manager::USER_TYPE_CHILD &&
+             !result.is_child_account) {
+    LOG(FATAL) << "Incorrect non-child token for the child user.";
   }
   callback_.Run(true, user_context_);
 }
diff --git a/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc b/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc
index 27b0a00..3f993ed 100644
--- a/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc
@@ -80,10 +80,8 @@
 
     signin_browser_context_ = std::make_unique<TestingProfile>();
 
-    signin_ui_web_contents_ = base::WrapUnique<content::WebContents>(
-        content::WebContentsTester::CreateTestWebContents(
-            GetSigninProfile(),
-            content::SiteInstance::Create(GetSigninProfile())));
+    signin_ui_web_contents_ = content::WebContentsTester::CreateTestWebContents(
+        GetSigninProfile(), content::SiteInstance::Create(GetSigninProfile()));
 
     GURL url(kEmbedderUrl);
     content::WebContentsTester::For(signin_ui_web_contents())
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.cc b/chrome/browser/chromeos/login/test/oobe_base_test.cc
index 0f114b8..094b8818 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.cc
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.cc
@@ -49,6 +49,7 @@
 const char OobeBaseTest::kFakeUserEmail[] = "fake-email@gmail.com";
 const char OobeBaseTest::kFakeUserPassword[] = "fake-password";
 const char OobeBaseTest::kFakeUserGaiaId[] = "fake-gaiaId";
+const char OobeBaseTest::kEmptyUserServices[] = "[]";
 const char OobeBaseTest::kFakeSIDCookie[] = "fake-SID-cookie";
 const char OobeBaseTest::kFakeLSIDCookie[] = "fake-LSID-cookie";
 
diff --git a/chrome/browser/chromeos/login/test/oobe_base_test.h b/chrome/browser/chromeos/login/test/oobe_base_test.h
index a59ce3c..397ad4a 100644
--- a/chrome/browser/chromeos/login/test/oobe_base_test.h
+++ b/chrome/browser/chromeos/login/test/oobe_base_test.h
@@ -41,6 +41,7 @@
   static const char kFakeUserEmail[];
   static const char kFakeUserPassword[];
   static const char kFakeUserGaiaId[];
+  static const char kEmptyUserServices[];
 
   // FakeGaia is configured to return these cookies for kFakeUserEmail.
   static const char kFakeSIDCookie[];
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
index 650b2a8b..7b729f37 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_mojo.cc
@@ -219,8 +219,12 @@
   user_context.SetKey(Key(chromeos::Key::KEY_TYPE_SALTED_SHA256_TOP_HALF,
                           std::string(), hashed_password));
   user_context.SetSyncPasswordData(sync_password_data);
-  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
-    user_context.SetUserType(user_manager::USER_TYPE_ACTIVE_DIRECTORY);
+  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY &&
+      (user_context.GetUserType() !=
+       user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY)) {
+    LOG(FATAL) << "Incorrect Active Directory user type "
+               << user_context.GetUserType();
+  }
 
   existing_user_controller_->Login(user_context, chromeos::SigninSpecifics());
 }
diff --git a/chrome/browser/chromeos/login/ui/login_display_webui.cc b/chrome/browser/chromeos/login/ui/login_display_webui.cc
index 044281d..324f91f 100644
--- a/chrome/browser/chromeos/login/ui/login_display_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_webui.cc
@@ -267,10 +267,11 @@
   SignInScreenController::Get()->SetWebUIHandler(webui_handler_);
 }
 
-void LoginDisplayWebUI::ShowSigninScreenForCreds(const std::string& username,
-                                                 const std::string& password) {
+void LoginDisplayWebUI::ShowSigninScreenForTest(const std::string& username,
+                                                const std::string& password,
+                                                const std::string& services) {
   if (webui_handler_)
-    webui_handler_->ShowSigninScreenForCreds(username, password);
+    webui_handler_->ShowSigninScreenForTest(username, password, services);
 }
 
 bool LoginDisplayWebUI::IsShowGuest() const {
diff --git a/chrome/browser/chromeos/login/ui/login_display_webui.h b/chrome/browser/chromeos/login/ui/login_display_webui.h
index db0a2ce..4a94cec 100644
--- a/chrome/browser/chromeos/login/ui/login_display_webui.h
+++ b/chrome/browser/chromeos/login/ui/login_display_webui.h
@@ -72,8 +72,12 @@
   void ShowUpdateRequiredScreen() override;
   void ShowWrongHWIDScreen() override;
   void SetWebUIHandler(LoginDisplayWebUIHandler* webui_handler) override;
-  virtual void ShowSigninScreenForCreds(const std::string& username,
-                                        const std::string& password);
+  // Should match the same method in SigninScreenHandler.
+  // |services| must be a valid JSON array. See SigninScreenHandler for
+  // detalis.
+  virtual void ShowSigninScreenForTest(const std::string& username,
+                                       const std::string& password,
+                                       const std::string& services);
   bool IsShowGuest() const override;
   bool IsShowUsers() const override;
   bool ShowUsersHasChanged() const override;
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index 4a14489..85e09be 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -240,6 +240,7 @@
       chrome::NOTIFICATION_SESSION_STARTED,
       content::NotificationService::AllSources());
 
+  SetSignFormField("services", "[]");
   SetSignFormField("password", OobeBaseTest::kFakeUserPassword);
   ClickNext();
 
@@ -274,6 +275,7 @@
       content::NotificationService::AllSources());
 
   // Finish sign-up.
+  SetSignFormField("services", "[]");
   SetSignFormField("password", OobeBaseTest::kFakeUserPassword);
   ClickNext();
 
diff --git a/chrome/browser/chromeos/policy/blocking_login_browsertest.cc b/chrome/browser/chromeos/policy/blocking_login_browsertest.cc
index d0eff7e4..6ff96b7 100644
--- a/chrome/browser/chromeos/policy/blocking_login_browsertest.cc
+++ b/chrome/browser/chromeos/policy/blocking_login_browsertest.cc
@@ -162,7 +162,7 @@
         static_cast<LoginDisplayWebUI*>(controller->login_display());
     ASSERT_TRUE(login_display);
 
-    login_display->ShowSigninScreenForCreds(username, "password");
+    login_display->ShowSigninScreenForTest(username, "password", "[]");
 
     // Wait for the session to start after submitting the credentials. This
     // will wait until all the background requests are done.
diff --git a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
index 17519f4..63f4005 100644
--- a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
@@ -56,7 +56,7 @@
 IN_PROC_BROWSER_TEST_F(ForceMaximizeOnFirstRunTest, PRE_TwoRuns) {
   SetUpResolution();
   SkipToLoginScreen();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   // Check that the first browser window is maximized.
   const BrowserList* const browser_list = BrowserList::GetInstance();
@@ -81,7 +81,7 @@
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
       content::NotificationService::AllSources()).Wait();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   const Browser* const browser = OpenNewBrowserWindow();
   ASSERT_TRUE(browser);
@@ -103,7 +103,7 @@
 IN_PROC_BROWSER_TEST_F(ForceMaximizePolicyFalseTest, GeneralFirstRun) {
   SetUpResolution();
   SkipToLoginScreen();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   const BrowserList* const browser_list = BrowserList::GetInstance();
   EXPECT_EQ(1U, browser_list->size());
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.cc b/chrome/browser/chromeos/policy/login_policy_test_base.cc
index 54087881..29b9a6b 100644
--- a/chrome/browser/chromeos/policy/login_policy_test_base.cc
+++ b/chrome/browser/chromeos/policy/login_policy_test_base.cc
@@ -32,6 +32,8 @@
 
 const char LoginPolicyTestBase::kAccountPassword[] = "letmein";
 const char LoginPolicyTestBase::kAccountId[] = "user@example.com";
+// Empty services list for userInfo.
+const char LoginPolicyTestBase::kEmptyServices[] = "[]";
 
 LoginPolicyTestBase::LoginPolicyTestBase() {
   set_open_about_blank_on_browser_launch(false);
@@ -109,8 +111,9 @@
 }
 
 void LoginPolicyTestBase::LogIn(const std::string& user_id,
-                                const std::string& password) {
-  GetLoginDisplay()->ShowSigninScreenForCreds(user_id, password);
+                                const std::string& password,
+                                const std::string& services) {
+  GetLoginDisplay()->ShowSigninScreenForTest(user_id, password, services);
 
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_SESSION_STARTED,
diff --git a/chrome/browser/chromeos/policy/login_policy_test_base.h b/chrome/browser/chromeos/policy/login_policy_test_base.h
index 6d17780..6ea6bafa 100644
--- a/chrome/browser/chromeos/policy/login_policy_test_base.h
+++ b/chrome/browser/chromeos/policy/login_policy_test_base.h
@@ -41,10 +41,14 @@
   }
 
   void SkipToLoginScreen();
-  void LogIn(const std::string& user_id, const std::string& password);
+  // Should match ShowSigninScreenForTest method in SigninScreenHandler.
+  void LogIn(const std::string& user_id,
+             const std::string& password,
+             const std::string& services);
 
   static const char kAccountPassword[];
   static const char kAccountId[];
+  static const char kEmptyServices[];
 
  private:
   void SetUpGaiaServerWithAccessTokens();
diff --git a/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc b/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
index 468fa4d7..fc01ba3 100644
--- a/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
+++ b/chrome/browser/chromeos/policy/restore_on_startup_browsertest_chromeos.cc
@@ -56,7 +56,7 @@
 }
 
 void RestoreOnStartupTestChromeOS::LogInAndVerifyStartUpURLs() {
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   const BrowserList* const browser_list = BrowserList::GetInstance();
   ASSERT_EQ(1U, browser_list->size());
diff --git a/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc b/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
index 7d31ea7..09b03b3c3 100644
--- a/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
+++ b/chrome/browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc
@@ -370,7 +370,8 @@
   // it waits for a user session start unconditionally, which will not happen if
   // chrome requests a restart to set user-session flags.
   SkipToLoginScreen();
-  GetLoginDisplay()->ShowSigninScreenForCreds(kAccountId, kAccountPassword);
+  GetLoginDisplay()->ShowSigninScreenForTest(kAccountId, kAccountPassword,
+                                             kEmptyServices);
 
   // Wait for either the user session to start, or for restart to be requested
   // (whichever happens first).
diff --git a/chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc b/chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc
index 2edefe79..1ae6551 100644
--- a/chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc
@@ -76,7 +76,7 @@
   CloudExternalDataManagerBase::SetMaxExternalDataSizeForTesting(1000);
 
   SkipToLoginScreen();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   Profile* profile = ProfileManager::GetActiveUserProfile();
   ASSERT_TRUE(profile);
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc
index 3ae2659..6afb8d8 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_browsertest.cc
@@ -40,6 +40,9 @@
     "eyAic2VydmljZXMiOiBbInVjYSJdIH0="
     ".dummy-signature";
 
+// Services list for the child user. (This must be a correct JSON array.)
+const char kChildServices[] = "[\"uca\"]";
+
 // Helper class that counts the number of notifications of the specified
 // type that have been received.
 class CountNotificationObserver : public content::NotificationObserver {
@@ -98,7 +101,7 @@
             user_manager::known_user::GetProfileRequiresPolicy(account_id));
 
   SkipToLoginScreen();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   // User should be marked as having a valid OAuth token.
   const user_manager::UserManager* const user_manager =
@@ -134,7 +137,8 @@
   CountNotificationObserver observer(
       chrome::NOTIFICATION_SESSION_STARTED,
       content::NotificationService::AllSources());
-  GetLoginDisplay()->ShowSigninScreenForCreds(kAccountId, kAccountPassword);
+  GetLoginDisplay()->ShowSigninScreenForTest(kAccountId, kAccountPassword,
+                                             kEmptyServices);
   base::RunLoop().Run();
   // Should not receive a SESSION_STARTED notification.
   ASSERT_EQ(0, observer.notification_count());
@@ -163,7 +167,7 @@
   // Delete the policy file - this will cause a 500 error on policy requests.
   user_policy_helper()->DeletePolicyFile();
   SkipToLoginScreen();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   // User should be marked as having a valid OAuth token.
   const user_manager::UserManager* const user_manager =
@@ -202,7 +206,7 @@
   // Delete the policy file - this will cause a 500 error on policy requests.
   user_policy_helper()->DeletePolicyFile();
   SkipToLoginScreen();
-  LogIn(kAccountId, kAccountPassword);
+  LogIn(kAccountId, kAccountPassword, kEmptyServices);
 
   // User should be marked as having a valid OAuth token.
   EXPECT_EQ(user_manager::User::OAUTH2_TOKEN_STATUS_VALID,
@@ -254,7 +258,7 @@
             user_manager::known_user::GetProfileRequiresPolicy(account_id));
 
   SkipToLoginScreen();
-  LogIn(GetAccount(), kAccountPassword);
+  LogIn(GetAccount(), kAccountPassword, kEmptyServices);
 
   // User should be marked as having a valid OAuth token.
   const user_manager::UserManager* const user_manager =
@@ -302,7 +306,7 @@
             user_manager::known_user::GetProfileRequiresPolicy(account_id));
 
   SkipToLoginScreen();
-  LogIn(GetAccount(), kAccountPassword);
+  LogIn(GetAccount(), kAccountPassword, kChildServices);
 
   // User should be marked as having a valid OAuth token.
   const user_manager::UserManager* const user_manager =
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 3f526a1..c849a15 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -6,8 +6,7 @@
 
 #include <vector>
 
-#include "ash/ash_constants.h"
-#include "ash/autoclick/autoclick_controller.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
@@ -217,9 +216,7 @@
       ash::prefs::kAccessibilityAutoclickEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
   registry->RegisterIntegerPref(
-      ash::prefs::kAccessibilityAutoclickDelayMs,
-      static_cast<int>(ash::AutoclickController::GetDefaultAutoclickDelay()
-                           .InMilliseconds()),
+      ash::prefs::kAccessibilityAutoclickDelayMs, ash::kDefaultAutoclickDelayMs,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
   registry->RegisterBooleanPref(
       ash::prefs::kAccessibilityVirtualKeyboardEnabled, false,
diff --git a/chrome/browser/devtools/inspector_protocol_config.json b/chrome/browser/devtools/inspector_protocol_config.json
index 5260199..96b580a7 100644
--- a/chrome/browser/devtools/inspector_protocol_config.json
+++ b/chrome/browser/devtools/inspector_protocol_config.json
@@ -19,7 +19,6 @@
             {
                 "domain": "Target",
                 "include": [ "setRemoteLocations", "createBrowserContext", "createTarget", "disposeBrowserContext" ],
-                "async": ["disposeBrowserContext"],
                 "include_events": []
             },
             {
diff --git a/chrome/browser/devtools/protocol/target_handler.cc b/chrome/browser/devtools/protocol/target_handler.cc
index 20e42cd..cb544fe 100644
--- a/chrome/browser/devtools/protocol/target_handler.cc
+++ b/chrome/browser/devtools/protocol/target_handler.cc
@@ -22,7 +22,6 @@
   if (delegate)
     delegate->UpdateDeviceDiscovery();
   registrations_.clear();
-  BrowserList::RemoveObserver(this);
 }
 
 protocol::Response TargetHandler::SetRemoteLocations(
@@ -112,49 +111,23 @@
   });
 }
 
-void TargetHandler::DisposeBrowserContext(
+protocol::Response TargetHandler::DisposeBrowserContext(
     const std::string& context_id,
-    std::unique_ptr<DisposeBrowserContextCallback> callback) {
-  if (pending_context_disposals_.find(context_id) !=
-      pending_context_disposals_.end()) {
-    callback->sendFailure(protocol::Response::Error(
-        "Disposing of browser context " + context_id + " is already pending"));
-    return;
-  }
+    bool* out_success) {
   auto it = registrations_.find(context_id);
   if (it == registrations_.end()) {
-    callback->sendFailure(protocol::Response::Error(
-        "Failed to find browser context with id " + context_id));
-    return;
+    return protocol::Response::Error("Failed to find browser context with id " +
+                                     context_id);
   }
-
-  if (pending_context_disposals_.empty())
-    BrowserList::AddObserver(this);
-
-  pending_context_disposals_[context_id] = std::move(callback);
   Profile* profile = it->second->profile();
-  BrowserList::CloseAllBrowsersWithIncognitoProfile(
-      profile, base::DoNothing(), base::DoNothing(),
-      true /* skip_beforeunload */);
-}
-
-void TargetHandler::OnBrowserRemoved(Browser* browser) {
-  std::string context_id = browser->profile()->UniqueId();
-  auto pending_disposal = pending_context_disposals_.find(context_id);
-  if (pending_disposal == pending_context_disposals_.end())
-    return;
-  for (auto* opened_browser : *BrowserList::GetInstance()) {
-    if (opened_browser->profile() == browser->profile())
-      return;
+  for (auto* browser : *BrowserList::GetInstance()) {
+    if (browser->profile() == profile &&
+        !browser->IsAttemptingToCloseBrowser()) {
+      *out_success = false;
+      return protocol::Response::OK();
+    }
   }
-  auto it = registrations_.find(context_id);
-  // We cannot delete immediately here: the profile might still be referenced
-  // during the browser tier-down process.
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
-                                                  it->second.release());
   registrations_.erase(it);
-  pending_disposal->second->sendSuccess();
-  pending_context_disposals_.erase(pending_disposal);
-  if (pending_context_disposals_.empty())
-    BrowserList::RemoveObserver(this);
+  *out_success = true;
+  return protocol::Response::OK();
 }
diff --git a/chrome/browser/devtools/protocol/target_handler.h b/chrome/browser/devtools/protocol/target_handler.h
index 268d899..bfff3d0 100644
--- a/chrome/browser/devtools/protocol/target_handler.h
+++ b/chrome/browser/devtools/protocol/target_handler.h
@@ -11,14 +11,11 @@
 #include "chrome/browser/devtools/protocol/forward.h"
 #include "chrome/browser/devtools/protocol/target.h"
 #include "chrome/browser/media/router/presentation/independent_otr_profile_manager.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list_observer.h"
 #include "net/base/host_port_pair.h"
 
 using RemoteLocations = std::set<net::HostPortPair>;
 
-class TargetHandler : public protocol::Target::Backend,
-                      public BrowserListObserver {
+class TargetHandler : public protocol::Target::Backend {
  public:
   explicit TargetHandler(protocol::UberDispatcher* dispatcher);
   ~TargetHandler() override;
@@ -37,22 +34,16 @@
       protocol::Maybe<std::string> browser_context_id,
       protocol::Maybe<bool> enable_begin_frame_control,
       std::string* out_target_id) override;
-  void DisposeBrowserContext(
-      const std::string& context_id,
-      std::unique_ptr<DisposeBrowserContextCallback> callback) override;
+  protocol::Response DisposeBrowserContext(const std::string& context_id,
+                                           bool* out_success) override;
 
  private:
   void OnOriginalProfileDestroyed(Profile* profile);
 
-  void OnBrowserRemoved(Browser* browser) override;
-
   base::flat_map<
       std::string,
       std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>>
       registrations_;
-  base::flat_map<std::string, std::unique_ptr<DisposeBrowserContextCallback>>
-      pending_context_disposals_;
-
   RemoteLocations remote_locations_;
 
   base::WeakPtrFactory<TargetHandler> weak_factory_;
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index b11b31b..a58bf88 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -6,9 +6,12 @@
 
 #include <algorithm>
 #include <memory>
+#include <set>
+#include <vector>
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/json/json_string_value_serializer.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/path_service.h"
@@ -31,7 +34,6 @@
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_source.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
@@ -44,13 +46,13 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_util.h"
-#include "extensions/browser/notification_types.h"
 #include "extensions/browser/runtime_data.h"
 #include "extensions/common/api/declarative_net_request/constants.h"
 #include "extensions/common/api/declarative_net_request/test_utils.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/url_pattern.h"
+#include "extensions/test/extension_test_message_listener.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/test/test_data_directory.h"
@@ -184,6 +186,7 @@
                             kJSONRulesFilename, rules, hosts,
                             has_background_script_);
 
+    ExtensionTestMessageListener listener("ready", false /*will_reply*/);
     const Extension* extension = nullptr;
     switch (GetParam()) {
       case ExtensionLoadType::PACKED:
@@ -201,6 +204,10 @@
     // Ensure the ruleset is also loaded on the IO thread.
     content::RunAllTasksUntilIdle();
 
+    // Wait for the background page to load if needed.
+    if (has_background_script_)
+      WaitForBackgroundScriptToLoad(&listener, extension->id());
+
     // Ensure no load errors were reported.
     EXPECT_TRUE(LoadErrorReporter::GetInstance()->GetErrors()->empty());
 
@@ -220,7 +227,77 @@
                            {URLPattern::kAllUrlsPattern});
   }
 
+  void WaitForBackgroundScriptToLoad(ExtensionTestMessageListener* listener,
+                                     const ExtensionId& extension_id) {
+    ASSERT_TRUE(listener->WaitUntilSatisfied());
+    ASSERT_EQ(extension_id, listener->extension_id_for_message());
+  }
+
+  void AddWhitelistedPages(const ExtensionId& extension_id,
+                           const std::vector<std::string>& patterns) {
+    UpdateWhitelistedPages(extension_id, patterns, "addWhitelistedPages");
+  }
+
+  void RemoveWhitelistedPages(const ExtensionId& extension_id,
+                              const std::vector<std::string>& patterns) {
+    UpdateWhitelistedPages(extension_id, patterns, "removeWhitelistedPages");
+  }
+
+  // Verifies that the result of getWhitelistedPages call is the same as
+  // |expected_patterns|.
+  void VerifyGetWhitelistedPages(
+      const ExtensionId& extension_id,
+      const std::set<std::string>& expected_patterns) {
+    static constexpr char kScript[] = R"(
+      chrome.declarativeNetRequest.getWhitelistedPages(function(patterns) {
+        window.domAutomationController.send(chrome.runtime.lastError
+                                                ? 'error'
+                                                : JSON.stringify(patterns));
+      });
+    )";
+
+    const std::string result =
+        ExecuteScriptInBackgroundPage(extension_id, kScript);
+    ASSERT_NE("error", result);
+
+    // Parse |result| as a list and deserialize it to a set of strings.
+    std::unique_ptr<base::Value> value =
+        JSONStringValueDeserializer(result).Deserialize(
+            nullptr /*error_code*/, nullptr /*error_message*/);
+    ASSERT_TRUE(value);
+    ASSERT_TRUE(value->is_list());
+    std::set<std::string> patterns;
+    for (const auto& pattern_value : value->GetList()) {
+      ASSERT_TRUE(pattern_value.is_string());
+      patterns.insert(pattern_value.GetString());
+    }
+
+    EXPECT_EQ(expected_patterns, patterns);
+  }
+
  private:
+  void UpdateWhitelistedPages(const ExtensionId& extension_id,
+                              const std::vector<std::string>& patterns,
+                              const std::string& function_name) {
+    static constexpr char kScript[] = R"(
+      chrome.declarativeNetRequest.%s(%s, function() {
+        window.domAutomationController.send(chrome.runtime.lastError
+                                                ? 'error'
+                                                : 'success');
+      });
+    )";
+
+    // Serialize |patterns| to JSON.
+    std::unique_ptr<base::ListValue> list = ToListValue(patterns);
+    std::string json_string;
+    ASSERT_TRUE(JSONStringValueSerializer(&json_string).Serialize(*list));
+
+    EXPECT_EQ("success", ExecuteScriptInBackgroundPage(
+                             extension_id,
+                             base::StringPrintf(kScript, function_name.c_str(),
+                                                json_string.c_str())));
+  }
+
   base::ScopedTempDir temp_dir_;
   bool has_background_script_ = false;
 
@@ -1106,7 +1183,7 @@
       rules_2, "extension_2", {URLPattern::kAllUrlsPattern}));
   const std::string extension_id_2 = last_loaded_extension_id();
 
-  auto get_manifest_url = [](const std::string& extension_id) {
+  auto get_manifest_url = [](const ExtensionId& extension_id) {
     return GURL(base::StringPrintf("%s://%s/manifest.json",
                                    extensions::kExtensionScheme,
                                    extension_id.c_str()));
@@ -1137,37 +1214,13 @@
   ASSERT_TRUE(dnr_extension);
   EXPECT_EQ("Test extension", dnr_extension->name());
 
-  // Ensure the background page is ready before dispatching the script to it.
-  if (!ExtensionSystem::Get(profile())->runtime_data()->IsBackgroundPageReady(
-          dnr_extension)) {
-    content::WindowedNotificationObserver(
-        NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
-        content::Source<Extension>(dnr_extension))
-        .Wait();
-  }
+  constexpr char kGoogleDotCom[] = "https://www.google.com/";
 
-  // Whitelist "https://www.google.com/".
-  const char* script1 = R"(
-    chrome.declarativeNetRequest.addWhitelistedPages(
-        ['https://www.google.com/'], function() {
-          window.domAutomationController.send('success');
-        });
-  )";
-  EXPECT_EQ("success",
-            ExecuteScriptInBackgroundPage(last_loaded_extension_id(), script1));
+  // Whitelist |kGoogleDotCom|.
+  AddWhitelistedPages(dnr_extension->id(), {kGoogleDotCom});
 
   // Ensure that the page was whitelisted.
-  const char* script2 = R"(
-    chrome.declarativeNetRequest.getWhitelistedPages(function(patterns) {
-      if (patterns.length === 1 && patterns[0] === 'https://www.google.com/')
-        window.domAutomationController.send('success');
-      else
-        window.domAutomationController.send('error');
-    });
-  )";
-
-  EXPECT_EQ("success",
-            ExecuteScriptInBackgroundPage(last_loaded_extension_id(), script2));
+  VerifyGetWhitelistedPages(dnr_extension->id(), {kGoogleDotCom});
 }
 
 // Tests that the pages whitelisted using the page whitelisting API are
@@ -1191,46 +1244,24 @@
   ASSERT_TRUE(dnr_extension);
 
   // Ensure the background page is ready before dispatching the script to it.
+  // TODO(karandeepb): Remove the need to check IsBackgroundPageReady by
+  // creating the ExtensionTestMessageListener early. This should also ensure
+  // that the we start listening for messages from extension early enough to
+  // avoid any races. See crbug.com/838536.
   if (!ExtensionSystem::Get(profile())->runtime_data()->IsBackgroundPageReady(
           dnr_extension)) {
-    content::WindowedNotificationObserver(
-        NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
-        content::Source<Extension>(dnr_extension))
-        .Wait();
+    ExtensionTestMessageListener listener("ready", false /*will_reply*/);
+    WaitForBackgroundScriptToLoad(&listener, dnr_extension->id());
   }
 
-  const char* script1 = R"(
-    chrome.declarativeNetRequest.getWhitelistedPages(function(patterns) {
-        if (patterns.length === 1 && patterns[0] === "https://www.google.com/")
-          window.domAutomationController.send("success");
-        else
-          window.domAutomationController.send("error");
-    });
-  )";
-  ASSERT_EQ("success",
-            ExecuteScriptInBackgroundPage(dnr_extension->id(), script1));
+  constexpr char kGoogleDotCom[] = "https://www.google.com/";
 
-  // Remove "https://www.google.com/" from the whitelist.
-  const char* script2 = R"(
-    chrome.declarativeNetRequest.removeWhitelistedPages(
-      ["https://www.google.com/"], function() {
-        window.domAutomationController.send("success");
-    });
-  )";
-  ASSERT_EQ("success",
-            ExecuteScriptInBackgroundPage(dnr_extension->id(), script2));
+  VerifyGetWhitelistedPages(dnr_extension->id(), {kGoogleDotCom});
 
-  // Ensure that the page was removed from the whitelist.
-  const char* script3 = R"(
-    chrome.declarativeNetRequest.getWhitelistedPages(function(patterns) {
-        if (patterns.length === 0)
-          window.domAutomationController.send("success");
-        else
-          window.domAutomationController.send("error");
-    });
-  )";
-  EXPECT_EQ("success",
-            ExecuteScriptInBackgroundPage(dnr_extension->id(), script3));
+  // Remove |kGoogleDotCom| from the whitelist.
+  RemoveWhitelistedPages(dnr_extension->id(), {kGoogleDotCom});
+
+  VerifyGetWhitelistedPages(dnr_extension->id(), {});
 }
 
 // Test fixture to verify that host permissions for the request url and the
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index 2d8cb60..90c6838 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -96,8 +96,8 @@
   // Add 3 web contentses to the browser.
   content::WebContents* web_contentses[arraysize(tab_urls)];
   for (size_t i = 0; i < arraysize(tab_urls); ++i) {
-    std::unique_ptr<content::WebContents> web_contents = base::WrapUnique(
-        content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
+    std::unique_ptr<content::WebContents> web_contents =
+        content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
     content::WebContents* raw_web_contents = web_contents.get();
     web_contentses[i] = raw_web_contents;
     browser()->tab_strip_model()->AppendWebContents(std::move(web_contents),
@@ -157,8 +157,8 @@
   // Add 3 web contentses to the browser.
   content::WebContents* web_contentses[arraysize(tab_urls)];
   for (size_t i = 0; i < arraysize(tab_urls); ++i) {
-    std::unique_ptr<content::WebContents> web_contents = base::WrapUnique(
-        content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
+    std::unique_ptr<content::WebContents> web_contents =
+        content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
     content::WebContents* raw_web_contents = web_contents.get();
     web_contentses[i] = raw_web_contents;
     browser()->tab_strip_model()->AppendWebContents(std::move(web_contents),
@@ -248,8 +248,8 @@
           .Build();
   ASSERT_TRUE(extension);
 
-  std::unique_ptr<content::WebContents> web_contents = base::WrapUnique(
-      content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
+  std::unique_ptr<content::WebContents> web_contents =
+      content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
   content::WebContents* raw_web_contents = web_contents.get();
   ASSERT_TRUE(raw_web_contents);
   content::WebContentsTester* web_contents_tester =
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index 475fccad..f1dddbc 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -197,7 +197,7 @@
   void SetUp() override {
     testing::Test::SetUp();
     testing_profile_ = TestingProfile::Builder().Build();
-    contents_.reset(CreateTestWebContents());
+    contents_ = CreateTestWebContents();
     extension_info_map_ = new InfoMap();
     old_factory_ = resource_context_.GetRequestContext()->job_factory();
 
@@ -330,7 +330,7 @@
     return GetResult(std::move(request), test_delegate_.request_status());
   }
 
-  content::WebContents* CreateTestWebContents() {
+  std::unique_ptr<content::WebContents> CreateTestWebContents() {
     auto site_instance = content::SiteInstance::Create(browser_context());
     return content::WebContentsTester::CreateTestWebContents(
         browser_context(), std::move(site_instance));
diff --git a/chrome/browser/extensions/webstore_inline_installer_unittest.cc b/chrome/browser/extensions/webstore_inline_installer_unittest.cc
index 89143ed..163d71a7 100644
--- a/chrome/browser/extensions/webstore_inline_installer_unittest.cc
+++ b/chrome/browser/extensions/webstore_inline_installer_unittest.cc
@@ -70,7 +70,7 @@
 
 void WebstoreInlineInstallerTest::SetUp() {
   ChromeRenderViewHostTestHarness::SetUp();
-  web_contents_.reset(CreateTestWebContents());
+  web_contents_ = CreateTestWebContents();
 }
 
 void WebstoreInlineInstallerTest::TearDown() {
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 18232430..855bfa7 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -218,17 +218,18 @@
 }
 
 void GeolocationPermissionContextTests::AddNewTab(const GURL& url) {
-  content::WebContents* new_tab = CreateTestWebContents();
-  content::NavigationSimulator::NavigateAndCommitFromBrowser(new_tab, url);
+  std::unique_ptr<content::WebContents> new_tab = CreateTestWebContents();
+  content::NavigationSimulator::NavigateAndCommitFromBrowser(new_tab.get(),
+                                                             url);
 
   // Set up required helpers, and make this be as "tabby" as the code requires.
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  extensions::SetViewType(new_tab, extensions::VIEW_TYPE_TAB_CONTENTS);
+  extensions::SetViewType(new_tab.get(), extensions::VIEW_TYPE_TAB_CONTENTS);
 #endif
 
-  SetupRequestManager(new_tab);
+  SetupRequestManager(new_tab.get());
 
-  extra_tabs_.push_back(base::WrapUnique(new_tab));
+  extra_tabs_.push_back(std::move(new_tab));
 }
 
 void GeolocationPermissionContextTests::CheckTabContentsState(
diff --git a/chrome/browser/lifetime/browser_close_manager.cc b/chrome/browser/lifetime/browser_close_manager.cc
index cb42dd00..db0f58c 100644
--- a/chrome/browser/lifetime/browser_close_manager.cc
+++ b/chrome/browser/lifetime/browser_close_manager.cc
@@ -177,7 +177,7 @@
       // DestroyBrowser to make sure the browser is deleted and cleanup can
       // happen.
       while (browser->tab_strip_model()->count())
-        delete browser->tab_strip_model()->GetWebContentsAt(0);
+        browser->tab_strip_model()->DetachWebContentsAt(0);
       browser->window()->DestroyBrowser();
       // Destroying the browser should have removed it from the browser list.
       DCHECK(!base::ContainsValue(*BrowserList::GetInstance(), browser));
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
index 49b5890..41a8502 100644
--- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
+++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
@@ -248,18 +248,18 @@
           content::WebContentsTester::CreateTestWebContents(incognito_profile,
                                                             nullptr);
     }
-    return incognito_web_contents_;
+    return incognito_web_contents_.get();
   }
 
   void TearDown() override {
     // We must delete the incognito WC first, as that triggers observers which
     // require RenderViewHost, etc., that in turn are deleted by
     // RenderViewHostTestHarness::TearDown().
-    delete incognito_web_contents_;
+    incognito_web_contents_.reset();
     PresentationServiceDelegateImplTest::TearDown();
   }
 
-  content::WebContents* incognito_web_contents_;
+  std::unique_ptr<content::WebContents> incognito_web_contents_;
 };
 
 TEST_F(PresentationServiceDelegateImplTest, AddScreenAvailabilityListener) {
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index 2be9c73..62e5f89 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -470,14 +470,14 @@
   no_permissions_extension_ =
       AddMediaGalleriesApp("no", read_permissions, profile_.get());
 
-  single_web_contents_.reset(
-      content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
+  single_web_contents_ =
+      content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL);
   single_rph_ = rph_factory->ReleaseRPH(profile_.get());
 
-  shared_web_contents1_.reset(
-      content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
-  shared_web_contents2_.reset(
-      content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
+  shared_web_contents1_ =
+      content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL);
+  shared_web_contents2_ =
+      content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL);
   shared_rph_ = rph_factory->ReleaseRPH(profile_.get());
 }
 
diff --git a/chrome/browser/metrics/tab_stats_data_store_unittest.cc b/chrome/browser/metrics/tab_stats_data_store_unittest.cc
index 672fcaf1..561fa34 100644
--- a/chrome/browser/metrics/tab_stats_data_store_unittest.cc
+++ b/chrome/browser/metrics/tab_stats_data_store_unittest.cc
@@ -69,7 +69,7 @@
 TEST_F(TabStatsDataStoreTest, TrackTabUsageDuringInterval) {
   std::vector<std::unique_ptr<content::WebContents>> web_contents_vec;
   for (size_t i = 0; i < 3; ++i) {
-    web_contents_vec.emplace_back(base::WrapUnique(CreateTestWebContents()));
+    web_contents_vec.emplace_back(CreateTestWebContents());
     // Make sure that these WebContents are initially not visible.
     web_contents_vec.back()->WasHidden();
   }
@@ -142,12 +142,12 @@
   // Make sure that the tab stats get properly copied when a tab is replaced.
   TabStatsDataStore::TabStateDuringInterval tab_stats_copy =
       interval_map->find(web_contents_id_vec[1])->second;
-  content::WebContents* new_contents = CreateTestWebContents();
+  std::unique_ptr<content::WebContents> new_contents = CreateTestWebContents();
   content::WebContents* old_contents = web_contents_vec[1].get();
-  data_store_->OnTabReplaced(old_contents, new_contents);
-  EXPECT_EQ(data_store_->GetTabIDForTesting(new_contents).value(),
+  data_store_->OnTabReplaced(old_contents, new_contents.get());
+  EXPECT_EQ(data_store_->GetTabIDForTesting(new_contents.get()).value(),
             web_contents_id_vec[1]);
-  web_contents_vec[1].reset(new_contents);
+  web_contents_vec[1] = std::move(new_contents);
   // |old_contents| is invalid starting from here.
   EXPECT_FALSE(data_store_->GetTabIDForTesting(old_contents));
   auto iter = interval_map->find(web_contents_id_vec[1]);
diff --git a/chrome/browser/metrics/tab_stats_tracker_unittest.cc b/chrome/browser/metrics/tab_stats_tracker_unittest.cc
index d7b25bf..ac41f6f 100644
--- a/chrome/browser/metrics/tab_stats_tracker_unittest.cc
+++ b/chrome/browser/metrics/tab_stats_tracker_unittest.cc
@@ -40,9 +40,10 @@
                  ChromeRenderViewHostTestHarness* test_harness) {
     EXPECT_TRUE(test_harness);
     for (size_t i = 0; i < tab_count; ++i) {
-      content::WebContents* tab = test_harness->CreateTestWebContents();
-      tab_stats_data_store()->OnTabAdded(tab);
-      tabs_.emplace_back(base::WrapUnique(tab));
+      std::unique_ptr<content::WebContents> tab =
+          test_harness->CreateTestWebContents();
+      tab_stats_data_store()->OnTabAdded(tab.get());
+      tabs_.emplace_back(std::move(tab));
     }
     return tab_stats_data_store()->tab_stats().total_tab_count;
   }
@@ -291,7 +292,7 @@
 
   std::vector<std::unique_ptr<content::WebContents>> web_contentses;
   for (size_t i = 0; i < 4; ++i) {
-    web_contentses.emplace_back(base::WrapUnique(CreateTestWebContents()));
+    web_contentses.emplace_back(CreateTestWebContents());
     // Make sure that these WebContents are initially not visible.
     web_contentses[i]->WasHidden();
     tab_stats_tracker_->OnInitialOrInsertedTab(web_contentses[i].get());
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index 58c58a9..bea310bb 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -825,7 +825,7 @@
   NotificationLaunchId launch_id(base::UTF16ToUTF8(
       command_line.GetSwitchValueNative(switches::kNotificationLaunchId)));
   if (!launch_id.is_valid()) {
-    LogActivationStatus(ActivationStatus::ACTIVATION_INVALID_LAUNCH_ID);
+    LogActivationStatus(ActivationStatus::INVALID_LAUNCH_ID);
     return false;
   }
 
@@ -852,11 +852,10 @@
 std::string NotificationPlatformBridgeWin::GetProfileIdFromLaunchId(
     const base::string16& launch_id_str) {
   NotificationLaunchId launch_id(base::UTF16ToUTF8(launch_id_str));
-  if (!launch_id.is_valid()) {
-    LogActivationStatus(ActivationStatus::GET_PROFILE_ID_INVALID_LAUNCH_ID);
-    return std::string();
-  }
-  return launch_id.profile_id();
+
+  // The launch_id_invalid failure is logged via HandleActivation(). We don't
+  // re-log it here, which would skew the UMA failure metrics.
+  return launch_id.is_valid() ? launch_id.profile_id() : std::string();
 }
 
 // static
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_metrics.h b/chrome/browser/notifications/notification_platform_bridge_win_metrics.h
index 1a0364e..3db596a 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win_metrics.h
+++ b/chrome/browser/notifications/notification_platform_bridge_win_metrics.h
@@ -114,8 +114,9 @@
 // numeric values should never be reused.
 enum class ActivationStatus {
   SUCCESS = 0,
-  GET_PROFILE_ID_INVALID_LAUNCH_ID = 1,
-  ACTIVATION_INVALID_LAUNCH_ID = 2,
+  DEPRECATED_GET_PROFILE_ID_INVALID_LAUNCH_ID = 1,
+  DEPRECATED_ACTIVATION_INVALID_LAUNCH_ID = 2,
+  INVALID_LAUNCH_ID = 3,
   COUNT  // Must be the final value.
 };
 
diff --git a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
index 8d2293c..65787da2 100644
--- a/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
+++ b/chrome/browser/ntp_snippets/content_suggestions_service_factory.cc
@@ -81,14 +81,12 @@
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
 #include "chrome/browser/offline_pages/request_coordinator_factory.h"
-#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
 #include "components/ntp_snippets/remote/prefetched_pages_tracker_impl.h"
 #include "components/offline_pages/core/background/request_coordinator.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_model.h"
 #include "components/offline_pages/core/prefetch/prefetch_service.h"
 #include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
 #endif
 
 using bookmarks::BookmarkModel;
@@ -107,7 +105,6 @@
 using ntp_snippets::IsBookmarkProviderEnabled;
 using ntp_snippets::IsDownloadsProviderEnabled;
 using ntp_snippets::IsForeignSessionsProviderEnabled;
-using ntp_snippets::IsRecentTabProviderEnabled;
 using ntp_snippets::PersistentScheduler;
 using ntp_snippets::PrefetchedPagesTracker;
 using ntp_snippets::RemoteSuggestionsDatabase;
@@ -131,7 +128,6 @@
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 using ntp_snippets::PrefetchedPagesTrackerImpl;
-using ntp_snippets::RecentTabSuggestionsProvider;
 using offline_pages::OfflinePageModel;
 using offline_pages::OfflinePageModelFactory;
 using offline_pages::RequestCoordinator;
@@ -154,23 +150,6 @@
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 
-void RegisterRecentTabProviderIfEnabled(ContentSuggestionsService* service,
-                                        Profile* profile,
-                                        OfflinePageModel* offline_page_model) {
-  if (!IsRecentTabProviderEnabled()) {
-    return;
-  }
-
-  RequestCoordinator* request_coordinator =
-      RequestCoordinatorFactory::GetForBrowserContext(profile);
-  offline_pages::DownloadUIAdapter* ui_adapter = offline_pages::
-      RecentTabsUIAdapterDelegate::GetOrCreateRecentTabsUIAdapter(
-          offline_page_model, request_coordinator);
-  auto provider = std::make_unique<RecentTabSuggestionsProvider>(
-      service, ui_adapter, profile->GetPrefs());
-  service->RegisterProvider(std::move(provider));
-}
-
 void RegisterWithPrefetching(ContentSuggestionsService* service,
                              Profile* profile) {
   // There's a circular dependency between ContentSuggestionsService and
@@ -497,7 +476,6 @@
 #endif  // OS_ANDROID
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
-  RegisterRecentTabProviderIfEnabled(service, profile, offline_page_model);
   RegisterWithPrefetching(service, profile);
 #endif
 
diff --git a/chrome/browser/ntp_snippets/dependent_features.cc b/chrome/browser/ntp_snippets/dependent_features.cc
index a0ca616..5ac907f 100644
--- a/chrome/browser/ntp_snippets/dependent_features.cc
+++ b/chrome/browser/ntp_snippets/dependent_features.cc
@@ -46,14 +46,6 @@
              ntp_snippets::kBookmarkSuggestionsFeature);
 }
 
-bool IsRecentTabProviderEnabled() {
-  return !AreNtpShortcutsEnabled() &&
-         base::FeatureList::IsEnabled(
-             ntp_snippets::kRecentOfflineTabSuggestionsFeature) &&
-         base::FeatureList::IsEnabled(
-             offline_pages::kOffliningRecentPagesFeature);
-}
-
 bool IsForeignSessionsProviderEnabled() {
   return !AreNtpShortcutsEnabled() &&
          base::FeatureList::IsEnabled(
diff --git a/chrome/browser/ntp_snippets/dependent_features.h b/chrome/browser/ntp_snippets/dependent_features.h
index 801621e5..38a8b22 100644
--- a/chrome/browser/ntp_snippets/dependent_features.h
+++ b/chrome/browser/ntp_snippets/dependent_features.h
@@ -17,8 +17,6 @@
 
 bool IsBookmarkProviderEnabled();
 
-bool IsRecentTabProviderEnabled();
-
 bool IsPhysicalWebPageProviderEnabled();
 
 bool IsForeignSessionsProviderEnabled();
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc
index 8a5e2b5..fa9ce4f 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.cc
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -42,7 +42,6 @@
 #include "components/offline_pages/core/offline_page_item.h"
 #include "components/offline_pages/core/offline_page_model.h"
 #include "components/offline_pages/core/offline_page_types.h"
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
 #include "components/offline_pages/core/request_header/offline_page_header.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
@@ -821,19 +820,6 @@
       request_ids, base::Bind(&OnRemoveRequestsDone, j_callback_ref));
 }
 
-void OfflinePageBridge::RegisterRecentTab(JNIEnv* env,
-                                          const JavaParamRef<jobject>& obj,
-                                          int tab_id) {
-  RequestCoordinator* request_coordinator =
-      RequestCoordinatorFactory::GetForBrowserContext(browser_context_);
-
-  RecentTabsUIAdapterDelegate* ui_adapter_delegate =
-      RecentTabsUIAdapterDelegate::FromDownloadUIAdapter(
-          RecentTabsUIAdapterDelegate::GetOrCreateRecentTabsUIAdapter(
-              offline_page_model_, request_coordinator));
-  ui_adapter_delegate->RegisterTab(tab_id);
-}
-
 void OfflinePageBridge::WillCloseTab(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
@@ -850,19 +836,6 @@
     tab_helper->WillCloseTab();
 }
 
-void OfflinePageBridge::UnregisterRecentTab(JNIEnv* env,
-                                            const JavaParamRef<jobject>& obj,
-                                            int tab_id) {
-  RequestCoordinator* request_coordinator =
-      RequestCoordinatorFactory::GetForBrowserContext(browser_context_);
-
-  RecentTabsUIAdapterDelegate* ui_adapter_delegate =
-      RecentTabsUIAdapterDelegate::FromDownloadUIAdapter(
-          RecentTabsUIAdapterDelegate::GetOrCreateRecentTabsUIAdapter(
-              offline_page_model_, request_coordinator));
-  ui_adapter_delegate->UnregisterTab(tab_id);
-}
-
 void OfflinePageBridge::ScheduleDownload(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h
index 9e49a6a9..489c65f 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.h
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -166,15 +166,9 @@
       const base::android::JavaParamRef<jlongArray>& j_request_ids_array,
       const base::android::JavaParamRef<jobject>& j_callback_obj);
 
-  void RegisterRecentTab(JNIEnv* env,
-                         const base::android::JavaParamRef<jobject>& obj,
-                         int tab_id);
   void WillCloseTab(JNIEnv* env,
                     const base::android::JavaParamRef<jobject>& obj,
                     const base::android::JavaParamRef<jobject>& j_web_contents);
-  void UnregisterRecentTab(JNIEnv* env,
-                           const base::android::JavaParamRef<jobject>& obj,
-                           int tab_id);
   void ScheduleDownload(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index b7ba0b7..c4aafae 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -182,7 +182,6 @@
 #include "components/ntp_snippets/breaking_news/breaking_news_gcm_app_handler.h"
 #include "components/ntp_snippets/breaking_news/subscription_manager_impl.h"
 #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h"
-#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
 #include "components/ntp_tiles/popular_sites_impl.h"
 #else
 #include "chrome/browser/gcm/gcm_product_util.h"
@@ -305,6 +304,9 @@
 // Deprecated 4/2018.
 const char kDismissedPhysicalWebPageSuggestions[] =
     "ntp_suggestions.physical_web.dismissed_ids";
+// Deprecated 5/2018.
+const char kDismissedRecentOfflineTabSuggestions[] =
+    "ntp_suggestions.offline_pages.recent_tabs.dismissed_ids";
 #else
 // Deprecated 1/2018.
 const char kShowFirstRunBubbleOption[] = "show-first-run-bubble-option";
@@ -330,6 +332,7 @@
 
 #if defined(OS_ANDROID)
   registry->RegisterListPref(kDismissedPhysicalWebPageSuggestions);
+  registry->RegisterListPref(kDismissedRecentOfflineTabSuggestions);
 #endif
 }
 
@@ -589,7 +592,6 @@
   DownloadSuggestionsProvider::RegisterProfilePrefs(registry);
   ntp_snippets::BreakingNewsGCMAppHandler::RegisterProfilePrefs(registry);
   ntp_snippets::ClickBasedCategoryRanker::RegisterProfilePrefs(registry);
-  ntp_snippets::RecentTabSuggestionsProvider::RegisterProfilePrefs(registry);
   ntp_snippets::SubscriptionManagerImpl::RegisterProfilePrefs(registry);
   OomInterventionDecider::RegisterProfilePrefs(registry);
 #endif  // defined(OS_ANDROID)
@@ -721,5 +723,8 @@
 #if defined(OS_ANDROID)
   // Added 4/2018
   profile_prefs->ClearPref(kDismissedPhysicalWebPageSuggestions);
+
+  // Added 5/2018
+  profile_prefs->ClearPref(kDismissedRecentOfflineTabSuggestions);
 #endif  // defined(OS_ANDROID)
 }
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index a54aa04..aae0c8e 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -1095,11 +1095,6 @@
 }
 
 void PrerenderManager::DeleteOldWebContents() {
-  for (WebContents* web_contents : old_web_contents_list_) {
-    // TODO(dominich): should we use Instant Unload Handler here?
-    // Or should |old_web_contents_list_| contain unique_ptrs?
-    delete web_contents;
-  }
   old_web_contents_list_.clear();
 }
 
@@ -1149,7 +1144,7 @@
 void PrerenderManager::ScheduleDeleteOldWebContents(
     std::unique_ptr<WebContents> tab,
     OnCloseWebContentsDeleter* deleter) {
-  old_web_contents_list_.push_back(tab.release());
+  old_web_contents_list_.push_back(std::move(tab));
   PostCleanupTask();
 
   if (!deleter)
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 10f37d8f..c5d7f27 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -576,7 +576,7 @@
   // Track time of last prerender to limit prerender spam.
   base::TimeTicks last_prerender_start_time_;
 
-  std::vector<content::WebContents*> old_web_contents_list_;
+  std::vector<std::unique_ptr<content::WebContents>> old_web_contents_list_;
 
   std::vector<std::unique_ptr<OnCloseWebContentsDeleter>>
       on_close_web_contents_deleters_;
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc
index 003944a..14fb359 100644
--- a/chrome/browser/printing/background_printing_manager.cc
+++ b/chrome/browser/printing/background_printing_manager.cc
@@ -31,7 +31,6 @@
 
  private:
   void RenderProcessGone(base::TerminationStatus status) override;
-  void WebContentsDestroyed() override;
 
   BackgroundPrintingManager* manager_;
 };
@@ -46,9 +45,6 @@
     base::TerminationStatus status) {
   manager_->DeletePreviewContents(web_contents());
 }
-void BackgroundPrintingManager::Observer::WebContentsDestroyed() {
-  manager_->DeletePreviewContents(web_contents());
-}
 
 BackgroundPrintingManager::BackgroundPrintingManager() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -64,27 +60,31 @@
 }
 
 void BackgroundPrintingManager::OwnPrintPreviewDialog(
-    WebContents* preview_dialog) {
+    std::unique_ptr<WebContents> preview_dialog) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(PrintPreviewDialogController::IsPrintPreviewURL(
       preview_dialog->GetURL()));
-  CHECK(!HasPrintPreviewDialog(preview_dialog));
+  CHECK(!HasPrintPreviewDialog(preview_dialog.get()));
 
-  printing_contents_map_[preview_dialog] =
-      std::make_unique<Observer>(this, preview_dialog);
+  WebContents* raw_preview_dialog = preview_dialog.get();
+  PrintingContents printing_contents;
+  printing_contents.observer =
+      std::make_unique<Observer>(this, raw_preview_dialog);
+  printing_contents.contents = std::move(preview_dialog);
+  printing_contents_map_[raw_preview_dialog] = std::move(printing_contents);
 
   // Watch for print jobs finishing. Everything else is watched for by the
   // Observer. TODO(avi, cait): finish the job of removing this last
   // notification.
   registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
-                 content::Source<WebContents>(preview_dialog));
+                 content::Source<WebContents>(raw_preview_dialog));
 
   // Activate the initiator.
   PrintPreviewDialogController* dialog_controller =
       PrintPreviewDialogController::GetInstance();
   if (!dialog_controller)
     return;
-  WebContents* initiator = dialog_controller->GetInitiator(preview_dialog);
+  WebContents* initiator = dialog_controller->GetInitiator(raw_preview_dialog);
   if (!initiator)
     return;
   initiator->GetDelegate()->ActivateContents(initiator);
@@ -131,12 +131,15 @@
   // Stop all observation ...
   registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
                     content::Source<WebContents>(preview_contents));
+  std::unique_ptr<WebContents> contents_to_delete =
+      std::move(i->second.contents);
   printing_contents_map_.erase(i);
 
   // ... and mortally wound the contents. Deletion immediately is not a good
   // idea in case this was triggered by |preview_contents| far up the
   // callstack. (Trace where the NOTIFICATION_PRINT_JOB_RELEASED comes from.)
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, preview_contents);
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+      FROM_HERE, std::move(contents_to_delete));
 }
 
 std::set<content::WebContents*> BackgroundPrintingManager::CurrentContentSet() {
@@ -152,4 +155,12 @@
   return base::ContainsKey(printing_contents_map_, preview_dialog);
 }
 
+BackgroundPrintingManager::PrintingContents::PrintingContents() = default;
+BackgroundPrintingManager::PrintingContents::~PrintingContents() = default;
+BackgroundPrintingManager::PrintingContents::PrintingContents(
+    PrintingContents&&) = default;
+BackgroundPrintingManager::PrintingContents&
+BackgroundPrintingManager::PrintingContents::operator=(PrintingContents&&) =
+    default;
+
 }  // namespace printing
diff --git a/chrome/browser/printing/background_printing_manager.h b/chrome/browser/printing/background_printing_manager.h
index ea211ad..2042a23 100644
--- a/chrome/browser/printing/background_printing_manager.h
+++ b/chrome/browser/printing/background_printing_manager.h
@@ -36,7 +36,8 @@
   // Takes ownership of |preview_dialog| and deletes it when |preview_dialog|
   // finishes printing. This removes |preview_dialog| from its ConstrainedDialog
   // and hides it from the user.
-  void OwnPrintPreviewDialog(content::WebContents* preview_dialog);
+  void OwnPrintPreviewDialog(
+      std::unique_ptr<content::WebContents> preview_dialog);
 
   // Returns true if |printing_contents_map_| contains |preview_dialog|.
   bool HasPrintPreviewDialog(content::WebContents* preview_dialog);
@@ -60,9 +61,21 @@
   void DeletePreviewContents(content::WebContents* preview_contents);
 
   // A map from print preview WebContentses (managed by
-  // BackgroundPrintingManager) to the Observers that observe them.
-  std::map<content::WebContents*, std::unique_ptr<Observer>>
-      printing_contents_map_;
+  // BackgroundPrintingManager) to the Observers that observe them and the owned
+  // version of the WebContents.
+  struct PrintingContents {
+    PrintingContents();
+    ~PrintingContents();
+    PrintingContents(PrintingContents&&);
+    PrintingContents& operator=(PrintingContents&&);
+
+    std::unique_ptr<content::WebContents> contents;
+    std::unique_ptr<Observer> observer;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(PrintingContents);
+  };
+  std::map<content::WebContents*, PrintingContents> printing_contents_map_;
 
   content::NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc b/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
index 26144af4..c78a7f61 100644
--- a/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
+++ b/chrome/browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc
@@ -95,7 +95,7 @@
 
   std::unique_ptr<content::WebContents> opener;
   if (!no_opener_) {
-    opener.reset(CreateTestWebContents());
+    opener = CreateTestWebContents();
     content::WebContentsTester::For(web_contents())->SetOpener(opener.get());
   }
 
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
index 6802a3ff..9c06117 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source_unittest.cc
@@ -237,7 +237,7 @@
  private:
   std::unique_ptr<content::WebContents> CreateAndNavigateWebContents() {
     std::unique_ptr<content::WebContents> web_contents =
-        base::WrapUnique(CreateTestWebContents());
+        CreateTestWebContents();
     // Commit an URL to allow discarding.
     content::WebContentsTester::For(web_contents.get())
         ->NavigateAndCommit(GURL("https://www.example.com"));
@@ -320,7 +320,7 @@
   TabLifecycleUnitExternal* tab_lifecycle_unit_external =
       source_->GetTabLifecycleUnitExternal(original_web_contents);
   std::unique_ptr<content::WebContents> new_web_contents =
-      base::WrapUnique(CreateTestWebContents());
+      CreateTestWebContents();
   content::WebContents* raw_new_web_contents = new_web_contents.get();
   std::unique_ptr<content::WebContents> original_web_contents_deleter =
       tab_strip_model_->ReplaceWebContentsAt(1, std::move(new_web_contents));
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
index 694939d..7d2f440d 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -74,7 +74,7 @@
     ChromeRenderViewHostTestHarness::SetUp();
 
     std::unique_ptr<content::WebContents> test_web_contents =
-        base::WrapUnique(CreateTestWebContents());
+        CreateTestWebContents();
     web_contents_ = test_web_contents.get();
     // Commit an URL to allow discarding.
     content::WebContentsTester::For(web_contents_)
@@ -86,7 +86,7 @@
     web_contents_->WasHidden();
 
     std::unique_ptr<content::WebContents> second_web_contents =
-        base::WrapUnique(CreateTestWebContents());
+        CreateTestWebContents();
     content::WebContents* raw_second_web_contents = second_web_contents.get();
     tab_strip_model_->AppendWebContents(std::move(second_web_contents), false);
     raw_second_web_contents->WasHidden();
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc b/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
index c47138f..cfa49164 100644
--- a/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_load_tracker_unittest.cc
@@ -96,9 +96,9 @@
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
 
-    contents1_.reset(CreateTestWebContents());
-    contents2_.reset(CreateTestWebContents());
-    contents3_.reset(CreateTestWebContents());
+    contents1_ = CreateTestWebContents();
+    contents2_ = CreateTestWebContents();
+    contents3_ = CreateTestWebContents();
 
     tracker_.AddObserver(&observer_);
   }
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 7b84b37d..8a89957 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -157,8 +157,7 @@
   }
 
   std::unique_ptr<WebContents> CreateWebContents() {
-    std::unique_ptr<WebContents> web_contents =
-        base::WrapUnique(CreateTestWebContents());
+    std::unique_ptr<WebContents> web_contents = CreateTestWebContents();
     // Commit an URL to allow discarding.
     content::WebContentsTester::For(web_contents.get())
         ->NavigateAndCommit(GURL("https://www.example.com"));
@@ -170,7 +169,7 @@
     tab_manager_ = g_browser_process->GetTabManager();
   }
 
-  void TearDown() override {
+  void ResetState() {
     // NavigationHandles and NavigationThrottles must be deleted before the
     // associated WebContents.
     nav_handle1_.reset();
@@ -186,6 +185,10 @@
     contents1_.reset();
     contents2_.reset();
     contents3_.reset();
+  }
+
+  void TearDown() override {
+    ResetState();
 
     task_runner_->RunUntilIdle();
     scoped_context_.reset();
@@ -195,12 +198,12 @@
   void PrepareTabs(const char* url1 = kTestUrl,
                    const char* url2 = kTestUrl,
                    const char* url3 = kTestUrl) {
-    nav_handle1_ = CreateTabAndNavigation(url1);
-    nav_handle2_ = CreateTabAndNavigation(url2);
-    nav_handle3_ = CreateTabAndNavigation(url3);
-    contents1_ = base::WrapUnique(nav_handle1_->GetWebContents());
-    contents2_ = base::WrapUnique(nav_handle2_->GetWebContents());
-    contents3_ = base::WrapUnique(nav_handle3_->GetWebContents());
+    contents1_ = CreateTestWebContents();
+    nav_handle1_ = CreateTabAndNavigation(url1, contents1_.get());
+    contents2_ = CreateTestWebContents();
+    nav_handle2_ = CreateTabAndNavigation(url2, contents2_.get());
+    contents3_ = CreateTestWebContents();
+    nav_handle3_ = CreateTabAndNavigation(url3, contents3_.get());
 
     contents1_->WasHidden();
     contents2_->WasHidden();
@@ -258,8 +261,9 @@
   }
 
  protected:
-  std::unique_ptr<NavigationHandle> CreateTabAndNavigation(const char* url) {
-    content::WebContents* web_contents = CreateTestWebContents();
+  std::unique_ptr<NavigationHandle> CreateTabAndNavigation(
+      const char* url,
+      content::WebContents* web_contents) {
     TabUIHelper::CreateForWebContents(web_contents);
     return content::NavigationHandle::CreateNavigationHandleForTesting(
         GURL(url), web_contents->GetMainFrame());
@@ -705,6 +709,7 @@
   EXPECT_FALSE(tab_manager1.IsNavigationDelayedForTest(nav_handle1_.get()));
   EXPECT_TRUE(tab_manager1.IsNavigationDelayedForTest(nav_handle2_.get()));
   EXPECT_TRUE(tab_manager1.IsNavigationDelayedForTest(nav_handle3_.get()));
+  ResetState();
 
   TabManager tab_manager2;
   tab_manager2.SetLoadingSlotsForTest(2);
@@ -712,6 +717,7 @@
   EXPECT_FALSE(tab_manager2.IsNavigationDelayedForTest(nav_handle1_.get()));
   EXPECT_FALSE(tab_manager2.IsNavigationDelayedForTest(nav_handle2_.get()));
   EXPECT_TRUE(tab_manager2.IsNavigationDelayedForTest(nav_handle3_.get()));
+  ResetState();
 
   TabManager tab_manager3;
   tab_manager3.SetLoadingSlotsForTest(3);
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
index a48f671..9f613299 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data_unittest.cc
@@ -45,8 +45,8 @@
 
   TabManager::WebContentsData* CreateWebContentsAndTabData(
       std::unique_ptr<WebContents>* web_contents) {
-    web_contents->reset(
-        WebContentsTester::CreateTestWebContents(browser_context(), nullptr));
+    *web_contents =
+        WebContentsTester::CreateTestWebContents(browser_context(), nullptr);
     TabManager::WebContentsData::CreateForWebContents(web_contents->get());
     return TabManager::WebContentsData::FromWebContents(web_contents->get());
   }
diff --git a/chrome/browser/resources/gaia_auth_host/authenticator.js b/chrome/browser/resources/gaia_auth_host/authenticator.js
index 76c58c3..f926d3cb 100644
--- a/chrome/browser/resources/gaia_auth_host/authenticator.js
+++ b/chrome/browser/resources/gaia_auth_host/authenticator.js
@@ -704,7 +704,9 @@
       return;
     }
     // TODO(https://crbug.com/837107): remove this once API is fully stabilized.
-    if (!this.services_ && !this.email_.endsWith('@gmail.com')) {
+    // @example.com is used in tests.
+    if (!this.services_ && !this.email_.endsWith('@gmail.com') &&
+        !this.email_.endsWith('@example.com')) {
       console.warn('Forcing empty services.');
       this.services_ = [];
     }
diff --git a/chrome/browser/resources/print_preview/new/app.html b/chrome/browser/resources/print_preview/new/app.html
index 7cb5fa0d..292cf56 100644
--- a/chrome/browser/resources/print_preview/new/app.html
+++ b/chrome/browser/resources/print_preview/new/app.html
@@ -79,61 +79,64 @@
         <print-preview-destination-settings id="destinationSettings"
             destination="[[destination_]]"
             destination-store="[[destinationStore_]]"
-            invitation-store="[[invitationStore_]]"
+            invitation-store="[[invitationStore_]]" class="settings-section"
             disabled="[[controlsDisabled_]]" state="[[state]]"
             recent-destinations="[[recentDestinations_]]"
             user-info="{{userInfo_}}" available>
         </print-preview-destination-settings>
         <print-preview-pages-settings settings="{{settings}}"
-            document-info="[[documentInfo_]]" disabled="[[controlsDisabled_]]"
+            document-info="[[documentInfo_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.pages.available]]">
         </print-preview-pages-settings>
         <print-preview-copies-settings settings="{{settings}}"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.copies.available]]">
         </print-preview-copies-settings>
         <print-preview-layout-settings settings="{{settings}}"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.layout.available]]">
         </print-preview-layout-settings>
         <print-preview-color-settings settings="{{settings}}"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.color.available]]">
         </print-preview-color-settings>
         <print-preview-more-settings settings-expanded="{{settingsExpanded_}}"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[shouldShowMoreSettings_]]">
         </print-preview-more-settings>
         <print-preview-media-size-settings settings="{{settings}}"
             capability="[[destination_.capabilities.printer.media_size]]"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.mediaSize.available]]" collapsible>
         </print-preview-media-size-settings>
         <print-preview-margins-settings settings="{{settings}}"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.margins.available]]" collapsible>
         </print-preview-margins-settings>
         <print-preview-dpi-settings settings="{{settings}}"
             capability="[[destination_.capabilities.printer.dpi]]"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.dpi.available]]" collapsible>
         </print-preview-dpi-settings>
         <print-preview-scaling-settings settings="{{settings}}"
-            document-info="[[documentInfo_]]" disabled="[[controlsDisabled_]]"
+            document-info="[[documentInfo_]]" class="settings-section"
+            disabled="[[controlsDisabled_]]"
             available="[[settings.scaling.available]]" collapsible>
         </print-preview-scaling-settings>
         <print-preview-other-options-settings settings="{{settings}}"
-            disabled="[[controlsDisabled_]]"
+            class="settings-section" disabled="[[controlsDisabled_]]"
             available="[[settings.otherOptions.available]]" collapsible>
         </print-preview-other-options-settings>
         <print-preview-advanced-options-settings settings="{{settings}}"
+            class="settings-section"
             destination="[[destination_]]" disabled="[[controlsDisabled_]]"
             available="[[settings.vendorItems.available]]" collapsible>
         </print-preview-advanced-options-settings>
 <if expr="not chromeos">
         <print-preview-link-container destination="[[destination_]]"
             app-kiosk-mode="[[isInAppKioskMode_]]"
-            disabled="[[controlsDisabled_]]" available
+            disabled="[[controlsDisabled_]]"
 <if expr="is_macosx">
             on-open-pdf-in-preview="onOpenPdfInPreview_"
 </if>
diff --git a/chrome/browser/resources/print_preview/new/app.js b/chrome/browser/resources/print_preview/new/app.js
index ee0eae5..b8412aaf 100644
--- a/chrome/browser/resources/print_preview/new/app.js
+++ b/chrome/browser/resources/print_preview/new/app.js
@@ -542,15 +542,16 @@
 
   /** Changes the visibility of settings sections. */
   updateSettingsVisibility_: function() {
-    Array.from(this.$.settingsSections.children).forEach(section => {
-      if (!section.available ||
-          (section.collapsible && this.shouldShowMoreSettings_ &&
-           !this.settingsExpanded_)) {
-        section.hide();
-        return;
-      }
-      section.show();
-    });
+    Array.from(this.shadowRoot.querySelectorAll('.settings-section'))
+        .forEach(section => {
+          if (!section.available ||
+              (section.collapsible && this.shouldShowMoreSettings_ &&
+               !this.settingsExpanded_)) {
+            section.hide();
+            return;
+          }
+          section.show();
+        });
   },
 
   /** @private */
diff --git a/chrome/browser/resources/print_preview/new/compiled_resources2.gyp b/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
index 818f1d97..dd5aeaa9 100644
--- a/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
+++ b/chrome/browser/resources/print_preview/new/compiled_resources2.gyp
@@ -208,7 +208,6 @@
         '../data/compiled_resources2.gyp:destination',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        'settings_section_behavior',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/print_preview/new/link_container.html b/chrome/browser/resources/print_preview/new/link_container.html
index 48b03a85..5fca983 100644
--- a/chrome/browser/resources/print_preview/new/link_container.html
+++ b/chrome/browser/resources/print_preview/new/link_container.html
@@ -6,7 +6,6 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="../data/destination.html">
 <link rel="import" href="print_preview_shared_css.html">
-<link rel="import" href="settings_section_behavior.html">
 <link rel="import" href="throbber_css.html">
 
 <dom-module id="print-preview-link-container">
diff --git a/chrome/browser/resources/print_preview/new/link_container.js b/chrome/browser/resources/print_preview/new/link_container.js
index 9dd09a6..235de40a 100644
--- a/chrome/browser/resources/print_preview/new/link_container.js
+++ b/chrome/browser/resources/print_preview/new/link_container.js
@@ -5,8 +5,6 @@
 Polymer({
   is: 'print-preview-link-container',
 
-  behaviors: [print_preview_new.SettingsSectionBehavior],
-
   properties: {
     appKioskMode: Boolean,
 
diff --git a/chrome/browser/resources/settings/a11y_page/tts_subpage.html b/chrome/browser/resources/settings/a11y_page/tts_subpage.html
index 903655a..c76c59b 100644
--- a/chrome/browser/resources/settings/a11y_page/tts_subpage.html
+++ b/chrome/browser/resources/settings/a11y_page/tts_subpage.html
@@ -91,11 +91,14 @@
         <div id="extension_name_[[index]]" class="start">
           [[extension.name]]
         </div>
-        <paper-button on-click="onManageTtsEngineSettingsClick_"
-            aria-describedby="extension_name_[[index]]"
-            hidden="[[!extension.options_page]]">
-          $i18n{settings}
-        </paper-button>
+        <a href="[[extension.optionsPage]]"
+            tabindex=-1
+            target="_blank"
+            hidden="[[!extension.optionsPage]]">
+          <paper-button aria-describedby="extension_name_[[index]]">
+            $i18n{settings}
+          </paper-button>
+        </a>
       </div>
     </template>
     <div class="settings-box block continuation">
diff --git a/chrome/browser/resources/settings/a11y_page/tts_subpage.js b/chrome/browser/resources/settings/a11y_page/tts_subpage.js
index 437d10d..503e31f9 100644
--- a/chrome/browser/resources/settings/a11y_page/tts_subpage.js
+++ b/chrome/browser/resources/settings/a11y_page/tts_subpage.js
@@ -110,14 +110,6 @@
     });
   },
 
-  /**
-   * Function to navigate to the options page for an extension.
-   * @param {TtsHandlerExtension} engine
-   * @private */
-  onManageTtsEngineSettingsClick_: function(engine) {
-    window.open(engine.optionsPage, '_blank');
-  },
-
   /** @private */
   onPreviewTtsClick_: function() {
     let utter = new window.SpeechSynthesisUtterance();
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index e5d2cb8..e2718951 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -1,9 +1,9 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="../icons.html">
 <link rel="import" href="../prefs/prefs.html">
@@ -43,13 +43,12 @@
             </paper-icon-button-light>
           </template>
           <div class="separator"></div>
-          <paper-toggle-button id="enableBluetooth"
+          <cr-toggle id="enableBluetooth"
               checked="{{bluetoothToggleState_}}"
               disabled$=
                   "[[!isToggleEnabled_(adapterState_, stateChangeInProgress_)]]"
-              on-click="stopTap_"
               aria-label="$i18n{bluetoothToggleA11yLabel}">
-          </paper-toggle-button>
+          </cr-toggle>
         </div>
       </neon-animatable>
 
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
index 73b88de..8b67451 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -192,14 +192,6 @@
    * @param {!Event} e
    * @private
    */
-  stopTap_: function(e) {
-    e.stopPropagation();
-  },
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
   onSubpageArrowTap_: function(e) {
     this.openSubpage_();
     e.stopPropagation();
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html
index 018a505..a8de158 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.html
@@ -2,10 +2,10 @@
 
 <link rel="import" href="chrome://resources/cr_components/chromeos/bluetooth_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="../i18n_setup.html">
 <link rel="import" href="../icons.html">
 <link rel="import" href="../settings_shared_css.html">
@@ -44,12 +44,11 @@
         [[getOnOffString_(bluetoothToggleState,
           '$i18nPolymer{deviceOn}', '$i18nPolymer{deviceOff}')]]
       </div>
-      <paper-toggle-button id="enableBluetooth"
+      <cr-toggle id="enableBluetooth"
           checked="{{bluetoothToggleState}}"
           disabled$="[[!isToggleEnabled_(adapterState, stateChangeInProgress)]]"
-          aria-label="$i18n{bluetoothToggleA11yLabel}"
-          on-click="stopTap_">
-      </paper-toggle-button>
+          aria-label="$i18n{bluetoothToggleA11yLabel}">
+      </cr-toggle>
     </div>
 
     <!-- Paired device list -->
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
index 6890575..476a450 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_subpage.js
@@ -370,14 +370,6 @@
    * @param {!Event} event
    * @private
    */
-  stopTap_: function(event) {
-    event.stopPropagation();
-  },
-
-  /**
-   * @param {!Event} event
-   * @private
-   */
   onEnableTap_: function(event) {
     if (this.isToggleEnabled_())
       this.bluetoothToggleState = !this.bluetoothToggleState;
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index 2ad6b0f..18c697e4 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -9,6 +9,7 @@
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
@@ -18,7 +19,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
 <link rel="import" href="../prefs/prefs.html">
 <link rel="import" href="../route.html">
@@ -41,7 +41,7 @@
         -webkit-margin-end: 10px;
       }
 
-      paper-toggle-button {
+      cr-toggle {
         -webkit-margin-start: var(--settings-control-label-spacing);
       }
 
@@ -141,10 +141,10 @@
           <cr-policy-network-indicator
               property="[[networkProperties.Priority]]">
           </cr-policy-network-indicator>
-          <paper-toggle-button checked="{{preferNetwork_}}"
+          <cr-toggle checked="{{preferNetwork_}}"
               disabled="[[isNetworkPolicyEnforced(networkProperties.Priority)]]"
               aria-labelledby="preferNetworkToggleLabel">
-          </paper-toggle-button>
+          </cr-toggle>
         </div>
       </template>
       <!-- Autoconnect. -->
@@ -156,11 +156,11 @@
           <cr-policy-network-indicator
               property="[[getManagedAutoConnect_(networkProperties)]]">
           </cr-policy-network-indicator>
-          <paper-toggle-button checked="{{autoConnect_}}"
+          <cr-toggle checked="{{autoConnect_}}"
               disabled="[[!enableAutoConnect_(networkProperties,
                   globalPolicy)]]"
               aria-labelledby="autoConnectToggleLabel">
-          </paper-toggle-button>
+          </cr-toggle>
         </div>
       </template>
       <!-- Data roaming (Cellular only). -->
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html
index 91b79a02..2889a2e 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.html
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -1,11 +1,11 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_list.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="../settings_shared_css.html">
 
 <dom-module id="settings-internet-subpage">
@@ -89,12 +89,12 @@
               on-click="onAddButtonTap_" tabindex$="[[tabindex]]">
           </button>
         </paper-icon-button-light>
-        <paper-toggle-button id="deviceEnabledButton"
+        <cr-toggle id="deviceEnabledButton"
             aria-label$="[[getToggleA11yString_(deviceState)]]"
             checked="[[deviceIsEnabled_(deviceState)]]"
             disabled="[[!enableToggleIsEnabled_(deviceState)]]"
-            on-click="onDeviceEnabledTap_">
-        </paper-toggle-button>
+            on-change="onDeviceEnabledChange_">
+        </cr-toggle>
       </div>
     </template>
 
@@ -215,13 +215,13 @@
               $i18n{internetToggleTetherSubtext}
             </div>
           </div>
-          <paper-toggle-button id="tetherEnabledButton"
+          <cr-toggle id="tetherEnabledButton"
               aria-label="$i18n{internetToggleTetherLabel}"
               aria-describedby="tetherSecondary"
               checked="[[deviceIsEnabled_(tetherDeviceState)]]"
               disabled="[[!tetherToggleIsEnabled_(deviceState,
                   tetherDeviceState)]]">
-          </paper-toggle-button>
+          </cr-toggle>
         </div>
       </template>
     </template>
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chrome/browser/resources/settings/internet_page/internet_subpage.js
index 919eed9..336b50c 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.js
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -455,14 +455,12 @@
    * @param {!Event} event
    * @private
    */
-  onDeviceEnabledTap_: function(event) {
+  onDeviceEnabledChange_: function(event) {
     assert(this.deviceState);
     this.fire('device-enabled-toggled', {
       enabled: !this.deviceIsEnabled_(this.deviceState),
       type: this.deviceState.Type
     });
-    // Make sure this does not propagate to onDetailsTap_.
-    event.stopPropagation();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index d45bd71..1d16847 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -2,11 +2,11 @@
 
 <link rel="import" href="chrome://resources/cr_components/chromeos/network/network_siminfo.html">
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="../settings_page/settings_subpage.html">
 <link rel="import" href="../settings_shared_css.html">
 
@@ -74,12 +74,12 @@
 
       <template is="dom-if" if="[[enableToggleIsVisible_(deviceState)]]">
         <div class="separator"></div>
-        <paper-toggle-button  id="deviceEnabledButton"
+        <cr-toggle id="deviceEnabledButton"
             aria-label$="[[getToggleA11yString_(deviceState)]]"
             checked="[[deviceIsEnabled_(deviceState)]]"
             disabled="[[!enableToggleIsEnabled_(deviceState)]]"
-            on-click="onDeviceEnabledTap_">
-        </paper-toggle-button>
+            on-change="onDeviceEnabledChange_">
+        </cr-toggle>
       </template>
     </div>
   </template>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index 7963ca5..ab3be60 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -327,13 +327,11 @@
    * @param {!Event} event
    * @private
    */
-  onDeviceEnabledTap_: function(event) {
+  onDeviceEnabledChange_: function(event) {
     const deviceIsEnabled = this.deviceIsEnabled_(this.deviceState);
     const type = this.deviceState ? this.deviceState.Type : '';
     this.fire(
         'device-enabled-toggled', {enabled: !deviceIsEnabled, type: type});
-    // Make sure this does not propagate to onDetailsTap_.
-    event.stopPropagation();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 1b64c43..baa02f9 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -61,6 +61,7 @@
       }
 
       #advancedButton:focus {
+        box-shadow: none;
         outline: none;
       }
 
diff --git a/chrome/browser/resources/snippets_internals/snippets_internals.html b/chrome/browser/resources/snippets_internals/snippets_internals.html
index 318d0512..43869fec 100644
--- a/chrome/browser/resources/snippets_internals/snippets_internals.html
+++ b/chrome/browser/resources/snippets_internals/snippets_internals.html
@@ -26,9 +26,6 @@
         <td class="name">Article Suggestions enabled
         <td id="flag-article-suggestions" class="value">
       <tr>
-        <td class="name">Recent Tab Suggestions enabled
-        <td id="flag-recent-offline-tab-suggestions" class="value">
-      <tr>
         <td class="name">Offlining Recent Tabs enabled
         <td id="flag-offlining-recent-pages-feature" class="value">
       <tr>
diff --git a/chrome/browser/sessions/session_restore_observer_unittest.cc b/chrome/browser/sessions/session_restore_observer_unittest.cc
index 6cf1097f..5d6e13e 100644
--- a/chrome/browser/sessions/session_restore_observer_unittest.cc
+++ b/chrome/browser/sessions/session_restore_observer_unittest.cc
@@ -77,7 +77,7 @@
   // testing::Test:
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-    SetContents(CreateRestoredWebContents().release());
+    SetContents(CreateRestoredWebContents());
     restored_tabs_.emplace_back(web_contents(), false, false, false);
   }
 
diff --git a/chrome/browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc b/chrome/browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc
index ddad919..d133eb2a 100644
--- a/chrome/browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc
+++ b/chrome/browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc
@@ -33,8 +33,8 @@
     router_ =
         SyncSessionsWebContentsRouterFactory::GetInstance()->GetForProfile(
             &profile_);
-    test_contents_.reset(
-        content::WebContentsTester::CreateTestWebContents(&profile_, nullptr));
+    test_contents_ =
+        content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
   }
 
   SyncSessionsWebContentsRouter* router() { return router_; }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e0ec670..38caa0b 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1486,8 +1486,6 @@
       "tabs/tab_strip_model_stats_recorder.h",
       "tabs/tab_utils.cc",
       "tabs/tab_utils.h",
-      "tabs/web_contents_closer.cc",
-      "tabs/web_contents_closer.h",
       "tabs/window_activity_watcher.cc",
       "tabs/window_activity_watcher.h",
       "tabs/window_features.cc",
diff --git a/chrome/browser/ui/ash/chrome_keyboard_ui_unittest.cc b/chrome/browser/ui/ash/chrome_keyboard_ui_unittest.cc
index ab13bf8f..5ca1e30 100644
--- a/chrome/browser/ui/ash/chrome_keyboard_ui_unittest.cc
+++ b/chrome/browser/ui/ash/chrome_keyboard_ui_unittest.cc
@@ -41,8 +41,7 @@
 
 // A test for crbug.com/734534
 TEST_F(ChromeKeyboardUITest, DoesNotCrashWhenParentDoesNotExist) {
-  std::unique_ptr<content::WebContents> contents =
-      base::WrapUnique(CreateTestWebContents());
+  std::unique_ptr<content::WebContents> contents = CreateTestWebContents();
   TestChromeKeyboardUI keyboard_ui(std::move(contents));
 
   EXPECT_FALSE(keyboard_ui.HasContentsWindow());
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
index 3ad42cd..6d760f9 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -131,8 +131,8 @@
     GetMenuModelCallback callback) {
   ChromeLauncherController* controller = ChromeLauncherController::instance();
   const ash::ShelfItem* item = controller->GetItem(shelf_id());
-  std::move(callback).Run(
-      LauncherContextMenu::Create(controller, item, display_id));
+  context_menu_ = LauncherContextMenu::Create(controller, item, display_id);
+  context_menu_->GetMenuModel(std::move(callback));
 }
 
 void AppShortcutLauncherItemController::ExecuteCommand(bool from_context_menu,
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
index f9c5f83..a4bc33bf 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_APP_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
 #define CHROME_BROWSER_UI_ASH_LAUNCHER_APP_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -24,6 +25,8 @@
 class Extension;
 }
 
+class LauncherContextMenu;
+
 // Item controller for an app shortcut.
 // If the associated app is a platform or ARC app, launching the app replaces
 // this instance with an AppWindowLauncherItemController to handle the app's
@@ -101,6 +104,8 @@
   // The cached list of open app web contents shown in an application menu.
   std::vector<content::WebContents*> app_menu_items_;
 
+  std::unique_ptr<LauncherContextMenu> context_menu_;
+
   DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
index 0da56398..fc62492 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -106,8 +106,8 @@
     GetMenuModelCallback callback) {
   ChromeLauncherController* controller = ChromeLauncherController::instance();
   const ash::ShelfItem* item = controller->GetItem(shelf_id());
-  std::move(callback).Run(
-      LauncherContextMenu::Create(controller, item, display_id));
+  context_menu_ = LauncherContextMenu::Create(controller, item, display_id);
+  context_menu_->GetMenuModel(std::move(callback));
 }
 
 void AppWindowLauncherItemController::Close() {
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
index 7b40962..a50c0c17 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_ASH_LAUNCHER_APP_WINDOW_LAUNCHER_ITEM_CONTROLLER_H_
 
 #include <list>
+#include <memory>
 #include <string>
 
 #include "ash/public/cpp/shelf_item_delegate.h"
@@ -21,6 +22,8 @@
 class BaseWindow;
 }
 
+class LauncherContextMenu;
+
 // This is a ShelfItemDelegate for abstract app windows (extension or ARC).
 // There is one instance per app, per launcher id. For apps with multiple
 // windows, each item controller keeps track of all windows associated with the
@@ -101,6 +104,8 @@
   // Scoped list of observed windows (for removal on destruction)
   ScopedObserver<aura::Window, aura::WindowObserver> observed_windows_;
 
+  std::unique_ptr<LauncherContextMenu> context_menu_;
+
   DISALLOW_COPY_AND_ASSIGN(AppWindowLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
index 39557ca6..3663855 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h"
 
-#include <memory>
 #include <utility>
 
 #include "base/strings/utf_string_conversions.h"
@@ -59,8 +58,8 @@
     GetMenuModelCallback callback) {
   ChromeLauncherController* controller = ChromeLauncherController::instance();
   const ash::ShelfItem* item = controller->GetItem(shelf_id());
-  std::move(callback).Run(
-      LauncherContextMenu::Create(controller, item, display_id));
+  context_menu_ = LauncherContextMenu::Create(controller, item, display_id);
+  context_menu_->GetMenuModel(std::move(callback));
 }
 
 void ArcAppDeferredLauncherItemController::Close() {
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
index fcd5cf1..d8b8d604 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 
 #include "ash/public/cpp/shelf_item_delegate.h"
@@ -15,6 +16,7 @@
 #include "base/time/time.h"
 
 class ArcAppDeferredLauncherController;
+class LauncherContextMenu;
 
 // ArcAppDeferredLauncherItemController displays the icon of the ARC app that
 // cannot be launched immediately (due to ARC not being ready) on Chrome OS'
@@ -57,6 +59,8 @@
   base::WeakPtr<ArcAppDeferredLauncherController> host_;
   const base::Time start_time_;
 
+  std::unique_ptr<LauncherContextMenu> context_menu_;
+
   DISALLOW_COPY_AND_ASSIGN(ArcAppDeferredLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
index b846b08..b0675324 100644
--- a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h"
 
+#include <memory>
+#include <utility>
+
 #include "ash/public/cpp/shelf_item.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
@@ -17,13 +20,17 @@
     ChromeLauncherController* controller,
     const ash::ShelfItem* item,
     int64_t display_id)
-    : LauncherContextMenu(controller, item, display_id) {
-  Init();
+    : LauncherContextMenu(controller, item, display_id) {}
+
+ArcLauncherContextMenu::~ArcLauncherContextMenu() = default;
+
+void ArcLauncherContextMenu::GetMenuModel(GetMenuModelCallback callback) {
+  auto menu_model = std::make_unique<ui::SimpleMenuModel>(this);
+  BuildMenu(menu_model.get());
+  std::move(callback).Run(std::move(menu_model));
 }
 
-ArcLauncherContextMenu::~ArcLauncherContextMenu() {}
-
-void ArcLauncherContextMenu::Init() {
+void ArcLauncherContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
   const ArcAppListPrefs* arc_list_prefs =
       ArcAppListPrefs::Get(controller()->profile());
   DCHECK(arc_list_prefs);
@@ -40,16 +47,19 @@
   const bool app_is_open = controller()->IsOpen(item().id);
   if (!app_is_open) {
     DCHECK(app_info->launchable);
-    AddContextMenuOption(MENU_OPEN_NEW, IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
+    AddContextMenuOption(menu_model, MENU_OPEN_NEW,
+                         IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
     if (!features::IsTouchableAppContextMenuEnabled())
-      AddSeparator(ui::NORMAL_SEPARATOR);
+      menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
   }
 
   if (!app_id.has_shelf_group_id() && app_info->launchable)
-    AddPinMenu();
+    AddPinMenu(menu_model);
 
-  if (app_is_open)
-    AddContextMenuOption(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+  if (app_is_open) {
+    AddContextMenuOption(menu_model, MENU_CLOSE,
+                         IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+  }
   if (!features::IsTouchableAppContextMenuEnabled())
-    AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
 }
diff --git a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h
index 58ea7490..5c7aaee 100644
--- a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h
@@ -16,8 +16,11 @@
                          int64_t display_id);
   ~ArcLauncherContextMenu() override;
 
+  // LauncherContextMenu:
+  void GetMenuModel(GetMenuModelCallback callback) override;
+
  private:
-  void Init();
+  void BuildMenu(ui::SimpleMenuModel* menu_model);
 
   DISALLOW_COPY_AND_ASSIGN(ArcLauncherContextMenu);
 };
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index 80481d6f..15cd340 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -248,8 +248,8 @@
     GetMenuModelCallback callback) {
   ChromeLauncherController* controller = ChromeLauncherController::instance();
   const ash::ShelfItem* item = controller->GetItem(shelf_id());
-  std::move(callback).Run(
-      LauncherContextMenu::Create(controller, item, display_id));
+  context_menu_ = LauncherContextMenu::Create(controller, item, display_id);
+  context_menu_->GetMenuModel(std::move(callback));
 }
 
 void BrowserShortcutLauncherItemController::ExecuteCommand(
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
index b93253d..c811c66 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_BROWSER_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
 #define CHROME_BROWSER_UI_ASH_LAUNCHER_BROWSER_SHORTCUT_LAUNCHER_ITEM_CONTROLLER_H_
 
+#include <memory>
+
 #include "ash/public/cpp/shelf_item_delegate.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
@@ -19,6 +21,8 @@
 class WebContents;
 }
 
+class LauncherContextMenu;
+
 // Shelf item delegate for a browser shortcut; only one such item should exist.
 // This item shows an application menu that lists open browser windows or tabs.
 class BrowserShortcutLauncherItemController : public ash::ShelfItemDelegate,
@@ -76,6 +80,8 @@
   // Observer for browser windows closing events.
   ScopedObserver<BrowserList, BrowserListObserver> browser_list_observer_;
 
+  std::unique_ptr<LauncherContextMenu> context_menu_;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserShortcutLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 559eba3b..6a4ef1f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -22,6 +22,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -340,8 +341,20 @@
     return LauncherContextMenu::Create(controller_, &item, display_id);
   }
 
-  bool IsItemPresentInMenu(LauncherContextMenu* menu, int command_id) {
-    return menu->GetIndexOfCommandId(command_id) != -1;
+  bool IsItemPresentInMenu(LauncherContextMenu* launcher_context_menu,
+                           int command_id) {
+    base::RunLoop run_loop;
+    std::unique_ptr<ui::MenuModel> menu;
+    launcher_context_menu->GetMenuModel(base::BindLambdaForTesting(
+        [&](std::unique_ptr<ui::MenuModel> created_menu) {
+          menu = std::move(created_menu);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+    ui::MenuModel* menu_ptr = menu.get();
+    int index = 0;
+    return ui::MenuModel::GetModelAndIndexForCommandId(command_id, &menu_ptr,
+                                                       &index);
   }
 
   ChromeLauncherController* controller_ = nullptr;
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
index 77afe7b..5bc1cb1d 100644
--- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h"
 
+#include <memory>
+#include <utility>
+
 #include "ash/public/cpp/shelf_item.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
@@ -15,26 +18,33 @@
     ChromeLauncherController* controller,
     const ash::ShelfItem* item,
     int64_t display_id)
-    : LauncherContextMenu(controller, item, display_id) {
-  Init();
+    : LauncherContextMenu(controller, item, display_id) {}
+
+CrostiniShelfContextMenu::~CrostiniShelfContextMenu() = default;
+
+void CrostiniShelfContextMenu::GetMenuModel(GetMenuModelCallback callback) {
+  auto menu_model = std::make_unique<ui::SimpleMenuModel>(this);
+  BuildMenu(menu_model.get());
+  std::move(callback).Run(std::move(menu_model));
 }
 
-CrostiniShelfContextMenu::~CrostiniShelfContextMenu() {}
-
-void CrostiniShelfContextMenu::Init() {
+void CrostiniShelfContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
   const crostini::CrostiniRegistryService* registry_service =
       crostini::CrostiniRegistryServiceFactory::GetForProfile(
           controller()->profile());
   std::unique_ptr<crostini::CrostiniRegistryService::Registration>
       registration = registry_service->GetRegistration(item().id.app_id);
   if (registration)
-    AddPinMenu();
+    AddPinMenu(menu_model);
 
-  if (controller()->IsOpen(item().id))
-    AddItemWithStringId(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
-  else
-    AddItemWithStringId(MENU_OPEN_NEW, IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
+  if (controller()->IsOpen(item().id)) {
+    menu_model->AddItemWithStringId(MENU_CLOSE,
+                                    IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+  } else {
+    menu_model->AddItemWithStringId(MENU_OPEN_NEW,
+                                    IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
+  }
 
   if (!features::IsTouchableAppContextMenuEnabled())
-    AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
 }
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h
index 0ca6fc2..6d6928c 100644
--- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.h
@@ -16,8 +16,11 @@
                            int64_t display_id);
   ~CrostiniShelfContextMenu() override;
 
+  // LauncherContextMenu:
+  void GetMenuModel(GetMenuModelCallback callback) override;
+
  private:
-  void Init();
+  void BuildMenu(ui::SimpleMenuModel* menu_model);
 
   DISALLOW_COPY_AND_ASSIGN(CrostiniShelfContextMenu);
 };
diff --git a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
index d59b17b..356eb5c7 100644
--- a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/ash/launcher/extension_launcher_context_menu.h"
 
+#include <utility>
+
 #include "ash/scoped_root_window_for_new_windows.h"  // mash-ok
 #include "ash/shell.h"                               // mash-ok
 #include "base/bind.h"
@@ -36,15 +38,19 @@
     ChromeLauncherController* controller,
     const ash::ShelfItem* item,
     int64_t display_id)
-    : LauncherContextMenu(controller, item, display_id) {
-  Init();
+    : LauncherContextMenu(controller, item, display_id) {}
+
+ExtensionLauncherContextMenu::~ExtensionLauncherContextMenu() = default;
+
+void ExtensionLauncherContextMenu::GetMenuModel(GetMenuModelCallback callback) {
+  auto menu_model = std::make_unique<ui::SimpleMenuModel>(this);
+  BuildMenu(menu_model.get());
+  std::move(callback).Run(std::move(menu_model));
 }
 
-ExtensionLauncherContextMenu::~ExtensionLauncherContextMenu() {}
-
-void ExtensionLauncherContextMenu::Init() {
+void ExtensionLauncherContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
   extension_items_.reset(new extensions::ContextMenuMatcher(
-      controller()->profile(), this, this,
+      controller()->profile(), this, menu_model,
       base::Bind(MenuItemHasLauncherContext)));
   if (item().type == ash::TYPE_PINNED_APP || item().type == ash::TYPE_APP) {
     // V1 apps can be started from the menu - but V2 apps should not.
@@ -53,56 +59,61 @@
                        GetLaunchType() == extensions::LAUNCH_TYPE_REGULAR)
                           ? IDS_APP_LIST_CONTEXT_MENU_NEW_TAB
                           : IDS_APP_LIST_CONTEXT_MENU_NEW_WINDOW;
-      AddContextMenuOption(MENU_OPEN_NEW, string_id);
+      AddContextMenuOption(menu_model, MENU_OPEN_NEW, string_id);
       if (!features::IsTouchableAppContextMenuEnabled())
-        AddSeparator(ui::NORMAL_SEPARATOR);
+        menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
     }
 
-    AddPinMenu();
+    AddPinMenu(menu_model);
 
-    if (controller()->IsOpen(item().id))
-      AddContextMenuOption(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+    if (controller()->IsOpen(item().id)) {
+      AddContextMenuOption(menu_model, MENU_CLOSE,
+                           IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+    }
 
     if (!controller()->IsPlatformApp(item().id) &&
         item().type == ash::TYPE_PINNED_APP) {
       if (!features::IsTouchableAppContextMenuEnabled())
-        AddSeparator(ui::NORMAL_SEPARATOR);
+        menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
       if (extensions::util::IsNewBookmarkAppsEnabled()) {
         // With bookmark apps enabled, hosted apps launch in a window by
         // default. This menu item is re-interpreted as a single, toggle-able
         // option to launch the hosted app as a tab.
-        AddContextMenuOption(LAUNCH_TYPE_WINDOW,
+        AddContextMenuOption(menu_model, LAUNCH_TYPE_WINDOW,
                              IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
       } else {
-        AddContextMenuOption(LAUNCH_TYPE_REGULAR_TAB,
+        AddContextMenuOption(menu_model, LAUNCH_TYPE_REGULAR_TAB,
                              IDS_APP_CONTEXT_MENU_OPEN_REGULAR);
-        AddContextMenuOption(LAUNCH_TYPE_PINNED_TAB,
+        AddContextMenuOption(menu_model, LAUNCH_TYPE_PINNED_TAB,
                              IDS_APP_CONTEXT_MENU_OPEN_PINNED);
-        AddContextMenuOption(LAUNCH_TYPE_WINDOW,
+        AddContextMenuOption(menu_model, LAUNCH_TYPE_WINDOW,
                              IDS_APP_CONTEXT_MENU_OPEN_WINDOW);
         // Even though the launch type is Full Screen it is more accurately
         // described as Maximized in Ash.
-        AddContextMenuOption(LAUNCH_TYPE_FULLSCREEN,
+        AddContextMenuOption(menu_model, LAUNCH_TYPE_FULLSCREEN,
                              IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED);
       }
     }
   } else if (item().type == ash::TYPE_BROWSER_SHORTCUT) {
-    AddContextMenuOption(MENU_NEW_WINDOW, IDS_APP_LIST_NEW_WINDOW);
+    AddContextMenuOption(menu_model, MENU_NEW_WINDOW, IDS_APP_LIST_NEW_WINDOW);
     if (!controller()->profile()->IsGuestSession()) {
-      AddContextMenuOption(MENU_NEW_INCOGNITO_WINDOW,
+      AddContextMenuOption(menu_model, MENU_NEW_INCOGNITO_WINDOW,
                            IDS_APP_LIST_NEW_INCOGNITO_WINDOW);
     }
     if (!BrowserShortcutLauncherItemController(controller()->shelf_model())
              .IsListOfActiveBrowserEmpty()) {
-      AddContextMenuOption(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+      AddContextMenuOption(menu_model, MENU_CLOSE,
+                           IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
     }
   } else if (item().type == ash::TYPE_DIALOG) {
-    AddContextMenuOption(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+    AddContextMenuOption(menu_model, MENU_CLOSE,
+                         IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
   } else if (controller()->IsOpen(item().id)) {
-    AddContextMenuOption(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+    AddContextMenuOption(menu_model, MENU_CLOSE,
+                         IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
   }
   if (!features::IsTouchableAppContextMenuEnabled())
-    AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
   if (item().type == ash::TYPE_PINNED_APP || item().type == ash::TYPE_APP) {
     const extensions::MenuItem::ExtensionKey app_key(item().id.app_id);
     if (!app_key.empty()) {
@@ -110,7 +121,7 @@
       extension_items_->AppendExtensionItems(app_key, base::string16(), &index,
                                              false);  // is_action_menu
       if (!features::IsTouchableAppContextMenuEnabled())
-        AddSeparator(ui::NORMAL_SEPARATOR);
+        menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
     }
   }
 }
diff --git a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.h b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.h
index c6125878f..e726c2c9 100644
--- a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.h
@@ -23,13 +23,16 @@
                                int64_t display_id);
   ~ExtensionLauncherContextMenu() override;
 
+  // LauncherContextMenu overrides:
+  void GetMenuModel(GetMenuModelCallback callback) override;
+
   // ui::SimpleMenuModel::Delegate overrides:
   bool IsCommandIdChecked(int command_id) const override;
   bool IsCommandIdEnabled(int command_id) const override;
   void ExecuteCommand(int command_id, int event_flags) override;
 
  private:
-  void Init();
+  void BuildMenu(ui::SimpleMenuModel* menu_model);
 
   // Helpers to get and set the launch type for the extension item.
   extensions::LaunchType GetLaunchType() const;
diff --git a/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.cc
index ebd60d8..a687c13c 100644
--- a/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.h"
 
+#include <memory>
+#include <utility>
+
 #include "ash/public/cpp/shelf_item.h"
 #include "chrome/browser/ui/app_list/internal_app/internal_app_metadata.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -14,27 +17,34 @@
     ChromeLauncherController* controller,
     const ash::ShelfItem* item,
     int64_t display_id)
-    : LauncherContextMenu(controller, item, display_id) {
-  Init();
+    : LauncherContextMenu(controller, item, display_id) {}
+
+void InternalAppShelfContextMenu::GetMenuModel(GetMenuModelCallback callback) {
+  auto menu_model = std::make_unique<ui::SimpleMenuModel>(this);
+  BuildMenu(menu_model.get());
+  std::move(callback).Run(std::move(menu_model));
 }
 
-void InternalAppShelfContextMenu::Init() {
+void InternalAppShelfContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
   const bool app_is_open = controller()->IsOpen(item().id);
   if (!app_is_open) {
-    AddContextMenuOption(MENU_OPEN_NEW, IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
+    AddContextMenuOption(menu_model, MENU_OPEN_NEW,
+                         IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
     if (!features::IsTouchableAppContextMenuEnabled())
-      AddSeparator(ui::NORMAL_SEPARATOR);
+      menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
   }
 
   const auto* internal_app = app_list::FindInternalApp(item().id.app_id);
   DCHECK(internal_app);
   if (internal_app->show_in_launcher)
-    AddPinMenu();
+    AddPinMenu(menu_model);
 
-  if (app_is_open)
-    AddContextMenuOption(MENU_CLOSE, IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+  if (app_is_open) {
+    AddContextMenuOption(menu_model, MENU_CLOSE,
+                         IDS_LAUNCHER_CONTEXT_MENU_CLOSE);
+  }
 
   // Default menu items, e.g. "Autohide shelf" are appended. Adding a separator.
   if (!features::IsTouchableAppContextMenuEnabled())
-    AddSeparator(ui::NORMAL_SEPARATOR);
+    menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
 }
diff --git a/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.h b/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.h
index dbc7db2..4d6402a6 100644
--- a/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/internal_app_shelf_context_menu.h
@@ -14,11 +14,13 @@
   InternalAppShelfContextMenu(ChromeLauncherController* controller,
                               const ash::ShelfItem* item,
                               int64_t display_id);
-
   ~InternalAppShelfContextMenu() override = default;
 
+  // LauncherContextMenu:
+  void GetMenuModel(GetMenuModelCallback callback) override;
+
  private:
-  void Init();
+  void BuildMenu(ui::SimpleMenuModel* menu_model);
 
   DISALLOW_COPY_AND_ASSIGN(InternalAppShelfContextMenu);
 };
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index 1b3f351..7950321 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -65,14 +65,13 @@
 LauncherContextMenu::LauncherContextMenu(ChromeLauncherController* controller,
                                          const ash::ShelfItem* item,
                                          int64_t display_id)
-    : ui::SimpleMenuModel(this),
-      controller_(controller),
+    : controller_(controller),
       item_(item ? *item : ash::ShelfItem()),
       display_id_(display_id) {
   DCHECK_NE(display_id, display::kInvalidDisplayId);
 }
 
-LauncherContextMenu::~LauncherContextMenu() {}
+LauncherContextMenu::~LauncherContextMenu() = default;
 
 bool LauncherContextMenu::IsCommandIdChecked(int command_id) const {
   DCHECK(command_id < MENU_ITEM_COUNT);
@@ -125,7 +124,7 @@
   }
 }
 
-void LauncherContextMenu::AddPinMenu() {
+void LauncherContextMenu::AddPinMenu(ui::SimpleMenuModel* menu_model) {
   // Expect a valid ShelfID to add pin/unpin menu item.
   DCHECK(!item_.id.IsNull());
   int menu_pin_string_id;
@@ -144,7 +143,7 @@
       NOTREACHED();
       return;
   }
-  AddContextMenuOption(MENU_PIN, menu_pin_string_id);
+  AddContextMenuOption(menu_model, MENU_PIN, menu_pin_string_id);
 }
 
 bool LauncherContextMenu::ExecuteCommonCommand(int command_id,
@@ -160,11 +159,13 @@
   }
 }
 
-void LauncherContextMenu::AddContextMenuOption(MenuItem type, int string_id) {
+void LauncherContextMenu::AddContextMenuOption(ui::SimpleMenuModel* menu_model,
+                                               MenuItem type,
+                                               int string_id) {
   const gfx::VectorIcon& icon = GetMenuItemVectorIcon(type, string_id);
   if (features::IsTouchableAppContextMenuEnabled() && !icon.is_empty()) {
     const views::MenuConfig& menu_config = views::MenuConfig::instance();
-    AddItemWithStringIdAndIcon(
+    menu_model->AddItemWithStringIdAndIcon(
         type, string_id,
         gfx::CreateVectorIcon(icon, menu_config.touchable_icon_size,
                               menu_config.touchable_icon_color));
@@ -173,10 +174,10 @@
   // If the MenuType is a Check item.
   if (type == LAUNCH_TYPE_REGULAR_TAB || type == LAUNCH_TYPE_PINNED_TAB ||
       type == LAUNCH_TYPE_WINDOW || type == LAUNCH_TYPE_FULLSCREEN) {
-    AddCheckItemWithStringId(type, string_id);
+    menu_model->AddCheckItemWithStringId(type, string_id);
     return;
   }
-  AddItemWithStringId(type, string_id);
+  menu_model->AddItemWithStringId(type, string_id);
 }
 
 const gfx::VectorIcon& LauncherContextMenu::GetMenuItemVectorIcon(
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.h b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
index 79c8dbbb..9ba683f 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
@@ -13,8 +13,7 @@
 class ChromeLauncherController;
 
 // A base class for browser, extension, and ARC shelf item context menus.
-class LauncherContextMenu : public ui::SimpleMenuModel,
-                            public ui::SimpleMenuModel::Delegate {
+class LauncherContextMenu : public ui::SimpleMenuModel::Delegate {
  public:
   // Menu item command ids, used by subclasses and tests.
   // These are used in histograms, do not remove/renumber entries. Only add at
@@ -43,6 +42,10 @@
       const ash::ShelfItem* item,
       int64_t display_id);
 
+  using GetMenuModelCallback =
+      base::OnceCallback<void(std::unique_ptr<ui::MenuModel>)>;
+  virtual void GetMenuModel(GetMenuModelCallback callback) = 0;
+
   // ui::SimpleMenuModel::Delegate overrides:
   bool IsCommandIdChecked(int command_id) const override;
   bool IsCommandIdEnabled(int command_id) const override;
@@ -57,13 +60,15 @@
   const ash::ShelfItem& item() const { return item_; }
 
   // Add menu item for pin/unpin.
-  void AddPinMenu();
+  void AddPinMenu(ui::SimpleMenuModel* menu_model);
 
   // Helper method to execute common commands. Returns true if handled.
   bool ExecuteCommonCommand(int command_id, int event_flags);
 
   // Helper method to add touchable or normal context menu options.
-  void AddContextMenuOption(MenuItem type, int string_id);
+  void AddContextMenuOption(ui::SimpleMenuModel* menu_model,
+                            MenuItem type,
+                            int string_id);
 
   // Helper method to get the gfx::VectorIcon for a |type|. Returns an empty
   // gfx::VectorIcon if there is no icon for this |type|.
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
index 2fe061b..3baca9532 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
 
 #include <memory>
+#include <utility>
 
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/shelf_model.h"
@@ -61,8 +62,8 @@
 
 class LauncherContextMenuTest : public ash::AshTestBase {
  protected:
-
-  LauncherContextMenuTest() {}
+  LauncherContextMenuTest() = default;
+  ~LauncherContextMenuTest() override = default;
 
   void SetUp() override {
     arc_test_.SetUp(&profile_);
@@ -98,6 +99,19 @@
     return widget;
   }
 
+  std::unique_ptr<ui::MenuModel> GetMenuModel(
+      LauncherContextMenu* launcher_context_menu) {
+    base::RunLoop run_loop;
+    std::unique_ptr<ui::MenuModel> menu;
+    launcher_context_menu->GetMenuModel(base::BindLambdaForTesting(
+        [&](std::unique_ptr<ui::MenuModel> created_menu) {
+          menu = std::move(created_menu);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
+    return menu;
+  }
+
   std::unique_ptr<ui::MenuModel> GetContextMenu(
       ash::ShelfItemDelegate* item_delegate,
       int64_t display_id) {
@@ -145,22 +159,26 @@
        NewIncognitoWindowMenuIsDisabledWhenIncognitoModeOff) {
   const int64_t display_id = GetPrimaryDisplay().id();
   // Initially, "New Incognito window" should be enabled.
-  std::unique_ptr<LauncherContextMenu> menu =
+  std::unique_ptr<LauncherContextMenu> launcher_context_menu =
       CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  std::unique_ptr<ui::MenuModel> menu =
+      GetMenuModel(launcher_context_menu.get());
   ASSERT_TRUE(IsItemPresentInMenu(
       menu.get(), LauncherContextMenu::MENU_NEW_INCOGNITO_WINDOW));
-  EXPECT_TRUE(
-      menu->IsCommandIdEnabled(LauncherContextMenu::MENU_NEW_INCOGNITO_WINDOW));
+  EXPECT_TRUE(launcher_context_menu->IsCommandIdEnabled(
+      LauncherContextMenu::MENU_NEW_INCOGNITO_WINDOW));
 
   // Disable Incognito mode.
   IncognitoModePrefs::SetAvailability(profile()->GetPrefs(),
                                       IncognitoModePrefs::DISABLED);
-  menu = CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  launcher_context_menu =
+      CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  menu = GetMenuModel(launcher_context_menu.get());
   // The item should be disabled.
   ASSERT_TRUE(IsItemPresentInMenu(
       menu.get(), LauncherContextMenu::MENU_NEW_INCOGNITO_WINDOW));
-  EXPECT_FALSE(
-      menu->IsCommandIdEnabled(LauncherContextMenu::MENU_NEW_INCOGNITO_WINDOW));
+  EXPECT_FALSE(launcher_context_menu->IsCommandIdEnabled(
+      LauncherContextMenu::MENU_NEW_INCOGNITO_WINDOW));
 }
 
 // Verifies that "New window" menu item in the launcher context
@@ -169,19 +187,25 @@
        NewWindowMenuIsDisabledWhenIncognitoModeForced) {
   const int64_t display_id = GetPrimaryDisplay().id();
   // Initially, "New window" should be enabled.
-  std::unique_ptr<LauncherContextMenu> menu =
+  std::unique_ptr<LauncherContextMenu> launcher_context_menu =
       CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  std::unique_ptr<ui::MenuModel> menu =
+      GetMenuModel(launcher_context_menu.get());
   ASSERT_TRUE(
       IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_NEW_WINDOW));
-  EXPECT_TRUE(menu->IsCommandIdEnabled(LauncherContextMenu::MENU_NEW_WINDOW));
+  EXPECT_TRUE(launcher_context_menu->IsCommandIdEnabled(
+      LauncherContextMenu::MENU_NEW_WINDOW));
 
   // Disable Incognito mode.
   IncognitoModePrefs::SetAvailability(profile()->GetPrefs(),
                                       IncognitoModePrefs::FORCED);
-  menu = CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  launcher_context_menu =
+      CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  menu = GetMenuModel(launcher_context_menu.get());
   ASSERT_TRUE(
       IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_NEW_WINDOW));
-  EXPECT_FALSE(menu->IsCommandIdEnabled(LauncherContextMenu::MENU_NEW_WINDOW));
+  EXPECT_FALSE(launcher_context_menu->IsCommandIdEnabled(
+      LauncherContextMenu::MENU_NEW_WINDOW));
 }
 
 // Verifies that "Close" is not shown in context menu if no browser window is
@@ -189,8 +213,10 @@
 TEST_F(LauncherContextMenuTest,
        DesktopShellLauncherContextMenuVerifyCloseItem) {
   const int64_t display_id = GetPrimaryDisplay().id();
-  std::unique_ptr<LauncherContextMenu> menu =
+  std::unique_ptr<LauncherContextMenu> launcher_context_menu =
       CreateLauncherContextMenu(ash::TYPE_BROWSER_SHORTCUT, display_id);
+  std::unique_ptr<ui::MenuModel> menu =
+      GetMenuModel(launcher_context_menu.get());
   ASSERT_FALSE(
       IsItemPresentInMenu(menu.get(), LauncherContextMenu::MENU_CLOSE));
 }
@@ -402,13 +428,17 @@
       std::vector<arc::mojom::AppInfo>(arc_test().fake_apps().begin(),
                                        arc_test().fake_apps().begin() + 1));
   const std::string app_id = ArcAppTest::GetAppId(arc_test().fake_apps()[0]);
+  const ash::ShelfID shelf_id(app_id);
 
   controller()->PinAppWithID(app_id);
-  const ash::ShelfItem* item = controller()->GetItem(ash::ShelfID(app_id));
+  const ash::ShelfItem* item = controller()->GetItem(shelf_id);
   ASSERT_TRUE(item);
+  ash::ShelfItemDelegate* item_delegate =
+      model()->GetShelfItemDelegate(shelf_id);
+  ASSERT_TRUE(item_delegate);
   int64_t primary_id = GetPrimaryDisplay().id();
-  std::unique_ptr<LauncherContextMenu> menu =
-      std::make_unique<ArcLauncherContextMenu>(controller(), item, primary_id);
+  std::unique_ptr<ui::MenuModel> menu =
+      GetContextMenu(item_delegate, primary_id);
 
   // Test that there are 4 items in an ARC app context menu.
   EXPECT_EQ(4, menu->GetItemCount());
@@ -456,10 +486,12 @@
     const ash::ShelfItem* item = controller()->GetItem(ash::ShelfID(app_id));
     ASSERT_TRUE(item);
 
+    ash::ShelfItemDelegate* item_delegate =
+        model()->GetShelfItemDelegate(shelf_id);
+    ASSERT_TRUE(item_delegate);
     int64_t primary_id = GetPrimaryDisplay().id();
-    std::unique_ptr<LauncherContextMenu> menu =
-        std::make_unique<InternalAppShelfContextMenu>(controller(), item,
-                                                      primary_id);
+    std::unique_ptr<ui::MenuModel> menu =
+        GetContextMenu(item_delegate, primary_id);
 
     const int expected_options_num = internal_app.show_in_launcher ? 4 : 2;
     EXPECT_EQ(expected_options_num, menu->GetItemCount());
diff --git a/chrome/browser/ui/browser_list.cc b/chrome/browser/ui/browser_list.cc
index 53044f1..b171e8d 100644
--- a/chrome/browser/ui/browser_list.cc
+++ b/chrome/browser/ui/browser_list.cc
@@ -36,15 +36,6 @@
   return browsers_to_close;
 }
 
-BrowserList::BrowserVector GetIncognitoBrowsersToClose(Profile* profile) {
-  BrowserList::BrowserVector browsers_to_close;
-  for (auto* browser : *BrowserList::GetInstance()) {
-    if (browser->profile() == profile)
-      browsers_to_close.push_back(browser);
-  }
-  return browsers_to_close;
-}
-
 }  // namespace
 
 // static
@@ -163,18 +154,6 @@
 }
 
 // static
-void BrowserList::CloseAllBrowsersWithIncognitoProfile(
-    Profile* profile,
-    const CloseCallback& on_close_success,
-    const CloseCallback& on_close_aborted,
-    bool skip_beforeunload) {
-  DCHECK(profile->IsOffTheRecord());
-  TryToCloseBrowserList(GetIncognitoBrowsersToClose(profile), on_close_success,
-                        on_close_aborted, profile->GetPath(),
-                        skip_beforeunload);
-}
-
-// static
 void BrowserList::TryToCloseBrowserList(const BrowserVector& browsers_to_close,
                                         const CloseCallback& on_close_success,
                                         const CloseCallback& on_close_aborted,
diff --git a/chrome/browser/ui/browser_list.h b/chrome/browser/ui/browser_list.h
index 31248f31..80d883f 100644
--- a/chrome/browser/ui/browser_list.h
+++ b/chrome/browser/ui/browser_list.h
@@ -108,14 +108,6 @@
                                           const CloseCallback& on_close_aborted,
                                           bool skip_beforeunload);
 
-  // Similarly to CloseAllBrowsersWithProfile, but DCHECK's that profile is
-  // Off-the-Record and doesn't close browsers with the original profile.
-  static void CloseAllBrowsersWithIncognitoProfile(
-      Profile* profile,
-      const CloseCallback& on_close_success,
-      const CloseCallback& on_close_aborted,
-      bool skip_beforeunload);
-
   // Returns true if at least one incognito session is active across all
   // desktops.
   static bool IsIncognitoSessionActive();
diff --git a/chrome/browser/ui/browser_unittest.cc b/chrome/browser/ui/browser_unittest.cc
index 0a75853..c7a826ea 100644
--- a/chrome/browser/ui/browser_unittest.cc
+++ b/chrome/browser/ui/browser_unittest.cc
@@ -28,8 +28,8 @@
 
   // Caller owns the memory.
   std::unique_ptr<WebContents> CreateTestWebContents() {
-    return base::WrapUnique(WebContentsTester::CreateTestWebContents(
-        profile(), SiteInstance::Create(profile())));
+    return WebContentsTester::CreateTestWebContents(
+        profile(), SiteInstance::Create(profile()));
   }
 
  private:
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
index 9a119c5f..3bb931d9e 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
@@ -174,8 +174,8 @@
 };
 
 void ChromeOmniboxNavigationObserverTest::SetUp() {
-  web_contents_.reset(content::WebContentsTester::CreateTestWebContents(
-      profile(), content::SiteInstance::Create(profile())));
+  web_contents_ = content::WebContentsTester::CreateTestWebContents(
+      profile(), content::SiteInstance::Create(profile()));
 
   InfoBarService::CreateForWebContents(web_contents_.get());
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
index 036dd56f..5f293551 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -127,8 +127,8 @@
   ~ManagePasswordsBubbleModelTest() override = default;
 
   void SetUp() override {
-    test_web_contents_.reset(
-        content::WebContentsTester::CreateTestWebContents(&profile_, nullptr));
+    test_web_contents_ =
+        content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
     mock_delegate_.reset(new testing::NiceMock<PasswordsModelDelegateMock>);
     ON_CALL(*mock_delegate_, GetPasswordFormMetricsRecorder())
         .WillByDefault(Return(nullptr));
diff --git a/chrome/browser/ui/passwords/password_manager_porter_unittest.cc b/chrome/browser/ui/passwords/password_manager_porter_unittest.cc
index dd947b6..4c2ae0b 100644
--- a/chrome/browser/ui/passwords/password_manager_porter_unittest.cc
+++ b/chrome/browser/ui/passwords/password_manager_porter_unittest.cc
@@ -191,8 +191,8 @@
   void SetUp() override {
     password_manager_porter_.reset(new TestPasswordManagerPorter());
     profile_.reset(new TestingProfile());
-    web_contents_.reset(content::WebContentsTester::CreateTestWebContents(
-        profile_.get(), nullptr));
+    web_contents_ = content::WebContentsTester::CreateTestWebContents(
+        profile_.get(), nullptr);
     // SelectFileDialog::SetFactory is responsible for freeing the memory
     // associated with a new factory.
     selected_file_ = base::FilePath(kNullFileName);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index ee0887f..24d14ba4 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -15,6 +15,7 @@
 #include "base/metrics/user_metrics.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
@@ -26,6 +27,7 @@
 #include "chrome/common/url_constants.h"
 #include "components/feature_engagement/buildflags.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -39,6 +41,81 @@
 
 namespace {
 
+// CloseTracker is used when closing a set of WebContents. It listens for
+// deletions of the WebContents and removes from the internal set any time one
+// is deleted.
+class CloseTracker {
+ public:
+  using Contents = base::span<content::WebContents* const>;
+
+  explicit CloseTracker(const Contents& contents);
+  ~CloseTracker();
+
+  // Returns true if there is another WebContents in the Tracker.
+  bool HasNext() const;
+
+  // Returns the next WebContents, or NULL if there are no more.
+  content::WebContents* Next();
+
+ private:
+  class DeletionObserver : public content::WebContentsObserver {
+   public:
+    DeletionObserver(CloseTracker* parent, content::WebContents* web_contents)
+        : WebContentsObserver(web_contents), parent_(parent) {}
+
+   private:
+    // WebContentsObserver:
+    void WebContentsDestroyed() override {
+      parent_->OnWebContentsDestroyed(this);
+    }
+
+    CloseTracker* parent_;
+
+    DISALLOW_COPY_AND_ASSIGN(DeletionObserver);
+  };
+
+  void OnWebContentsDestroyed(DeletionObserver* observer);
+
+  using Observers = std::vector<std::unique_ptr<DeletionObserver>>;
+  Observers observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(CloseTracker);
+};
+
+CloseTracker::CloseTracker(const Contents& contents) {
+  observers_.reserve(contents.size());
+  for (content::WebContents* current : contents)
+    observers_.push_back(std::make_unique<DeletionObserver>(this, current));
+}
+
+CloseTracker::~CloseTracker() {
+  DCHECK(observers_.empty());
+}
+
+bool CloseTracker::HasNext() const {
+  return !observers_.empty();
+}
+
+content::WebContents* CloseTracker::Next() {
+  if (observers_.empty())
+    return nullptr;
+
+  DeletionObserver* observer = observers_[0].get();
+  content::WebContents* web_contents = observer->web_contents();
+  observers_.erase(observers_.begin());
+  return web_contents;
+}
+
+void CloseTracker::OnWebContentsDestroyed(DeletionObserver* observer) {
+  for (auto i = observers_.begin(); i != observers_.end(); ++i) {
+    if (observer == i->get()) {
+      observers_.erase(i);
+      return;
+    }
+  }
+  NOTREACHED() << "WebContents destroyed that wasn't in the list";
+}
+
 // Returns true if the specified transition is one of the types that cause the
 // opener relationships for the tab in which the transition occurred to be
 // forgotten. This is generally any navigation that isn't a link click (i.e.
@@ -1167,7 +1244,7 @@
     for (auto& observer : observers_)
       observer.WillCloseAllTabs();
   }
-  const bool closed_all = CloseWebContentses(this, items, close_types);
+  const bool closed_all = CloseWebContentses(items, close_types);
   if (!ref)
     return closed_all;
   if (closing_all && !closed_all) {
@@ -1177,6 +1254,67 @@
   return closed_all;
 }
 
+bool TabStripModel::CloseWebContentses(
+    base::span<content::WebContents* const> items,
+    uint32_t close_types) {
+  if (items.empty())
+    return true;
+
+  CloseTracker close_tracker(items);
+
+  // We only try the fast shutdown path if the whole browser process is *not*
+  // shutting down. Fast shutdown during browser termination is handled in
+  // browser_shutdown::OnShutdownStarting.
+  if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) {
+    // Construct a map of processes to the number of associated tabs that are
+    // closing.
+    base::flat_map<content::RenderProcessHost*, size_t> processes;
+    for (content::WebContents* contents : items) {
+      if (ShouldRunUnloadListenerBeforeClosing(contents))
+        continue;
+      content::RenderProcessHost* process =
+          contents->GetMainFrame()->GetProcess();
+      ++processes[process];
+    }
+
+    // Try to fast shutdown the tabs that can close.
+    for (const auto& pair : processes)
+      pair.first->FastShutdownIfPossible(pair.second, false);
+  }
+
+  // We now return to our regularly scheduled shutdown procedure.
+  bool closed_all = true;
+  while (close_tracker.HasNext()) {
+    content::WebContents* closing_contents = close_tracker.Next();
+    if (!ContainsWebContents(closing_contents))
+      continue;
+
+    CoreTabHelper* core_tab_helper =
+        CoreTabHelper::FromWebContents(closing_contents);
+    core_tab_helper->OnCloseStarted();
+
+    // Update the explicitly closed state. If the unload handlers cancel the
+    // close the state is reset in Browser. We don't update the explicitly
+    // closed state if already marked as explicitly closed as unload handlers
+    // call back to this if the close is allowed.
+    if (!closing_contents->GetClosedByUserGesture()) {
+      closing_contents->SetClosedByUserGesture(
+          close_types & TabStripModel::CLOSE_USER_GESTURE);
+    }
+
+    if (RunUnloadListenerBeforeClosing(closing_contents)) {
+      closed_all = false;
+      continue;
+    }
+
+    OnWillDeleteWebContents(closing_contents, close_types);
+
+    delete closing_contents;
+  }
+
+  return closed_all;
+}
+
 WebContents* TabStripModel::GetWebContentsAtImpl(int index) const {
   CHECK(ContainsIndex(index))
       << "Failed to find: " << index << " in: " << count() << " entries.";
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 1a88899..67adfb7a 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -17,7 +17,6 @@
 #include "base/observer_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
-#include "chrome/browser/ui/tabs/web_contents_closer.h"
 #include "ui/base/models/list_selection_model.h"
 #include "ui/base/page_transition_types.h"
 
@@ -56,7 +55,7 @@
 // its bookkeeping when such events happen.
 //
 ////////////////////////////////////////////////////////////////////////////////
-class TabStripModel : public WebContentsCloseDelegate {
+class TabStripModel {
  public:
   // Used to specify what should happen when the tab is closed.
   enum CloseTypes {
@@ -122,7 +121,7 @@
   // Construct a TabStripModel with a delegate to help it do certain things
   // (see the TabStripModelDelegate documentation). |delegate| cannot be NULL.
   explicit TabStripModel(TabStripModelDelegate* delegate, Profile* profile);
-  ~TabStripModel() override;
+  ~TabStripModel();
 
   // Retrieves the TabStripModelDelegate associated with this TabStripModel.
   TabStripModelDelegate* delegate() const { return delegate_; }
@@ -438,13 +437,11 @@
     kUserGesture,
   };
 
-  // WebContentsCloseDelegate:
-  bool ContainsWebContents(content::WebContents* contents) override;
+  bool ContainsWebContents(content::WebContents* contents);
   void OnWillDeleteWebContents(content::WebContents* contents,
-                               uint32_t close_types) override;
-  bool RunUnloadListenerBeforeClosing(content::WebContents* contents) override;
-  bool ShouldRunUnloadListenerBeforeClosing(
-      content::WebContents* contents) override;
+                               uint32_t close_types);
+  bool RunUnloadListenerBeforeClosing(content::WebContents* contents);
+  bool ShouldRunUnloadListenerBeforeClosing(content::WebContents* contents);
 
   int ConstrainInsertionIndex(int index, bool pinned_tab);
 
@@ -483,6 +480,17 @@
   bool InternalCloseTabs(base::span<content::WebContents* const> items,
                          uint32_t close_types);
 
+  // |close_types| is a bitmask of the types in CloseTypes.
+  // Returns true if all the tabs have been deleted. A return value of false
+  // means some portion (potentially none) of the WebContents were deleted.
+  // WebContents not deleted by this function are processing unload handlers
+  // which may eventually be deleted based on the results of the unload handler.
+  // Additionally processing the unload handlers may result in needing to show
+  // UI for the WebContents. See UnloadController for details on how unload
+  // handlers are processed.
+  bool CloseWebContentses(base::span<content::WebContents* const> items,
+                          uint32_t close_types);
+
   // Gets the WebContents at an index. Does no bounds checking.
   content::WebContents* GetWebContentsAtImpl(int index) const;
 
diff --git a/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc b/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc
index 06cec9f..18fad1b 100644
--- a/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model_stats_recorder_unittest.cc
@@ -44,13 +44,15 @@
   HistogramTester tester;
 
   // Insert the first tab.
-  WebContents* contents1 = CreateTestWebContents();
-  tabstrip.InsertWebContentsAt(0, base::WrapUnique(contents1),
+  std::unique_ptr<WebContents> contents1 = CreateTestWebContents();
+  WebContents* raw_contents1 = contents1.get();
+  tabstrip.InsertWebContentsAt(0, std::move(contents1),
                                TabStripModel::ADD_ACTIVE);
 
   // Deactivate the first tab by inserting new tab.
-  WebContents* contents2 = CreateTestWebContents();
-  tabstrip.InsertWebContentsAt(1, base::WrapUnique(contents2),
+  std::unique_ptr<WebContents> contents2 = CreateTestWebContents();
+  WebContents* raw_contents2 = contents2.get();
+  tabstrip.InsertWebContentsAt(1, std::move(contents2),
                                TabStripModel::ADD_ACTIVE);
 
   tester.ExpectUniqueSample(
@@ -58,7 +60,7 @@
       static_cast<int>(TabStripModelStatsRecorder::TabState::INACTIVE), 1);
 
   // Reactivate the first tab.
-  tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(contents1), true);
+  tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(raw_contents1), true);
 
   tester.ExpectUniqueSample(
       "Tabs.StateTransfer.Target_Active",
@@ -71,12 +73,11 @@
 
   // Replace the contents of the first tab.
   // TabStripModeStatsRecorder should follow WebContents change.
-  std::unique_ptr<WebContents> contents3 =
-      base::WrapUnique(CreateTestWebContents());
+  std::unique_ptr<WebContents> contents3 = CreateTestWebContents();
   tabstrip.ReplaceWebContentsAt(0, std::move(contents3));
 
   // Close the inactive second tab.
-  tabstrip.CloseWebContentsAt(tabstrip.GetIndexOfWebContents(contents2),
+  tabstrip.CloseWebContentsAt(tabstrip.GetIndexOfWebContents(raw_contents2),
                               TabStripModel::CLOSE_USER_GESTURE |
                                   TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
 
@@ -107,18 +108,15 @@
   HistogramTester tester;
 
   // Create a tab in strip 1.
-  WebContents* contents1 = CreateTestWebContents();
-  tabstrip1.InsertWebContentsAt(0, base::WrapUnique(contents1),
+  tabstrip1.InsertWebContentsAt(0, CreateTestWebContents(),
                                 TabStripModel::ADD_ACTIVE);
 
   // Create a tab in strip 2.
-  WebContents* contents2 = CreateTestWebContents();
-  tabstrip2.InsertWebContentsAt(0, base::WrapUnique(contents2),
+  tabstrip2.InsertWebContentsAt(0, CreateTestWebContents(),
                                 TabStripModel::ADD_ACTIVE);
 
   // Create another tab in strip 1.
-  WebContents* contents3 = CreateTestWebContents();
-  tabstrip1.InsertWebContentsAt(1, base::WrapUnique(contents3),
+  tabstrip1.InsertWebContentsAt(1, CreateTestWebContents(),
                                 TabStripModel::ADD_ACTIVE);
 
   tester.ExpectUniqueSample(
@@ -126,8 +124,7 @@
       static_cast<int>(TabStripModelStatsRecorder::TabState::INACTIVE), 1);
 
   // Create another tab in strip 2.
-  WebContents* contents4 = CreateTestWebContents();
-  tabstrip2.InsertWebContentsAt(1, base::WrapUnique(contents4),
+  tabstrip2.InsertWebContentsAt(1, CreateTestWebContents(),
                                 TabStripModel::ADD_ACTIVE);
 
   tester.ExpectUniqueSample(
@@ -178,19 +175,19 @@
   HistogramTester tester;
 
   // Create first tab
-  WebContents* contents0 = CreateTestWebContents();
-  tabstrip.InsertWebContentsAt(0, base::WrapUnique(contents0),
+  std::unique_ptr<WebContents> contents0 = CreateTestWebContents();
+  WebContents* raw_contents0 = contents0.get();
+  tabstrip.InsertWebContentsAt(0, std::move(contents0),
                                TabStripModel::ADD_ACTIVE);
 
   // Add 9 more tabs and activate them
   for (int i = 1; i < 10; ++i) {
-    WebContents* contents = CreateTestWebContents();
-    tabstrip.InsertWebContentsAt(1, base::WrapUnique(contents),
+    tabstrip.InsertWebContentsAt(1, CreateTestWebContents(),
                                  TabStripModel::ADD_ACTIVE);
   }
 
   // Reactivate the first tab
-  tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(contents0), true);
+  tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(raw_contents0), true);
 
   tester.ExpectUniqueSample(
       "Tabs.StateTransfer.NumberOfOtherTabsActivatedBeforeMadeActive", 9, 1);
@@ -210,22 +207,25 @@
   HistogramTester tester;
 
   // Create tab 0, 1, 2
-  WebContents* contents0 = CreateTestWebContents();
-  WebContents* contents1 = CreateTestWebContents();
-  WebContents* contents2 = CreateTestWebContents();
-  tabstrip.InsertWebContentsAt(0, base::WrapUnique(contents0),
+  std::unique_ptr<WebContents> contents0 = CreateTestWebContents();
+  WebContents* raw_contents0 = contents0.get();
+  std::unique_ptr<WebContents> contents1 = CreateTestWebContents();
+  WebContents* raw_contents1 = contents1.get();
+  std::unique_ptr<WebContents> contents2 = CreateTestWebContents();
+  WebContents* raw_contents2 = contents2.get();
+  tabstrip.InsertWebContentsAt(0, std::move(contents0),
                                TabStripModel::ADD_ACTIVE);
-  tabstrip.InsertWebContentsAt(1, base::WrapUnique(contents1),
+  tabstrip.InsertWebContentsAt(1, std::move(contents1),
                                TabStripModel::ADD_ACTIVE);
-  tabstrip.InsertWebContentsAt(2, base::WrapUnique(contents2),
+  tabstrip.InsertWebContentsAt(2, std::move(contents2),
                                TabStripModel::ADD_ACTIVE);
 
   // Switch between tabs {0,1} for 5 times, then switch to tab 2
   for (int i = 0; i < 5; ++i) {
-    tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(contents0), true);
-    tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(contents1), true);
+    tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(raw_contents0), true);
+    tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(raw_contents1), true);
   }
-  tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(contents2), true);
+  tabstrip.ActivateTabAt(tabstrip.GetIndexOfWebContents(raw_contents2), true);
 
   EXPECT_THAT(
       tester.GetAllSamples(
diff --git a/chrome/browser/ui/tabs/web_contents_closer.cc b/chrome/browser/ui/tabs/web_contents_closer.cc
deleted file mode 100644
index 503f9ae..0000000
--- a/chrome/browser/ui/tabs/web_contents_closer.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/tabs/web_contents_closer.h"
-
-#include <memory>
-
-#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
-#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace {
-
-// CloseTracker is used when closing a set of WebContents. It listens for
-// deletions of the WebContents and removes from the internal set any time one
-// is deleted.
-class CloseTracker {
- public:
-  using Contents = base::span<content::WebContents* const>;
-
-  explicit CloseTracker(const Contents& contents);
-  ~CloseTracker();
-
-  // Returns true if there is another WebContents in the Tracker.
-  bool HasNext() const;
-
-  // Returns the next WebContents, or NULL if there are no more.
-  content::WebContents* Next();
-
- private:
-  class DeletionObserver : public content::WebContentsObserver {
-   public:
-    DeletionObserver(CloseTracker* parent, content::WebContents* web_contents)
-        : WebContentsObserver(web_contents), parent_(parent) {}
-
-   private:
-    // WebContentsObserver:
-    void WebContentsDestroyed() override {
-      parent_->OnWebContentsDestroyed(this);
-    }
-
-    CloseTracker* parent_;
-
-    DISALLOW_COPY_AND_ASSIGN(DeletionObserver);
-  };
-
-  void OnWebContentsDestroyed(DeletionObserver* observer);
-
-  using Observers = std::vector<std::unique_ptr<DeletionObserver>>;
-  Observers observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(CloseTracker);
-};
-
-CloseTracker::CloseTracker(const Contents& contents) {
-  observers_.reserve(contents.size());
-  for (content::WebContents* current : contents)
-    observers_.push_back(std::make_unique<DeletionObserver>(this, current));
-}
-
-CloseTracker::~CloseTracker() {
-  DCHECK(observers_.empty());
-}
-
-bool CloseTracker::HasNext() const {
-  return !observers_.empty();
-}
-
-content::WebContents* CloseTracker::Next() {
-  if (observers_.empty())
-    return nullptr;
-
-  DeletionObserver* observer = observers_[0].get();
-  content::WebContents* web_contents = observer->web_contents();
-  observers_.erase(observers_.begin());
-  return web_contents;
-}
-
-void CloseTracker::OnWebContentsDestroyed(DeletionObserver* observer) {
-  for (auto i = observers_.begin(); i != observers_.end(); ++i) {
-    if (observer == i->get()) {
-      observers_.erase(i);
-      return;
-    }
-  }
-  NOTREACHED() << "WebContents destroyed that wasn't in the list";
-}
-
-}  // namespace
-
-bool CloseWebContentses(WebContentsCloseDelegate* delegate,
-                        base::span<content::WebContents* const> items,
-                        uint32_t close_types) {
-  if (items.empty())
-    return true;
-
-  CloseTracker close_tracker(items);
-
-  // We only try the fast shutdown path if the whole browser process is *not*
-  // shutting down. Fast shutdown during browser termination is handled in
-  // browser_shutdown::OnShutdownStarting.
-  if (browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) {
-    // Construct a map of processes to the number of associated tabs that are
-    // closing.
-    base::flat_map<content::RenderProcessHost*, size_t> processes;
-    for (content::WebContents* contents : items) {
-      if (delegate->ShouldRunUnloadListenerBeforeClosing(contents))
-        continue;
-      content::RenderProcessHost* process =
-          contents->GetMainFrame()->GetProcess();
-      ++processes[process];
-    }
-
-    // Try to fast shutdown the tabs that can close.
-    for (const auto& pair : processes)
-      pair.first->FastShutdownIfPossible(pair.second, false);
-  }
-
-  // We now return to our regularly scheduled shutdown procedure.
-  bool closed_all = true;
-  while (close_tracker.HasNext()) {
-    content::WebContents* closing_contents = close_tracker.Next();
-    if (!delegate->ContainsWebContents(closing_contents))
-      continue;
-
-    CoreTabHelper* core_tab_helper =
-        CoreTabHelper::FromWebContents(closing_contents);
-    core_tab_helper->OnCloseStarted();
-
-    // Update the explicitly closed state. If the unload handlers cancel the
-    // close the state is reset in Browser. We don't update the explicitly
-    // closed state if already marked as explicitly closed as unload handlers
-    // call back to this if the close is allowed.
-    if (!closing_contents->GetClosedByUserGesture()) {
-      closing_contents->SetClosedByUserGesture(
-          close_types & TabStripModel::CLOSE_USER_GESTURE);
-    }
-
-    if (delegate->RunUnloadListenerBeforeClosing(closing_contents)) {
-      closed_all = false;
-      continue;
-    }
-
-    delegate->OnWillDeleteWebContents(closing_contents, close_types);
-
-    delete closing_contents;
-  }
-
-  return closed_all;
-}
diff --git a/chrome/browser/ui/tabs/web_contents_closer.h b/chrome/browser/ui/tabs/web_contents_closer.h
deleted file mode 100644
index 4b459500..0000000
--- a/chrome/browser/ui/tabs/web_contents_closer.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_TABS_WEB_CONTENTS_CLOSER_H_
-#define CHROME_BROWSER_UI_TABS_WEB_CONTENTS_CLOSER_H_
-
-#include <stdint.h>
-
-#include "base/containers/span.h"
-
-namespace content {
-class WebContents;
-}
-
-class WebContentsCloseDelegate {
- public:
-  // Returns true if the delegate still contains the tab.
-  virtual bool ContainsWebContents(content::WebContents* contents) = 0;
-
-  // Called right befor deleting |contents|. Gives the delegate a change to do
-  // last minute cleaning. |close_types| is the |close_types| supplied to
-  // CloseWebContentses().
-  virtual void OnWillDeleteWebContents(content::WebContents* contents,
-                                       uint32_t close_types) = 0;
-
-  // These mirror that of TabStripModelDelegate, see it for details.
-  virtual bool RunUnloadListenerBeforeClosing(
-      content::WebContents* contents) = 0;
-  virtual bool ShouldRunUnloadListenerBeforeClosing(
-      content::WebContents* contents) = 0;
-
- protected:
-  virtual ~WebContentsCloseDelegate() {}
-};
-
-// |close_types| is a bitmask of the types in TabStripModel::CloseTypes.
-// Returns true if all the tabs have been deleted. A return value of false means
-// some portion (potentially none) of the WebContents were deleted. WebContents
-// not deleted by this function are processing unload handlers which may
-// eventually be deleted based on the results of the unload handler.
-// Additionally processing the unload handlers may result in needing to show UI
-// for the WebContents. See UnloadController for details on how unload handlers
-// are processed.
-bool CloseWebContentses(WebContentsCloseDelegate* delegate,
-                        base::span<content::WebContents* const> items,
-                        uint32_t close_types);
-
-#endif  // CHROME_BROWSER_UI_TABS_WEB_CONTENTS_CLOSER_H_
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index 051600e..c4539e5 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -7,9 +7,9 @@
 #include <utility>
 
 #include "apps/ui/views/app_window_frame_view.h"
-#include "ash/ash_constants.h"
 #include "ash/frame/custom_frame_view_ash.h"
 #include "ash/public/cpp/app_types.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 #include "ash/public/cpp/shell_window_ids.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 0d9e6b2..83cc1409 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 
-#include "ash/ash_constants.h"
 #include "ash/ash_layout_constants.h"
 #include "ash/frame/caption_buttons/frame_back_button.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
@@ -15,6 +14,7 @@
 #include "ash/frame/frame_header_origin_text.h"
 #include "ash/frame/frame_header_util.h"
 #include "ash/public/cpp/app_types.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/window_properties.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index eaa1ed3..4fa8ce4 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -6,12 +6,12 @@
 
 #include <string>
 
-#include "ash/ash_constants.h"
 #include "ash/ash_layout_constants.h"
 #include "ash/frame/caption_buttons/frame_caption_button.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/frame/default_frame_header.h"
 #include "ash/frame/frame_header.h"
+#include "ash/public/cpp/ash_constants.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/public/cpp/vector_icons/vector_icons.h"
diff --git a/chrome/browser/ui/views/frame/browser_root_view.cc b/chrome/browser/ui/views/frame/browser_root_view.cc
index 090c230..d544c9ec 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view.cc
@@ -90,7 +90,11 @@
 }  // namespace
 
 BrowserRootView::DropInfo::DropInfo() = default;
-BrowserRootView::DropInfo::~DropInfo() = default;
+
+BrowserRootView::DropInfo::~DropInfo() {
+  if (target)
+    target->HandleDragExited();
+}
 
 // static
 const char BrowserRootView::kViewClassName[] =
@@ -161,7 +165,7 @@
       drop_info_->target->HandleDragExited();
     drop_info_->target = drop_target;
 
-    if (!drop_info_->file_supported || !drop_info_->url.is_valid() ||
+    if (!drop_info_->file_supported ||
         drop_info_->url.SchemeIs(url::kJavaScriptScheme)) {
       drop_info_->index.reset();
     } else {
@@ -179,11 +183,6 @@
 }
 
 void BrowserRootView::OnDragExited() {
-  if (drop_info_ && drop_info_->target) {
-    drop_info_->target->HandleDragExited();
-    drop_info_->target = nullptr;
-  }
-
   drop_info_.reset();
 }
 
@@ -193,6 +192,10 @@
   if (!drop_info_)
     return ui::DragDropTypes::DRAG_NONE;
 
+  // Ensure we call HandleDragExited() on |drop_info_|'s |target| when this
+  // function returns.
+  std::unique_ptr<DropInfo> drop_info = std::move(drop_info_);
+
   // Extract the URL and create a new ui::OSExchangeData containing the URL. We
   // do this as the TabStrip doesn't know about the autocomplete edit and needs
   // to know about it to handle 'paste and go'.
@@ -204,15 +207,15 @@
 
   // Do nothing if the file was unsupported, the URL is invalid, or this is a
   // javascript: URL (prevent self-xss). The URL may have been changed after
-  // |drop_info_| was created.
-  if (!drop_info_->file_supported || !url.is_valid() ||
+  // |drop_info| was created.
+  if (!drop_info->file_supported || !url.is_valid() ||
       url.SchemeIs(url::kJavaScriptScheme))
     return ui::DragDropTypes::DRAG_NONE;
 
   NavigateParams params(browser_view_->browser(), url,
                         ui::PAGE_TRANSITION_LINK);
-  params.tabstrip_index = drop_info_->index->value;
-  if (drop_info_->index->drop_before) {
+  params.tabstrip_index = drop_info->index->value;
+  if (drop_info->index->drop_before) {
     base::RecordAction(UserMetricsAction("Tab_DropURLBetweenTabs"));
     params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
   } else {
@@ -220,7 +223,7 @@
     params.disposition = WindowOpenDisposition::CURRENT_TAB;
     Browser* browser = browser_view_->browser();
     TabStripModel* model = browser->tab_strip_model();
-    params.source_contents = model->GetWebContentsAt(drop_info_->index->value);
+    params.source_contents = model->GetWebContentsAt(drop_info->index->value);
   }
 
   params.window_action = NavigateParams::SHOW_WINDOW;
diff --git a/chrome/browser/ui/views/frame/browser_root_view.h b/chrome/browser/ui/views/frame/browser_root_view.h
index 7435881..c4942a98 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.h
+++ b/chrome/browser/ui/views/frame/browser_root_view.h
@@ -72,6 +72,8 @@
   void OnMouseExited(const ui::MouseEvent& event) override;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(BrowserRootViewBrowserTest, ClearDropInfo);
+
   // Used during a drop session of a url. Tracks the position of the drop.
   struct DropInfo {
     DropInfo();
diff --git a/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc
new file mode 100644
index 0000000..35086013
--- /dev/null
+++ b/chrome/browser/ui/views/frame/browser_root_view_browsertest.cc
@@ -0,0 +1,54 @@
+// 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/views/frame/browser_root_view.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+#include "ui/base/dragdrop/drop_target_event.h"
+#include "ui/base/dragdrop/os_exchange_data.h"
+
+class BrowserRootViewBrowserTest : public InProcessBrowserTest {
+ public:
+  BrowserRootViewBrowserTest() = default;
+
+  BrowserRootView* browser_root_view() {
+    BrowserView* browser_view = static_cast<BrowserView*>(browser()->window());
+    return static_cast<BrowserRootView*>(
+        browser_view->GetWidget()->GetRootView());
+  }
+
+ private:
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserRootViewBrowserTest);
+};
+
+// Clear drop info after performing drop. http://crbug.com/838791
+IN_PROC_BROWSER_TEST_F(BrowserRootViewBrowserTest, ClearDropInfo) {
+  ui::OSExchangeData data;
+  data.SetURL(GURL("http://www.chromium.org/"), base::string16());
+  ui::DropTargetEvent event(data, gfx::Point(), gfx::Point(),
+                            ui::DragDropTypes::DRAG_COPY);
+
+  BrowserRootView* root_view = browser_root_view();
+  root_view->OnDragUpdated(event);
+  root_view->OnPerformDrop(event);
+  EXPECT_FALSE(root_view->drop_info_);
+}
+
+// Make sure plain string is droppable. http://crbug.com/838794
+IN_PROC_BROWSER_TEST_F(BrowserRootViewBrowserTest, PlainString) {
+  ui::OSExchangeData data;
+  data.SetString(base::ASCIIToUTF16("Plain string"));
+  ui::DropTargetEvent event(data, gfx::Point(), gfx::Point(),
+                            ui::DragDropTypes::DRAG_COPY);
+
+  BrowserRootView* root_view = browser_root_view();
+  EXPECT_NE(ui::DragDropTypes::DRAG_NONE, root_view->OnDragUpdated(event));
+  EXPECT_NE(ui::DragDropTypes::DRAG_NONE, root_view->OnPerformDrop(event));
+}
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view_unittest.cc b/chrome/browser/ui/views/media_router/web_contents_display_observer_view_unittest.cc
index dd900e8..1561645 100644
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view_unittest.cc
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view_unittest.cc
@@ -49,7 +49,7 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
-    web_contents_.reset(CreateTestWebContents());
+    web_contents_ = CreateTestWebContents();
     display_observer_ = std::make_unique<TestWebContentsDisplayObserverView>(
         web_contents_.get(),
         base::BindRepeating(&MockCallback::OnDisplayChanged,
diff --git a/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc
index 684dfbfe..7c863b5 100644
--- a/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.cc
@@ -111,8 +111,6 @@
       user_context.SetKey(key);
       user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
       user_context.SetIsUsingOAuth(false);
-      user_context.SetUserType(
-          user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
       LoginDisplayHost::default_host()->CompleteLogin(user_context);
       break;
     }
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 28dee8d..479ab976 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -16,6 +16,7 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/task_scheduler/post_task.h"
@@ -662,8 +663,6 @@
       user_context.SetKey(key);
       user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY);
       user_context.SetIsUsingOAuth(false);
-      user_context.SetUserType(
-          user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY);
       LoginDisplayHost::default_host()->CompleteLogin(user_context);
       break;
     }
@@ -898,12 +897,14 @@
 }
 
 void GaiaScreenHandler::ShowSigninScreenForTest(const std::string& username,
-                                                const std::string& password) {
+                                                const std::string& password,
+                                                const std::string& services) {
   VLOG(2) << "ShowSigninScreenForTest for user " << username
           << ", frame_state=" << frame_state();
 
   test_user_ = username;
   test_pass_ = password;
+  test_services_ = services;
   test_expects_complete_login_ = true;
 
   // Submit login form for test if gaia is ready. If gaia is loading, login
@@ -927,6 +928,16 @@
       "document.getElementById('nextButton').click();";
   frame->ExecuteJavaScriptForTests(base::ASCIIToUTF16(code));
 
+  if (!test_services_.empty()) {
+    // Prefix each doublequote with backslash, so that it will remain correct
+    // JSON after assigning to the element property.
+    std::string escaped_services;
+    base::ReplaceChars(test_services_, "\"", "\\\"", &escaped_services);
+    code = "document.getElementById('services').value = \"" + escaped_services +
+           "\";";
+    frame->ExecuteJavaScriptForTests(base::ASCIIToUTF16(code));
+  }
+
   if (!test_pass_.empty()) {
     code = "document.getElementById('password').value = '" + test_pass_ + "';";
     code += "document.getElementById('nextButton').click();";
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
index 287881d8..ca864555 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -159,8 +159,10 @@
                 const authpolicy::ActiveDirectoryAccountInfo& account_info);
 
   // Show sign-in screen for the given credentials.
+  // Should match the same method in SigninScreenHandler.
   void ShowSigninScreenForTest(const std::string& username,
-                               const std::string& password);
+                               const std::string& password,
+                               const std::string& services);
   // Attempts login for test.
   void SubmitLoginFormForTest();
 
@@ -252,6 +254,8 @@
   // Test credentials.
   std::string test_user_;
   std::string test_pass_;
+  // Test result of userInfo.
+  std::string test_services_;
   bool test_expects_complete_login_ = false;
 
   // True if proxy doesn't allow access to google.com/generate_204.
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 3af82c2..02b21f3 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -1073,10 +1073,10 @@
   core_oobe_view_->ShowPasswordChangedScreen(show_password_error, email);
 }
 
-void SigninScreenHandler::ShowSigninScreenForCreds(
-    const std::string& username,
-    const std::string& password) {
-  gaia_screen_handler_->ShowSigninScreenForTest(username, password);
+void SigninScreenHandler::ShowSigninScreenForTest(const std::string& username,
+                                                  const std::string& password,
+                                                  const std::string& services) {
+  gaia_screen_handler_->ShowSigninScreenForTest(username, password, services);
 }
 
 void SigninScreenHandler::ShowWhitelistCheckFailedError() {
@@ -1212,7 +1212,19 @@
   DCHECK_EQ(account_id.GetUserEmail(),
             gaia::SanitizeEmail(account_id.GetUserEmail()));
 
-  UserContext user_context(account_id);
+  const user_manager::User* user =
+      user_manager::UserManager::Get()->FindUser(account_id);
+  DCHECK(user);
+  user_manager::UserType user_type = user_manager::UserType::USER_TYPE_REGULAR;
+  if (!user) {
+    LOG(ERROR) << "HandleAuthenticateUser: User not found! account type="
+               << AccountId::AccountTypeToString(account_id.GetAccountType());
+    if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
+      user_type = user_manager::USER_TYPE_ACTIVE_DIRECTORY;
+  } else {
+    user_type = user->GetType();
+  }
+  UserContext user_context(user_type, account_id);
   user_context.SetKey(Key(password));
   // Only save the password for enterprise users. See https://crbug.com/386606.
   const bool is_enterprise_managed = g_browser_process->platform_part()
@@ -1222,17 +1234,13 @@
     user_context.SetPasswordKey(Key(password));
   }
   user_context.SetIsUsingPin(authenticated_by_pin);
-  const user_manager::User* user =
-      user_manager::UserManager::Get()->FindUser(account_id);
-  DCHECK(user);
-  if (!user) {
-    LOG(ERROR) << "HandleAuthenticateUser: User not found! account type="
-               << AccountId::AccountTypeToString(account_id.GetAccountType());
-  } else {
-    user_context.SetUserType(user->GetType());
+  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY &&
+      (user_context.GetUserType() !=
+       user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY)) {
+    LOG(FATAL) << "Incorrect Active Directory user type "
+               << user_context.GetUserType();
   }
-  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
-    user_context.SetUserType(user_manager::USER_TYPE_ACTIVE_DIRECTORY);
+
   delegate_->Login(user_context, SigninSpecifics());
 
   UpdatePinKeyboardState(account_id);
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index c801908..3d9bda5 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -115,8 +115,11 @@
   virtual void ShowPasswordChangedDialog(bool show_password_error,
                                          const std::string& email) = 0;
   // Show sign-in screen for the given credentials.
-  virtual void ShowSigninScreenForCreds(const std::string& username,
-                                        const std::string& password) = 0;
+  // |services| - list of services returned by userInfo call as JSON array.
+  // Should be empty array for regular user: "[]".
+  virtual void ShowSigninScreenForTest(const std::string& username,
+                                       const std::string& password,
+                                       const std::string& services) = 0;
   virtual void ShowWhitelistCheckFailedError() = 0;
   virtual void ShowUnrecoverableCrypthomeErrorDialog() = 0;
   virtual void LoadUsers(const user_manager::UserList& users,
@@ -342,8 +345,9 @@
   void ShowPasswordChangedDialog(bool show_password_error,
                                  const std::string& email) override;
   void ShowErrorScreen(LoginDisplay::SigninError error_id) override;
-  void ShowSigninScreenForCreds(const std::string& username,
-                                const std::string& password) override;
+  void ShowSigninScreenForTest(const std::string& username,
+                               const std::string& password,
+                               const std::string& services) override;
   void ShowWhitelistCheckFailedError() override;
   void ShowUnrecoverableCrypthomeErrorDialog() override;
   void LoadUsers(const user_manager::UserList& users,
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 785966a2..3c401ca 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -781,7 +781,7 @@
       delegate->ReleaseWebContents();
   DCHECK_EQ(preview_dialog, preview_contents.get());
   background_printing_manager->OwnPrintPreviewDialog(
-      preview_contents.release());
+      std::move(preview_contents));
   OnClosePrintPreviewDialog();
 }
 
diff --git a/chrome/browser/ui/webui/snippets_internals/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals/snippets_internals_message_handler.cc
index e1ebaeb..738860b 100644
--- a/chrome/browser/ui/webui/snippets_internals/snippets_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/snippets_internals/snippets_internals_message_handler.cc
@@ -54,7 +54,6 @@
 using ntp_snippets::CategoryStatus;
 using ntp_snippets::ContentSuggestion;
 using ntp_snippets::IsBookmarkProviderEnabled;
-using ntp_snippets::IsRecentTabProviderEnabled;
 using ntp_snippets::KnownCategories;
 using ntp_snippets::RemoteSuggestion;
 using ntp_snippets::RemoteSuggestionsProvider;
@@ -94,17 +93,6 @@
     entry->Set("downloadSuggestionExtra", std::move(value));
   }
 
-  if (suggestion.recent_tab_suggestion_extra()) {
-    const auto& extra = *suggestion.recent_tab_suggestion_extra();
-    auto value = std::make_unique<base::DictionaryValue>();
-    value->SetInteger("tabID", extra.tab_id);
-    value->SetString(
-        "offlinePageID",
-        base::StringPrintf("0x%016llx", static_cast<long long unsigned int>(
-                                            extra.offline_page_id)));
-    entry->Set("recentTabSuggestionExtra", std::move(value));
-  }
-
   if (suggestion.notification_extra()) {
     const auto& extra = *suggestion.notification_extra();
     auto value = std::make_unique<base::DictionaryValue>();
@@ -425,8 +413,6 @@
       "flag-article-suggestions",
       base::FeatureList::IsEnabled(ntp_snippets::kArticleSuggestionsFeature));
 
-  SendBoolean("flag-recent-offline-tab-suggestions",
-              IsRecentTabProviderEnabled());
   SendBoolean("flag-offlining-recent-pages-feature",
               base::FeatureList::IsEnabled(
                   offline_pages::kOffliningRecentPagesFeature));
diff --git a/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc b/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc
index b3d3f6a..5d7dea32 100644
--- a/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc
+++ b/chrome/browser/ui/webui/web_dialog_web_contents_delegate_unittest.cc
@@ -89,8 +89,8 @@
 }
 
 TEST_F(WebDialogWebContentsDelegateTest, AddNewContentsForegroundTabTest) {
-  std::unique_ptr<WebContents> contents = base::WrapUnique(
-      WebContentsTester::CreateTestWebContents(profile(), NULL));
+  std::unique_ptr<WebContents> contents =
+      WebContentsTester::CreateTestWebContents(profile(), NULL);
   test_web_contents_delegate_->AddNewContents(
       NULL, std::move(contents), WindowOpenDisposition::NEW_FOREGROUND_TAB,
       gfx::Rect(), false, NULL);
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index d78d3a3..ff81d2c9 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -14,7 +14,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/net/url_request_mock_util.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -963,35 +962,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FastUnloadTest,
-                       BrowserListForceCloseWithIncognitoProfileCloseProfiles) {
-  Profile* otr_profile = browser()->profile()->GetOffTheRecordProfile();
-  Browser* otr_browser1 = CreateBrowser(otr_profile);
-  Browser* otr_browser2 = CreateBrowser(otr_profile);
-  content::WindowedNotificationObserver otr_browser1_observer(
-      chrome::NOTIFICATION_BROWSER_CLOSED,
-      content::Source<Browser>(otr_browser1));
-  content::WindowedNotificationObserver otr_browser2_observer(
-      chrome::NOTIFICATION_BROWSER_CLOSED,
-      content::Source<Browser>(otr_browser2));
-  UnloadResults unload_results;
-  BrowserList::CloseAllBrowsersWithIncognitoProfile(
-      otr_profile,
-      base::BindRepeating(&UnloadResults::AddSuccess,
-                          base::Unretained(&unload_results)),
-      base::BindRepeating(&UnloadResults::AddAbort,
-                          base::Unretained(&unload_results)),
-      true);
-  // Incognito browsers should be closed.
-  otr_browser1_observer.Wait();
-  otr_browser2_observer.Wait();
-  // Browser with original profile should not close.
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-
-  EXPECT_EQ(1, unload_results.get_successes());
-  EXPECT_EQ(0, unload_results.get_aborts());
-}
-
-IN_PROC_BROWSER_TEST_F(FastUnloadTest,
                        BrowserListForceCloseAfterNormalCloseWithFastUnload) {
   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
   PrepareForDialog(browser());
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 635ba1a..78bdbc1 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1480,6 +1480,7 @@
           "../browser/ui/views/extensions/extension_uninstall_dialog_view_browsertest.cc",
           "../browser/ui/views/extensions/media_galleries_dialog_views_browsertest.cc",
           "../browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc",
+          "../browser/ui/views/frame/browser_root_view_browsertest.cc",
           "../browser/ui/views/frame/browser_view_browsertest.cc",
           "../browser/ui/views/hung_renderer_view_browsertest.cc",
           "../browser/ui/views/location_bar/location_bar_view_browsertest.cc",
diff --git a/chrome/test/data/webui/cr_elements/cr_checkbox_test.js b/chrome/test/data/webui/cr_elements/cr_checkbox_test.js
index d81c0e7..2d8d9827 100644
--- a/chrome/test/data/webui/cr_elements/cr_checkbox_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_checkbox_test.js
@@ -8,14 +8,14 @@
   setup(function() {
     PolymerTest.clearBody();
     document.body.innerHTML = `
-      <cr-checkbox id="checkbox">
-        <div id="label">label
-          <a id="link">link</a>
+      <cr-checkbox>
+        <div>label
+          <a>link</a>
         </div>
       </cr-checkbox>
     `;
 
-    checkbox = document.getElementById('checkbox');
+    checkbox = document.querySelector('cr-checkbox');
     assertNotChecked();
   });
 
@@ -143,7 +143,7 @@
     });
 
     assertNotChecked();
-    link = document.getElementById('link');
+    link = document.querySelector('a');
     link.click();
     assertNotChecked();
 
@@ -153,4 +153,29 @@
     // Wait 1 cycle to make sure change-event was not fired.
     setTimeout(done);
   });
+
+  test('InitializingWithTabindex', function() {
+    PolymerTest.clearBody();
+    document.body.innerHTML = `
+      <cr-checkbox id="checkbox" tabindex="-1"></cr-checkbox>
+    `;
+
+    checkbox = document.querySelector('cr-checkbox');
+
+    // Should not override tabindex if it is initialized.
+    assertEquals(-1, checkbox.tabIndex);
+  });
+
+
+  test('InitializingWithDisabled', function() {
+    PolymerTest.clearBody();
+    document.body.innerHTML = `
+      <cr-checkbox id="checkbox" disabled></cr-checkbox>
+    `;
+
+    checkbox = document.querySelector('cr-checkbox');
+
+    // Initializing with disabled should make tabindex="-1".
+    assertEquals(-1, checkbox.tabIndex);
+  });
 });
diff --git a/chrome/test/data/webui/print_preview/advanced_dialog_test.js b/chrome/test/data/webui/print_preview/advanced_dialog_test.js
new file mode 100644
index 0000000..4beff9f
--- /dev/null
+++ b/chrome/test/data/webui/print_preview/advanced_dialog_test.js
@@ -0,0 +1,83 @@
+// 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.
+
+cr.define('advanced_dialog_test', function() {
+  /** @enum {string} */
+  const TestNames = {
+    AdvancedSettings1Option: 'advanced settings 1 option',
+    AdvancedSettings2Options: 'advanced settings 2 options',
+  };
+
+  const suiteName = 'AdvancedDialogTest';
+  suite(suiteName, function() {
+    /** @type {?PrintPreviewAdvancedSettingsDialogElement} */
+    let dialog = null;
+
+    /** @type {?print_preview.Destination} */
+    let destination = null;
+
+    /** @type {string} */
+    let printerId = 'FooDevice';
+
+    /** @type {string} */
+    let printerName = 'FooName';
+
+    /** @override */
+    setup(function() {
+      // Create destination
+      destination = new print_preview.Destination(
+          printerId, print_preview.DestinationType.GOOGLE,
+          print_preview.DestinationOrigin.COOKIES, printerName,
+          true /* isRecent */,
+          print_preview.DestinationConnectionStatus.ONLINE);
+      PolymerTest.clearBody();
+      dialog = document.createElement('print-preview-advanced-dialog');
+    });
+
+    /**
+     * Verifies that the search box is shown or hidden based on the number
+     * of capabilities and that the correct number of items are created.
+     * @param {number} count The number of vendor capabilities the printer
+     *     should have.
+     */
+    function testListWithItemCount(count) {
+      const template =
+          print_preview_test_utils.getCddTemplateWithAdvancedSettings(
+              count, printerId, printerName);
+      destination.capabilities = template.capabilities;
+      dialog.destination = destination;
+
+      document.body.appendChild(dialog);
+      dialog.show();
+      Polymer.dom.flush();
+
+      // Search box should be hidden if there is only 1 item.
+      const searchBox = dialog.$.searchBox;
+      assertEquals(count == 1, searchBox.hidden);
+
+      // Verify item is displayed.
+      const vendorItems = template.capabilities.printer.vendor_capability;
+      const items = dialog.shadowRoot.querySelectorAll(
+          'print-preview-advanced-settings-item');
+      assertEquals(count, items.length);
+    }
+
+    // Tests that the search box does not appear when there is only one option,
+    // and that the vendor item is correctly displayed.
+    test(assert(TestNames.AdvancedSettings1Option), function() {
+      testListWithItemCount(1);
+    });
+
+    // Tests that the search box appears when there are two options, and that
+    // the items are correctly displayed.
+    test(assert(TestNames.AdvancedSettings2Options), function() {
+      testListWithItemCount(2);
+    });
+  });
+
+  return {
+    suiteName: suiteName,
+    TestNames: TestNames,
+  };
+});
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
index d63a2e5..a93aed8 100644
--- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -519,3 +519,33 @@
        function() {
   this.runMochaTest(destination_dialog_test.TestNames.PrinterList);
 });
+
+PrintPreviewAdvancedDialogTest = class extends NewPrintPreviewTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://print/new/advanced_settings_dialog.html';
+  }
+
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'print_preview_test_utils.js',
+      'advanced_dialog_test.js',
+    ]);
+  }
+
+  /** @override */
+  get suiteName() {
+    return advanced_dialog_test.suiteName;
+  }
+};
+
+TEST_F('PrintPreviewAdvancedDialogTest', 'AdvancedSettings1Option',
+       function() {
+  this.runMochaTest(advanced_dialog_test.TestNames.AdvancedSettings1Option);
+});
+
+TEST_F('PrintPreviewAdvancedDialogTest', 'AdvancedSettings2Options',
+       function() {
+  this.runMochaTest(advanced_dialog_test.TestNames.AdvancedSettings2Options);
+});
diff --git a/chrome/test/data/webui/print_preview/print_preview_test_utils.js b/chrome/test/data/webui/print_preview/print_preview_test_utils.js
index c324d80d..fe08bba 100644
--- a/chrome/test/data/webui/print_preview/print_preview_test_utils.js
+++ b/chrome/test/data/webui/print_preview/print_preview_test_utils.js
@@ -86,6 +86,51 @@
   }
 
   /**
+   * @param {number} numSettings
+   * @param {string} printerId
+   * @param {string=} opt_printerName Defaults to an empty string.
+   * @return {!print_preview.PrinterCapabilitiesResponse}
+   */
+  function getCddTemplateWithAdvancedSettings(
+      numSettings, printerId, opt_printerName) {
+    const template =
+        print_preview_test_utils.getCddTemplate(printerId, opt_printerName);
+    if (numSettings < 1)
+      return template;
+
+    template.capabilities.printer.vendor_capability = [{
+      display_name: 'Print Area',
+      id: 'Print Area',
+      type: 'SELECT',
+      select_cap: {
+        option: [
+          {display_name: 'A4', value: 4, is_default: true},
+          {display_name: 'A6', value: 6},
+          {display_name: 'A7', value: 7},
+        ],
+      },
+    }];
+
+    if (numSettings < 2)
+      return template;
+
+    // Add new capability.
+    template.capabilities.printer.vendor_capability.push({
+        display_name: 'Paper Type',
+        id: 'Paper Type',
+        type: 'SELECT',
+        select_cap: {
+            option: [
+                {display_name: 'Standard', value: 0, is_default: true},
+                {display_name: 'Recycled', value: 1},
+                {display_name: 'Special', value: 2}
+            ]
+        }
+    });
+    return template;
+  }
+
+  /**
    * Creates a destination with a certificate status tag.
    * @param {string} id Printer id
    * @param {string} name Printer display name
@@ -189,6 +234,7 @@
   return {
     getDefaultInitialSettings: getDefaultInitialSettings,
     getCddTemplate: getCddTemplate,
+    getCddTemplateWithAdvancedSettings: getCddTemplateWithAdvancedSettings,
     getDefaultMediaSize: getDefaultMediaSize,
     getDefaultOrientation: getDefaultOrientation,
     createDestinationWithCertificateStatus:
diff --git a/chrome/test/data/webui/print_preview/print_preview_tests.js b/chrome/test/data/webui/print_preview/print_preview_tests.js
index 6c9b9b17..32e3b37 100644
--- a/chrome/test/data/webui/print_preview/print_preview_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_tests.js
@@ -202,27 +202,6 @@
   }
 
   /**
-   * @param {string} printerId
-   * @return {!Object}
-   */
-  function getCddTemplateWithAdvancedSettings(printerId) {
-    const template = print_preview_test_utils.getCddTemplate(printerId);
-    template.capabilities.printer.vendor_capability = [{
-      display_name: 'Print Area',
-      id: 'Print Area',
-      type: 'SELECT',
-      select_cap: {
-        option: [
-          {display_name: 'A4', value: 4, is_default: true},
-          {display_name: 'A6', value: 6},
-          {display_name: 'A7', value: 7},
-        ],
-      },
-    }];
-    return template;
-  }
-
-  /**
    * Even though animation duration and delay is set to zero, it is necessary to
    * wait until the animation has finished.
    * @return {!Promise} A promise firing when the animation is done.
@@ -1253,7 +1232,9 @@
     // Test advanced settings with 1 capability (should not display settings
     // search box).
     test('AdvancedSettings1Option', function() {
-      const device = getCddTemplateWithAdvancedSettings('FooDevice');
+      const device =
+          print_preview_test_utils.getCddTemplateWithAdvancedSettings(
+              1, 'FooDevice');
       return setupSettingsAndDestinationsWithCapabilities(device)
           .then(function() {
         startAdvancedSettingsTest(device);
@@ -1264,24 +1245,12 @@
       });
     });
 
-
     // Test advanced settings with 2 capabilities (should have settings search
     // box).
     test('AdvancedSettings2Options', function() {
-      const device = getCddTemplateWithAdvancedSettings('FooDevice');
-       // Add new capability.
-      device.capabilities.printer.vendor_capability.push({
-          display_name: 'Paper Type',
-          id: 'Paper Type',
-          type: 'SELECT',
-          select_cap: {
-              option: [
-                  {display_name: 'Standard', value: 0, is_default: true},
-                  {display_name: 'Recycled', value: 1},
-                  {display_name: 'Special', value: 2}
-              ]
-          }
-      });
+      const device =
+          print_preview_test_utils.getCddTemplateWithAdvancedSettings(
+              2, 'FooDevice');
       return setupSettingsAndDestinationsWithCapabilities(device)
           .then(function() {
         startAdvancedSettingsTest(device);
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 7ee235ff..ea66bbc5 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10645.0.0
\ No newline at end of file
+10651.0.0
\ No newline at end of file
diff --git a/chromeos/components/tether/host_scan_scheduler_impl.cc b/chromeos/components/tether/host_scan_scheduler_impl.cc
index 2220577..0d17098 100644
--- a/chromeos/components/tether/host_scan_scheduler_impl.cc
+++ b/chromeos/components/tether/host_scan_scheduler_impl.cc
@@ -86,7 +86,7 @@
 }
 
 void HostScanSchedulerImpl::ScheduleScan() {
-  EnsureScan();
+  AttemptScan();
 }
 
 void HostScanSchedulerImpl::DefaultNetworkChanged(const NetworkState* network) {
@@ -102,12 +102,12 @@
   // NetworkStateHandlerObservers are finished running. Processing the
   // network change immediately can cause crashes; see https://crbug.com/800370.
   task_runner_->PostTask(FROM_HERE,
-                         base::BindOnce(&HostScanSchedulerImpl::EnsureScan,
+                         base::BindOnce(&HostScanSchedulerImpl::AttemptScan,
                                         weak_ptr_factory_.GetWeakPtr()));
 }
 
 void HostScanSchedulerImpl::ScanRequested() {
-  EnsureScan();
+  AttemptScan();
 }
 
 void HostScanSchedulerImpl::ScanFinished() {
@@ -142,7 +142,7 @@
   delay_scan_after_unlock_timer_->Start(
       FROM_HERE,
       base::TimeDelta::FromSeconds(kNumSecondsToDelayScanAfterUnlock),
-      base::Bind(&HostScanSchedulerImpl::EnsureScan,
+      base::Bind(&HostScanSchedulerImpl::AttemptScan,
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -158,10 +158,18 @@
   task_runner_ = test_task_runner;
 }
 
-void HostScanSchedulerImpl::EnsureScan() {
+void HostScanSchedulerImpl::AttemptScan() {
+  // If already scanning, there is nothing to do.
   if (host_scanner_->IsScanActive())
     return;
 
+  // If the screen is locked, a host scan should not occur.  A scan during the
+  // lock screen could cause bad interactions with EasyUnlock. See
+  // https://crbug.com/763604.
+  // Note: Once the SecureChannel API is available, this check can be removed.
+  if (session_manager_->IsScreenLocked())
+    return;
+
   // If the timer is running, this new scan is part of the same batch as the
   // previous scan, so the timer should be stopped (it will be restarted after
   // the new scan finishes). If the timer is not running, the new scan is part
diff --git a/chromeos/components/tether/host_scan_scheduler_impl.h b/chromeos/components/tether/host_scan_scheduler_impl.h
index d8cd7c6..3e5ab26 100644
--- a/chromeos/components/tether/host_scan_scheduler_impl.h
+++ b/chromeos/components/tether/host_scan_scheduler_impl.h
@@ -63,7 +63,7 @@
  private:
   friend class HostScanSchedulerImplTest;
 
-  void EnsureScan();
+  void AttemptScan();
   bool IsTetherNetworkConnectingOrConnected();
   void LogHostScanBatchMetric();
 
diff --git a/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc b/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
index 8b35b59a..4cae5d13 100644
--- a/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
+++ b/chromeos/components/tether/host_scan_scheduler_impl_unittest.cc
@@ -191,12 +191,18 @@
   VerifyScanDuration(5u /* expected_num_sections */);
 }
 
-TEST_F(HostScanSchedulerImplTest, ScansWhenDeviceUnlocked) {
+TEST_F(HostScanSchedulerImplTest, TestDeviceLockAndUnlock) {
   // Lock the screen. This should not trigger a scan.
   SetScreenLockedState(true /* is_locked */);
   EXPECT_EQ(0u, fake_host_scanner_->num_scans_started());
   EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning());
 
+  // Try to start a scan. Because the screen is locked, this should not actually
+  // cause a scan to be started.
+  host_scan_scheduler_->ScheduleScan();
+  EXPECT_EQ(0u, fake_host_scanner_->num_scans_started());
+  EXPECT_FALSE(mock_delay_scan_after_unlock_timer_->IsRunning());
+
   // Unlock the screen. A scan should not yet have been started, but the timer
   // should have.
   SetScreenLockedState(false /* is_locked */);
diff --git a/chromeos/login/auth/extended_authenticator.h b/chromeos/login/auth/extended_authenticator.h
index cfef8e59..89e937d 100644
--- a/chromeos/login/auth/extended_authenticator.h
+++ b/chromeos/login/auth/extended_authenticator.h
@@ -15,8 +15,6 @@
 #include "chromeos/chromeos_export.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 
-class AccountId;
-
 namespace chromeos {
 
 class AuthStatusConsumer;
@@ -70,16 +68,6 @@
   virtual void AuthenticateToCheck(const UserContext& context,
                                    const base::Closure& success_callback) = 0;
 
-  // This call will create and mount the home dir for |account_id| with the
-  // given |keys| if the home dir is missing. If the home dir exists already, a
-  // mount attempt will be performed using the first key in |keys| for
-  // authentication.  Note that all |keys| should have been transformed from
-  // plain text already.
-  // This method does not alter them.
-  virtual void CreateMount(const AccountId& account_id,
-                           const std::vector<cryptohome::KeyDefinition>& keys,
-                           const ResultCallback& success_callback) = 0;
-
   // Attempts to add a new |key| for the user identified/authorized by
   // |context|. If a key with the same label already exists, the behavior
   // depends on the |replace_existing| flag. If the flag is set, the old key is
diff --git a/chromeos/login/auth/extended_authenticator_impl.cc b/chromeos/login/auth/extended_authenticator_impl.cc
index 7f4a6d5..06fcdc5 100644
--- a/chromeos/login/auth/extended_authenticator_impl.cc
+++ b/chromeos/login/auth/extended_authenticator_impl.cc
@@ -82,33 +82,6 @@
                  success_callback));
 }
 
-void ExtendedAuthenticatorImpl::CreateMount(
-    const AccountId& account_id,
-    const std::vector<cryptohome::KeyDefinition>& keys,
-    const ResultCallback& success_callback) {
-  RecordStartMarker("MountEx");
-
-  cryptohome::Identification id(account_id);
-  cryptohome::MountRequest mount;
-  for (size_t i = 0; i < keys.size(); i++) {
-    cryptohome::KeyDefinitionToKey(keys[i], mount.mutable_create()->add_keys());
-  }
-  UserContext context(account_id);
-  Key key(keys.front().secret);
-  key.SetLabel(keys.front().label);
-  context.SetKey(key);
-  cryptohome::AuthorizationRequest auth;
-  cryptohome::Key* auth_key = auth.mutable_key();
-  if (!key.GetLabel().empty()) {
-    auth_key->mutable_data()->set_label(key.GetLabel());
-  }
-  auth_key->set_secret(key.GetSecret());
-  DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
-      id, auth, mount,
-      base::BindOnce(&ExtendedAuthenticatorImpl::OnMountComplete, this,
-                     "MountEx", context, success_callback));
-}
-
 void ExtendedAuthenticatorImpl::AddKey(const UserContext& context,
                                        const cryptohome::KeyDefinition& key,
                                        bool clobber_if_exists,
diff --git a/chromeos/login/auth/extended_authenticator_impl.h b/chromeos/login/auth/extended_authenticator_impl.h
index 7c086da..2b88201 100644
--- a/chromeos/login/auth/extended_authenticator_impl.h
+++ b/chromeos/login/auth/extended_authenticator_impl.h
@@ -17,8 +17,6 @@
 #include "chromeos/login/auth/extended_authenticator.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
-class AccountId;
-
 namespace chromeos {
 
 class AuthStatusConsumer;
@@ -36,9 +34,6 @@
                            const ResultCallback& success_callback) override;
   void AuthenticateToCheck(const UserContext& context,
                            const base::Closure& success_callback) override;
-  void CreateMount(const AccountId& account_id,
-                   const std::vector<cryptohome::KeyDefinition>& keys,
-                   const ResultCallback& success_callback) override;
   void AddKey(const UserContext& context,
               const cryptohome::KeyDefinition& key,
               bool clobber_if_exists,
diff --git a/chromeos/login/auth/fake_extended_authenticator.cc b/chromeos/login/auth/fake_extended_authenticator.cc
index 656e164..3824690 100644
--- a/chromeos/login/auth/fake_extended_authenticator.cc
+++ b/chromeos/login/auth/fake_extended_authenticator.cc
@@ -64,13 +64,6 @@
                 AuthFailure(AuthFailure::UNLOCK_FAILED));
 }
 
-void FakeExtendedAuthenticator::CreateMount(
-    const AccountId& account_id,
-    const std::vector<cryptohome::KeyDefinition>& keys,
-    const ResultCallback& success_callback) {
-  NOTREACHED();
-}
-
 void FakeExtendedAuthenticator::AddKey(const UserContext& context,
                     const cryptohome::KeyDefinition& key,
                     bool replace_existing,
diff --git a/chromeos/login/auth/fake_extended_authenticator.h b/chromeos/login/auth/fake_extended_authenticator.h
index ee48944..39a58a4 100644
--- a/chromeos/login/auth/fake_extended_authenticator.h
+++ b/chromeos/login/auth/fake_extended_authenticator.h
@@ -10,8 +10,6 @@
 #include "chromeos/login/auth/extended_authenticator.h"
 #include "chromeos/login/auth/user_context.h"
 
-class AccountId;
-
 namespace chromeos {
 
 class AuthFailure;
@@ -29,9 +27,6 @@
                            const ResultCallback& success_callback) override;
   void AuthenticateToCheck(const UserContext& context,
                            const base::Closure& success_callback) override;
-  void CreateMount(const AccountId& account_id,
-                   const std::vector<cryptohome::KeyDefinition>& keys,
-                   const ResultCallback& success_callback) override;
   void AddKey(const UserContext& context,
               const cryptohome::KeyDefinition& key,
               bool replace_existing,
diff --git a/chromeos/login/auth/login_performer.cc b/chromeos/login/auth/login_performer.cc
index 570a9b4d..31fe394 100644
--- a/chromeos/login/auth/login_performer.cc
+++ b/chromeos/login/auth/login_performer.cc
@@ -182,7 +182,10 @@
       gaia::ExtractDomainName(user_context.GetAccountId().GetUserEmail()));
 
   user_context_ = user_context;
-  user_context_.SetUserType(user_manager::USER_TYPE_SUPERVISED);
+  if (user_context_.GetUserType() != user_manager::USER_TYPE_SUPERVISED) {
+    LOG(FATAL) << "Incorrect supervised user type "
+               << user_context_.GetUserType();
+  }
 
   if (RunTrustedCheck(base::Bind(&LoginPerformer::TrustedLoginAsSupervisedUser,
                                  weak_factory_.GetWeakPtr(),
diff --git a/chromeos/login/auth/user_context.cc b/chromeos/login/auth/user_context.cc
index 8447f06..1e58b8c9 100644
--- a/chromeos/login/auth/user_context.cc
+++ b/chromeos/login/auth/user_context.cc
@@ -3,19 +3,35 @@
 // found in the LICENSE file.
 
 #include "chromeos/login/auth/user_context.h"
+#include "components/user_manager/user_manager.h"
 #include "components/user_manager/user_names.h"
 
 namespace chromeos {
 
+namespace {
+
+user_manager::UserType CalculateUserType(const AccountId& account_id) {
+  // UserManager is not initialized in unit tests.
+  if (!user_manager::UserManager::IsInitialized())
+    return user_manager::USER_TYPE_REGULAR;
+
+  if (user_manager::UserManager::Get()->IsSupervisedAccountId(account_id))
+    return user_manager::USER_TYPE_SUPERVISED;
+
+  if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY)
+    return user_manager::USER_TYPE_ACTIVE_DIRECTORY;
+
+  return user_manager::USER_TYPE_REGULAR;
+}
+
+}  // anonymous namespace
+
 UserContext::UserContext() : account_id_(EmptyAccountId()) {}
 
 UserContext::UserContext(const UserContext& other) = default;
 
 UserContext::UserContext(const AccountId& account_id)
-    : account_id_(account_id) {
-  account_id_.SetUserEmail(
-      user_manager::CanonicalizeUserID(account_id.GetUserEmail()));
-}
+    : UserContext(CalculateUserType(account_id), account_id) {}
 
 UserContext::UserContext(user_manager::UserType user_type,
                          const AccountId& account_id)
@@ -183,10 +199,6 @@
   auth_flow_ = auth_flow;
 }
 
-void UserContext::SetUserType(user_manager::UserType user_type) {
-  user_type_ = user_type;
-}
-
 void UserContext::SetPublicSessionLocale(const std::string& locale) {
   public_session_locale_ = locale;
 }
diff --git a/chromeos/login/auth/user_context.h b/chromeos/login/auth/user_context.h
index c279e975..26d1f7e 100644
--- a/chromeos/login/auth/user_context.h
+++ b/chromeos/login/auth/user_context.h
@@ -95,7 +95,6 @@
   void SetIsUsingPin(bool is_using_pin);
   void SetIsForcingDircrypto(bool is_forcing_dircrypto);
   void SetAuthFlow(AuthFlow auth_flow);
-  void SetUserType(user_manager::UserType user_type);
   void SetPublicSessionLocale(const std::string& locale);
   void SetPublicSessionInputMethod(const std::string& input_method);
   void SetDeviceId(const std::string& device_id);
diff --git a/components/assist_ranker/print_example_preprocessor_config.py b/components/assist_ranker/print_example_preprocessor_config.py
new file mode 100755
index 0000000..5e35a0f1
--- /dev/null
+++ b/components/assist_ranker/print_example_preprocessor_config.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python2
+
+# 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.
+
+"""Dumps info from a ExamplePreprocessorConfig protobuf file.
+
+Prints feature names, types, and bucket values.
+"""
+
+import os
+import sys
+import textwrap
+from enum import Enum
+from google.protobuf import text_format
+
+class FeatureType(Enum):
+  CATEGORICAL = 'categorical'
+  BUCKETED = 'bucketed'
+  SCALAR = 'scalar'
+
+
+def ReadConfig(pb_file):
+  """Parses the protobuf containing the example preprocessor config."""
+  import example_preprocessor_pb2
+  config = example_preprocessor_pb2.ExamplePreprocessorConfig()
+  with open(pb_file) as pb:
+    config.ParseFromString(pb.read())
+  return config
+
+
+def PrintExamplePreprocessorConfig(pb_file):
+  """Prints the features listed the example preprocessor config."""
+  config = ReadConfig(pb_file)
+
+  features = set()
+  for feature_index in sorted(config.feature_indices):
+    # For string or string list feature types, remove the "_value" suffix to get
+    # the base name.
+    name_parts = feature_index.split('_')
+    base_name = name_parts[0]
+    # Skip additional values of the same base name.
+    if base_name in features:
+      continue
+
+    features.add(base_name)
+    if len(name_parts) == 1:
+      feature_type = FeatureType.SCALAR
+    elif base_name in config.bucketizers:
+      feature_type = FeatureType.BUCKETED
+    else:
+      feature_type = FeatureType.CATEGORICAL
+    description = '* %s (%s)' % (base_name, feature_type.value)
+
+    if feature_type == FeatureType.BUCKETED:
+      description += ':\n\t'
+      boundaries = config.bucketizers[base_name].boundaries
+      bucket_str = ', '.join(['%.1f' % bucket for bucket in boundaries])
+
+      # Indent description by a tab and wrap text.
+      max_len = 80 - 8  # Leave at least 8 columns for tab width.
+      description += ('\n\t').join(textwrap.wrap(bucket_str, max_len))
+    print description
+  return 0
+
+
+def Main(args):
+  if len(args) != 2:
+    print 'Usage: %s <out_dir> <path/to/example_preprocessor_config.pb>' % (
+        __file__)
+    return 1
+
+  out_dir = args[0]
+  if not os.path.isdir(out_dir):
+    print 'Could not find out directory: %s' % out_dir
+    return 1
+
+  pb_file = args[1]
+  if not os.path.isfile(pb_file):
+    print 'Protobuf file not found: %s' % pb_file
+    return 1
+
+  proto_dir = os.path.join(out_dir, 'pyproto/components/assist_ranker/proto')
+  if not os.path.isdir(proto_dir):
+    print 'Proto directory not found: %s' % proto_dir
+    print 'Build the "components/assist_ranker/proto" target'
+    print '  (usually built with chrome)'
+    return 1
+
+  # Allow importing the ExamplePreprocessorConfig proto definition.
+  sys.path.insert(0, proto_dir)
+  PrintExamplePreprocessorConfig(pb_file)
+
+
+if __name__ == '__main__':
+  sys.exit(Main(sys.argv[1:]))
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 8bb028d..ebf5410 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1555,7 +1555,6 @@
     deps = [
       ":api_static_checks",
       ":copy_cronet_java8_jars",
-      ":cronet_maven_modules",
       ":cronet_package_copy",
       ":cronet_package_copy_native_lib",
       ":cronet_package_copy_native_lib_unstripped",
diff --git a/components/guest_view/browser/guest_view_manager_unittest.cc b/components/guest_view/browser/guest_view_manager_unittest.cc
index 654efcb..45ebeda 100644
--- a/components/guest_view/browser/guest_view_manager_unittest.cc
+++ b/components/guest_view/browser/guest_view_manager_unittest.cc
@@ -27,8 +27,7 @@
   ~GuestViewManagerTest() override {}
 
   std::unique_ptr<WebContents> CreateWebContents() {
-    return std::unique_ptr<WebContents>(
-        WebContentsTester::CreateTestWebContents(browser_context(), nullptr));
+    return WebContentsTester::CreateTestWebContents(browser_context(), nullptr);
   }
 
  private:
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index c431ec90..12cc9175 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -69,8 +69,6 @@
     "logger.h",
     "ntp_snippets_constants.cc",
     "ntp_snippets_constants.h",
-    "offline_pages/recent_tab_suggestions_provider.cc",
-    "offline_pages/recent_tab_suggestions_provider.h",
     "pref_names.cc",
     "pref_names.h",
     "pref_util.cc",
@@ -156,8 +154,6 @@
     "//components/metrics",
     "//components/ntp_snippets/remote/proto",
     "//components/offline_pages/core",
-    "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
-    "//components/offline_pages/core/recent_tabs",
     "//components/reading_list/core",
     "//components/sessions",
     "//components/strings",
@@ -216,7 +212,6 @@
     "contextual/contextual_suggestions_metrics_reporter_unittest.cc",
     "contextual/contextual_suggestions_ukm_entry_unittest.cc",
     "logger_unittest.cc",
-    "offline_pages/recent_tab_suggestions_provider_unittest.cc",
     "reading_list/reading_list_suggestions_provider_unittest.cc",
     "remote/cached_image_fetcher_unittest.cc",
     "remote/json_request_unittest.cc",
@@ -257,8 +252,6 @@
     "//components/offline_pages/core",
     "//components/offline_pages/core:test_support",
     "//components/offline_pages/core/background:test_support",
-    "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
-    "//components/offline_pages/core/recent_tabs",
     "//components/prefs:test_support",
     "//components/reading_list/core",
     "//components/sessions",
diff --git a/components/ntp_snippets/category.h b/components/ntp_snippets/category.h
index 506d51f..d421049 100644
--- a/components/ntp_snippets/category.h
+++ b/components/ntp_snippets/category.h
@@ -20,7 +20,7 @@
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
 enum class KnownCategories {
   // Pages recently downloaded during normal navigation.
-  RECENT_TABS,
+  RECENT_TABS_DEPRECATED,
 
   // Pages downloaded by the user for offline consumption.
   DOWNLOADS,
diff --git a/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc b/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
index c8e8843..bdc779d1 100644
--- a/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
+++ b/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
@@ -609,9 +609,6 @@
   // Make sure we have the default order.
   EXPECT_TRUE(CompareCategories(
       Category::FromKnownCategory(KnownCategories::DOWNLOADS),
-      Category::FromKnownCategory(KnownCategories::RECENT_TABS)));
-  EXPECT_TRUE(CompareCategories(
-      Category::FromKnownCategory(KnownCategories::RECENT_TABS),
       Category::FromKnownCategory(KnownCategories::FOREIGN_TABS)));
   EXPECT_TRUE(CompareCategories(
       Category::FromKnownCategory(KnownCategories::FOREIGN_TABS),
@@ -642,22 +639,22 @@
        ShouldResumePromotionAfter2WeeksSinceDismissal) {
   const Category downloads =
       Category::FromKnownCategory(KnownCategories::DOWNLOADS);
-  const Category recent_tabs =
-      Category::FromKnownCategory(KnownCategories::RECENT_TABS);
-  ASSERT_TRUE(CompareCategories(downloads, recent_tabs));
+  const Category foreign_tabs =
+      Category::FromKnownCategory(KnownCategories::FOREIGN_TABS);
+  ASSERT_TRUE(CompareCategories(downloads, foreign_tabs));
 
-  SetPromotedCategoryVariationParam(recent_tabs.id());
+  SetPromotedCategoryVariationParam(foreign_tabs.id());
   ResetRanker(base::DefaultClock::GetInstance());
-  ASSERT_TRUE(CompareCategories(recent_tabs, downloads));
+  ASSERT_TRUE(CompareCategories(foreign_tabs, downloads));
 
-  ranker()->OnCategoryDismissed(recent_tabs);
-  ASSERT_FALSE(CompareCategories(recent_tabs, downloads));
+  ranker()->OnCategoryDismissed(foreign_tabs);
+  ASSERT_FALSE(CompareCategories(foreign_tabs, downloads));
 
   // Simulate a little over 2 weeks of time passing.
   base::SimpleTestClock test_clock;
   test_clock.SetNow(base::Time::Now() + base::TimeDelta::FromDays(15));
   ResetRanker(&test_clock);
-  EXPECT_TRUE(CompareCategories(recent_tabs, downloads));
+  EXPECT_TRUE(CompareCategories(foreign_tabs, downloads));
 }
 
 TEST_F(ClickBasedCategoryRankerTest,
diff --git a/components/ntp_snippets/category_rankers/constant_category_ranker.cc b/components/ntp_snippets/category_rankers/constant_category_ranker.cc
index 40c7e1e4b..00a6ae3 100644
--- a/components/ntp_snippets/category_rankers/constant_category_ranker.cc
+++ b/components/ntp_snippets/category_rankers/constant_category_ranker.cc
@@ -124,7 +124,6 @@
     case CategoryOrderChoice::GENERAL:
       categories.push_back(KnownCategories::READING_LIST);
       categories.push_back(KnownCategories::DOWNLOADS);
-      categories.push_back(KnownCategories::RECENT_TABS);
       categories.push_back(KnownCategories::FOREIGN_TABS);
       categories.push_back(KnownCategories::BOOKMARKS);
       categories.push_back(KnownCategories::ARTICLES);
@@ -135,7 +134,6 @@
       categories.push_back(KnownCategories::DOWNLOADS);
       categories.push_back(KnownCategories::BOOKMARKS);
 
-      categories.push_back(KnownCategories::RECENT_TABS);
       categories.push_back(KnownCategories::FOREIGN_TABS);
       break;
   }
diff --git a/components/ntp_snippets/content_suggestion.cc b/components/ntp_snippets/content_suggestion.cc
index c3919f7c..5dd75b9 100644
--- a/components/ntp_snippets/content_suggestion.cc
+++ b/components/ntp_snippets/content_suggestion.cc
@@ -57,12 +57,6 @@
   download_suggestion_extra_ = std::move(download_suggestion_extra);
 }
 
-void ContentSuggestion::set_recent_tab_suggestion_extra(
-    std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra) {
-  DCHECK(id_.category().IsKnownCategory(KnownCategories::RECENT_TABS));
-  recent_tab_suggestion_extra_ = std::move(recent_tab_suggestion_extra);
-}
-
 void ContentSuggestion::set_reading_list_suggestion_extra(
     std::unique_ptr<ReadingListSuggestionExtra> reading_list_suggestion_extra) {
   DCHECK(id_.category().IsKnownCategory(KnownCategories::READING_LIST));
diff --git a/components/ntp_snippets/content_suggestion.h b/components/ntp_snippets/content_suggestion.h
index b6cf3f4..0dca371 100644
--- a/components/ntp_snippets/content_suggestion.h
+++ b/components/ntp_snippets/content_suggestion.h
@@ -40,14 +40,6 @@
   bool is_download_asset = false;
 };
 
-// Contains additional data which is only available for recent tab suggestions.
-struct RecentTabSuggestionExtra {
-  // Corresponding tab identifier.
-  int tab_id;
-  // Underlying offline page identifier.
-  int64_t offline_page_id = 0;
-};
-
 // ReadingListSuggestionExtra contains additional data which is only available
 // for Reading List suggestions.
 struct ReadingListSuggestionExtra {
@@ -163,14 +155,6 @@
   void set_download_suggestion_extra(
       std::unique_ptr<DownloadSuggestionExtra> download_suggestion_extra);
 
-  // Extra information for recent tab suggestions. Only available for
-  // KnownCategories::RECENT_TABS suggestions.
-  RecentTabSuggestionExtra* recent_tab_suggestion_extra() const {
-    return recent_tab_suggestion_extra_.get();
-  }
-  void set_recent_tab_suggestion_extra(
-      std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra);
-
   // Extra information for reading list suggestions. Only available for
   // KnownCategories::READING_LIST suggestions.
   ReadingListSuggestionExtra* reading_list_suggestion_extra() const {
@@ -213,7 +197,6 @@
   base::string16 publisher_name_;
   float score_;
   std::unique_ptr<DownloadSuggestionExtra> download_suggestion_extra_;
-  std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra_;
   std::unique_ptr<ReadingListSuggestionExtra> reading_list_suggestion_extra_;
   std::unique_ptr<NotificationExtra> notification_extra_;
 
diff --git a/components/ntp_snippets/content_suggestions_metrics.cc b/components/ntp_snippets/content_suggestions_metrics.cc
index 6c0fe3d5..2b7e3ca 100644
--- a/components/ntp_snippets/content_suggestions_metrics.cc
+++ b/components/ntp_snippets/content_suggestions_metrics.cc
@@ -81,7 +81,7 @@
 // sync with ContentSuggestionsCategory in histograms.xml.
 enum class HistogramCategories {
   EXPERIMENTAL,
-  RECENT_TABS,
+  RECENT_TABS_DEPRECATED,
   DOWNLOADS,
   BOOKMARKS,
   PHYSICAL_WEB_PAGES_DEPRECATED,
@@ -104,8 +104,6 @@
   // listed here.
   auto known_category = static_cast<KnownCategories>(category.id());
   switch (known_category) {
-    case KnownCategories::RECENT_TABS:
-      return HistogramCategories::RECENT_TABS;
     case KnownCategories::DOWNLOADS:
       return HistogramCategories::DOWNLOADS;
     case KnownCategories::BOOKMARKS:
@@ -118,6 +116,7 @@
       return HistogramCategories::READING_LIST;
     case KnownCategories::CONTEXTUAL:
       return HistogramCategories::CONTEXTUAL;
+    case KnownCategories::RECENT_TABS_DEPRECATED:
     case KnownCategories::PHYSICAL_WEB_PAGES_DEPRECATED:
     case KnownCategories::LOCAL_CATEGORIES_COUNT:
     case KnownCategories::REMOTE_CATEGORIES_OFFSET:
@@ -133,8 +132,6 @@
 std::string GetCategorySuffix(Category category) {
   HistogramCategories histogram_category = GetHistogramCategory(category);
   switch (histogram_category) {
-    case HistogramCategories::RECENT_TABS:
-      return "RecentTabs";
     case HistogramCategories::DOWNLOADS:
       return "Downloads";
     case HistogramCategories::BOOKMARKS:
@@ -149,6 +146,7 @@
       return "ReadingList";
     case HistogramCategories::CONTEXTUAL:
       return "Contextual";
+    case HistogramCategories::RECENT_TABS_DEPRECATED:
     case HistogramCategories::PHYSICAL_WEB_PAGES_DEPRECATED:
     case HistogramCategories::COUNT:
       NOTREACHED();
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
index 2fd237d2..5c3942e 100644
--- a/components/ntp_snippets/features.cc
+++ b/components/ntp_snippets/features.cc
@@ -32,7 +32,6 @@
     &kKeepPrefetchedContentSuggestions,
     &kNotificationsFeature,
     &kPublisherFaviconsFromNewServerFeature,
-    &kRecentOfflineTabSuggestionsFeature,
     &kRemoteSuggestionsBackendFeature,
     nullptr};
 
@@ -45,9 +44,6 @@
 const base::Feature kBookmarkSuggestionsFeature{
     "NTPBookmarkSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kRecentOfflineTabSuggestionsFeature{
-    "NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kIncreasedVisibility{"NTPSnippetsIncreasedVisibility",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h
index b2dda46..8b4ac0e 100644
--- a/components/ntp_snippets/features.h
+++ b/components/ntp_snippets/features.h
@@ -33,7 +33,6 @@
 // helpers in chrome/browser/ntp_snippets/dependent_features.h instead.
 
 extern const base::Feature kBookmarkSuggestionsFeature;
-extern const base::Feature kRecentOfflineTabSuggestionsFeature;
 extern const base::Feature kForeignSessionsSuggestionsFeature;
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
deleted file mode 100644
index 8c64425f..0000000
--- a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
+++ /dev/null
@@ -1,329 +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 "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/ntp_snippets/features.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/ntp_snippets/pref_util.h"
-#include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/variations/variations_associated_data.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/image/image.h"
-
-using offline_pages::ClientId;
-using offline_pages::DownloadUIAdapter;
-
-namespace ntp_snippets {
-
-namespace {
-
-const int kDefaultMaxSuggestionsCount = 5;
-
-const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count";
-
-int GetMaxSuggestionsCount() {
-  return variations::GetVariationParamByFeatureAsInt(
-      kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName,
-      kDefaultMaxSuggestionsCount);
-}
-
-struct OrderUIItemsByMostRecentlyCreatedFirst {
-  bool operator()(const OfflineItem& left, const OfflineItem& right) const {
-    return left.creation_time > right.creation_time;
-  }
-};
-
-struct OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst {
-  bool operator()(const OfflineItem& left, const OfflineItem& right) const {
-    if (left.page_url != right.page_url) {
-      return left.page_url < right.page_url;
-    }
-    return left.creation_time > right.creation_time;
-  }
-};
-
-}  // namespace
-
-RecentTabSuggestionsProvider::RecentTabSuggestionsProvider(
-    ContentSuggestionsProvider::Observer* observer,
-    offline_pages::DownloadUIAdapter* ui_adapter,
-    PrefService* pref_service)
-    : ContentSuggestionsProvider(observer),
-      category_status_(CategoryStatus::AVAILABLE_LOADING),
-      provided_category_(
-          Category::FromKnownCategory(KnownCategories::RECENT_TABS)),
-      recent_tabs_ui_adapter_(ui_adapter),
-      pref_service_(pref_service),
-      weak_ptr_factory_(this) {
-  observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
-  recent_tabs_ui_adapter_->AddObserver(this);
-}
-
-RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() {
-  recent_tabs_ui_adapter_->RemoveObserver(this);
-}
-
-CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus(
-    Category category) {
-  if (category == provided_category_) {
-    return category_status_;
-  }
-  NOTREACHED() << "Unknown category " << category.id();
-  return CategoryStatus::NOT_PROVIDED;
-}
-
-CategoryInfo RecentTabSuggestionsProvider::GetCategoryInfo(Category category) {
-  DCHECK_EQ(provided_category_, category);
-  return CategoryInfo(
-      l10n_util::GetStringUTF16(IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER),
-      ContentSuggestionsCardLayout::MINIMAL_CARD,
-      ContentSuggestionsAdditionalAction::NONE,
-      /*show_if_empty=*/false,
-      l10n_util::GetStringUTF16(IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_EMPTY));
-}
-
-void RecentTabSuggestionsProvider::DismissSuggestion(
-    const ContentSuggestion::ID& suggestion_id) {
-  DCHECK_EQ(provided_category_, suggestion_id.category());
-  std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
-  dismissed_ids.insert(suggestion_id.id_within_category());
-  StoreDismissedIDsToPrefs(dismissed_ids);
-}
-
-void RecentTabSuggestionsProvider::FetchSuggestionImage(
-    const ContentSuggestion::ID& suggestion_id,
-    ImageFetchedCallback callback) {
-  // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it's
-  // available there.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
-}
-
-void RecentTabSuggestionsProvider::FetchSuggestionImageData(
-    const ContentSuggestion::ID& suggestion_id,
-    ImageDataFetchedCallback callback) {
-  // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it's
-  // available there.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), std::string()));
-}
-
-void RecentTabSuggestionsProvider::Fetch(
-    const Category& category,
-    const std::set<std::string>& known_suggestion_ids,
-    FetchDoneCallback callback) {
-  LOG(DFATAL) << "RecentTabSuggestionsProvider has no |Fetch| functionality!";
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          std::move(callback),
-          Status(StatusCode::PERMANENT_ERROR,
-                 "RecentTabSuggestionsProvider has no |Fetch| functionality!"),
-          std::vector<ContentSuggestion>()));
-}
-
-void RecentTabSuggestionsProvider::ClearHistory(
-    base::Time begin,
-    base::Time end,
-    const base::Callback<bool(const GURL& url)>& filter) {
-  ClearDismissedSuggestionsForDebugging(provided_category_);
-  FetchRecentTabs();
-}
-
-void RecentTabSuggestionsProvider::ClearCachedSuggestions() {
-  // Ignored.
-}
-
-void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging(
-    Category category,
-    DismissedSuggestionsCallback callback) {
-  DCHECK_EQ(provided_category_, category);
-  recent_tabs_ui_adapter_->GetAllItems(base::BindOnce(
-      &RecentTabSuggestionsProvider::OnGetDismissedSuggestionsForDebuggingDone,
-      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void RecentTabSuggestionsProvider::OnGetDismissedSuggestionsForDebuggingDone(
-    DismissedSuggestionsCallback callback,
-    const std::vector<OfflineItem>& offline_items) {
-  std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
-  std::vector<ContentSuggestion> suggestions;
-  for (const OfflineItem& item : offline_items) {
-    int64_t offline_page_id =
-        recent_tabs_ui_adapter_->GetOfflineIdByGuid(item.id.id);
-    if (!dismissed_ids.count(base::IntToString(offline_page_id))) {
-      continue;
-    }
-
-    suggestions.push_back(ConvertUIItem(item));
-  }
-
-  std::move(callback).Run(std::move(suggestions));
-}
-
-void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
-    Category category) {
-  DCHECK_EQ(provided_category_, category);
-  StoreDismissedIDsToPrefs(std::set<std::string>());
-  FetchRecentTabs();
-}
-
-// static
-void RecentTabSuggestionsProvider::RegisterProfilePrefs(
-    PrefRegistrySimple* registry) {
-  registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private methods
-
-void RecentTabSuggestionsProvider::OnItemsAdded(
-    const std::vector<OfflineItem>& items) {
-  FetchRecentTabs();
-}
-
-void RecentTabSuggestionsProvider::OnItemUpdated(const OfflineItem& item) {
-  FetchRecentTabs();
-}
-
-void RecentTabSuggestionsProvider::OnItemRemoved(const ContentId& id) {
-  // Because we never switch to NOT_PROVIDED dynamically, there can be no open
-  // UI containing an invalidated suggestion unless the status is something
-  // other than NOT_PROVIDED, so only notify invalidation in that case.
-  if (category_status_ != CategoryStatus::NOT_PROVIDED) {
-    InvalidateSuggestion(id.id);
-  }
-}
-
-void RecentTabSuggestionsProvider::FetchRecentTabs() {
-  recent_tabs_ui_adapter_->GetAllItems(
-      base::BindOnce(&RecentTabSuggestionsProvider::OnFetchRecentTabsDone,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void RecentTabSuggestionsProvider::OnFetchRecentTabsDone(
-    const std::vector<OfflineItem>& offline_items) {
-  NotifyStatusChanged(CategoryStatus::AVAILABLE);
-  std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs();
-  std::set<std::string> new_dismissed_ids;
-  std::vector<OfflineItem> non_dismissed_items;
-
-  for (const OfflineItem& item : offline_items) {
-    std::string offline_page_id = base::IntToString(
-        recent_tabs_ui_adapter_->GetOfflineIdByGuid(item.id.id));
-    if (old_dismissed_ids.count(offline_page_id)) {
-      new_dismissed_ids.insert(offline_page_id);
-    } else {
-      non_dismissed_items.push_back(item);
-    }
-  }
-
-  observer()->OnNewSuggestions(
-      this, provided_category_,
-      GetMostRecentlyCreatedWithoutDuplicates(non_dismissed_items));
-  if (new_dismissed_ids.size() != old_dismissed_ids.size()) {
-    StoreDismissedIDsToPrefs(new_dismissed_ids);
-  }
-}
-
-void RecentTabSuggestionsProvider::NotifyStatusChanged(
-    CategoryStatus new_status) {
-  DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_);
-  if (category_status_ == new_status) {
-    return;
-  }
-  category_status_ = new_status;
-  observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
-}
-
-ContentSuggestion RecentTabSuggestionsProvider::ConvertUIItem(
-    const OfflineItem& ui_item) const {
-  // UI items have the Tab ID embedded in the GUID and the offline ID is
-  // available by querying.
-  int64_t offline_page_id =
-      recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item.id.id);
-  ContentSuggestion suggestion(
-      provided_category_, base::IntToString(offline_page_id), ui_item.page_url);
-  suggestion.set_title(base::UTF8ToUTF16(ui_item.title));
-  suggestion.set_publish_date(ui_item.creation_time);
-  suggestion.set_publisher_name(base::UTF8ToUTF16(ui_item.page_url.host()));
-  auto extra = std::make_unique<RecentTabSuggestionExtra>();
-  int tab_id;
-  bool success = base::StringToInt(ui_item.id.id, &tab_id);
-  DCHECK(success);
-  extra->tab_id = tab_id;
-  extra->offline_page_id = offline_page_id;
-  suggestion.set_recent_tab_suggestion_extra(std::move(extra));
-
-  return suggestion;
-}
-
-std::vector<ContentSuggestion>
-RecentTabSuggestionsProvider::GetMostRecentlyCreatedWithoutDuplicates(
-    std::vector<OfflineItem>& ui_items) const {
-  // |std::unique| only removes duplicates that immediately follow each other.
-  // Thus, first, we have to sort by URL and creation time and only then remove
-  // duplicates and sort the remaining items by creation time.
-  std::sort(ui_items.begin(), ui_items.end(),
-            OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst());
-  std::vector<OfflineItem>::iterator new_end =
-      std::unique(ui_items.begin(), ui_items.end(),
-                  [](const OfflineItem& left, const OfflineItem& right) {
-                    return left.page_url == right.page_url;
-                  });
-  ui_items.erase(new_end, ui_items.end());
-  std::sort(ui_items.begin(), ui_items.end(),
-            OrderUIItemsByMostRecentlyCreatedFirst());
-  std::vector<ContentSuggestion> suggestions;
-  for (const OfflineItem& ui_item : ui_items) {
-    suggestions.push_back(ConvertUIItem(ui_item));
-    if (static_cast<int>(suggestions.size()) == GetMaxSuggestionsCount()) {
-      break;
-    }
-  }
-  return suggestions;
-}
-
-void RecentTabSuggestionsProvider::InvalidateSuggestion(
-    const std::string& ui_item_guid) {
-  std::string offline_page_id = base::IntToString(
-      recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item_guid));
-  observer()->OnSuggestionInvalidated(
-      this, ContentSuggestion::ID(provided_category_, offline_page_id));
-
-  std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
-  auto it = dismissed_ids.find(offline_page_id);
-  if (it != dismissed_ids.end()) {
-    dismissed_ids.erase(it);
-    StoreDismissedIDsToPrefs(dismissed_ids);
-  }
-}
-
-std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs()
-    const {
-  return prefs::ReadDismissedIDsFromPrefs(
-      *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions);
-}
-
-void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs(
-    const std::set<std::string>& dismissed_ids) {
-  prefs::StoreDismissedIDsToPrefs(pref_service_,
-                                  prefs::kDismissedRecentOfflineTabSuggestions,
-                                  dismissed_ids);
-}
-
-}  // namespace ntp_snippets
diff --git a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
deleted file mode 100644
index 2c8c11e..0000000
--- a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
-#define COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/category_status.h"
-#include "components/ntp_snippets/content_suggestion.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/offline_page_model.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-using ContentId = offline_items_collection::ContentId;
-using OfflineItem = offline_items_collection::OfflineItem;
-using OfflineContentProvider = offline_items_collection::OfflineContentProvider;
-
-namespace ntp_snippets {
-
-// Provides recent tabs content suggestions from the offline pages model.
-class RecentTabSuggestionsProvider : public ContentSuggestionsProvider,
-                                     public OfflineContentProvider::Observer {
- public:
-  RecentTabSuggestionsProvider(ContentSuggestionsProvider::Observer* observer,
-                               offline_pages::DownloadUIAdapter* ui_adapter,
-                               PrefService* pref_service);
-  ~RecentTabSuggestionsProvider() override;
-
-  // ContentSuggestionsProvider implementation.
-  CategoryStatus GetCategoryStatus(Category category) override;
-  CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
-  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
-                            ImageFetchedCallback callback) override;
-  void FetchSuggestionImageData(const ContentSuggestion::ID& suggestion_id,
-                                ImageDataFetchedCallback callback) override;
-  void Fetch(const Category& category,
-             const std::set<std::string>& known_suggestion_ids,
-             FetchDoneCallback callback) override;
-  void ClearHistory(
-      base::Time begin,
-      base::Time end,
-      const base::Callback<bool(const GURL& url)>& filter) override;
-  void ClearCachedSuggestions() override;
-  void GetDismissedSuggestionsForDebugging(
-      Category category,
-      DismissedSuggestionsCallback callback) override;
-  void ClearDismissedSuggestionsForDebugging(Category category) override;
-
-  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- private:
-  friend class RecentTabSuggestionsProviderTestNoLoad;
-
-  // OfflineContentProvider::Observer implementation.
-  void OnItemsAdded(const std::vector<OfflineItem>& items) override;
-  void OnItemRemoved(const ContentId& id) override;
-  void OnItemUpdated(const OfflineItem& item) override;
-
-  // Updates the |category_status_| of the |provided_category_| and notifies the
-  // |observer_|, if necessary.
-  void NotifyStatusChanged(CategoryStatus new_status);
-
-  // Manually requests all Recent Tabs UI items and updates the suggestions.
-  void FetchRecentTabs();
-  void OnFetchRecentTabsDone(const std::vector<OfflineItem>& offline_items);
-
-  void OnGetDismissedSuggestionsForDebuggingDone(
-      DismissedSuggestionsCallback callback,
-      const std::vector<OfflineItem>& offline_items);
-
-  // Converts an OfflineItem to a ContentSuggestion for the
-  // |provided_category_|.
-  ContentSuggestion ConvertUIItem(const OfflineItem& ui_item) const;
-
-  // Removes duplicates for the same URL leaving only the most recently created
-  // items, returns at most |GetMaxSuggestionsCount()| ContentSuggestions
-  // corresponding to the remaining items, sorted by creation time (newer
-  // first).
-  std::vector<ContentSuggestion> GetMostRecentlyCreatedWithoutDuplicates(
-      std::vector<OfflineItem>& ui_items) const;
-
-  // Fires the |OnSuggestionInvalidated| event for the suggestion corresponding
-  // to the given |offline_id| and deletes it from the dismissed IDs list, if
-  // necessary.
-  void InvalidateSuggestion(const std::string& ui_item_guid);
-
-  // Reads dismissed IDs from Prefs.
-  std::set<std::string> ReadDismissedIDsFromPrefs() const;
-
-  // Writes |dismissed_ids| into Prefs.
-  void StoreDismissedIDsToPrefs(const std::set<std::string>& dismissed_ids);
-
-  CategoryStatus category_status_;
-  const Category provided_category_;
-  offline_pages::DownloadUIAdapter* recent_tabs_ui_adapter_;
-
-  PrefService* pref_service_;
-
-  base::WeakPtrFactory<RecentTabSuggestionsProvider> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProvider);
-};
-
-}  // namespace ntp_snippets
-
-#endif  // COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
diff --git a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc b/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
deleted file mode 100644
index 504a61f..0000000
--- a/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
+++ /dev/null
@@ -1,464 +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 "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
-#include "components/ntp_snippets/offline_pages/offline_pages_test_utils.h"
-#include "components/offline_pages/core/background/request_coordinator_stub_taco.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/offline_page_item.h"
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ntp_snippets::test::CaptureDismissedSuggestions;
-using ntp_snippets::test::FakeOfflinePageModel;
-using offline_pages::ClientId;
-using offline_pages::MultipleOfflinePageItemCallback;
-using offline_pages::OfflinePageItem;
-using testing::_;
-using testing::IsEmpty;
-using testing::Mock;
-using testing::Property;
-using testing::SizeIs;
-
-namespace ntp_snippets {
-
-namespace {
-
-const int64_t kSystemDownloadId = 0;
-
-OfflinePageItem CreateDummyRecentTab(int offline_id) {
-  // This is used to assign unique tab IDs to pages.  Since offline IDs are
-  // typically small integers like 1, 2, 3 etc, we start at 1001 to ensure that
-  // they are different, and can catch bugs where offline page ID is used in
-  // place of tab ID and vice versa.
-  std::string tab_id = base::IntToString(offline_id + 1000);
-  ClientId client_id(offline_pages::kLastNNamespace, tab_id);
-  return test::CreateDummyOfflinePageItem(offline_id, client_id);
-}
-
-std::vector<OfflinePageItem> CreateDummyRecentTabs(
-    const std::vector<int>& ids) {
-  std::vector<OfflinePageItem> result;
-  for (int id : ids) {
-    result.push_back(CreateDummyRecentTab(id));
-  }
-  return result;
-}
-
-OfflinePageItem CreateDummyRecentTab(int id, base::Time time) {
-  OfflinePageItem item = CreateDummyRecentTab(id);
-  item.creation_time = time;
-  item.last_access_time = time;
-  return item;
-}
-
-void GetAllItemsDummyCallback(const std::vector<OfflineItem>& items) {}
-
-}  // namespace
-
-class RecentTabSuggestionsProviderTestNoLoad : public testing::Test {
- public:
-  RecentTabSuggestionsProviderTestNoLoad()
-      : task_runner_(new base::TestSimpleTaskRunner()),
-        task_runner_handle_(task_runner_),
-        pref_service_(new TestingPrefServiceSimple()) {
-    RecentTabSuggestionsProvider::RegisterProfilePrefs(
-        pref_service()->registry());
-
-    taco_ = std::make_unique<offline_pages::RequestCoordinatorStubTaco>();
-    taco_->CreateRequestCoordinator();
-
-    ui_adapter_ = offline_pages::RecentTabsUIAdapterDelegate::
-        GetOrCreateRecentTabsUIAdapter(&model_, taco_->request_coordinator());
-    delegate_ =
-        offline_pages::RecentTabsUIAdapterDelegate::FromDownloadUIAdapter(
-            ui_adapter_);
-    provider_ = std::make_unique<RecentTabSuggestionsProvider>(
-        &observer_, ui_adapter_, pref_service());
-    // Force adapter to load its cache.
-    ui_adapter_->GetAllItems(base::BindOnce(&GetAllItemsDummyCallback));
-    provider_->FetchRecentTabs();
-  }
-
-  Category recent_tabs_category() {
-    return Category::FromKnownCategory(KnownCategories::RECENT_TABS);
-  }
-
-  ContentSuggestion::ID GetDummySuggestionId(int id) {
-    return ContentSuggestion::ID(recent_tabs_category(), base::IntToString(id));
-  }
-
-  void AddTabAndOfflinePageToModel(const OfflinePageItem& item) {
-    AddTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
-        item.client_id));
-    AddOfflinePageToModel(item);
-  }
-
-  void AddTab(int tab_id) { delegate_->RegisterTab(tab_id); }
-
-  void RemoveTab(int tab_id) { delegate_->UnregisterTab(tab_id); }
-
-  void AddOfflinePageToModel(const OfflinePageItem& item) {
-    ui_adapter_->OfflinePageAdded(&model_, item);
-  }
-
-  void FireOfflinePageDeleted(const OfflinePageItem& item) {
-    int tab_id = offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
-        item.client_id);
-    RemoveTab(tab_id);
-    ui_adapter_->OfflinePageDeleted(
-        offline_pages::OfflinePageModel::DeletedPageInfo(
-            item.offline_id, kSystemDownloadId, item.client_id,
-            "" /* request_origin */));
-  }
-
-  std::set<std::string> ReadDismissedIDsFromPrefs() {
-    return provider_->ReadDismissedIDsFromPrefs();
-  }
-
-  RecentTabSuggestionsProvider* provider() { return provider_.get(); }
-  MockContentSuggestionsProviderObserver* observer() { return &observer_; }
-  TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
-  base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
-
- private:
-  FakeOfflinePageModel model_;
-  offline_pages::DownloadUIAdapter* ui_adapter_;
-  offline_pages::RecentTabsUIAdapterDelegate* delegate_;
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle task_runner_handle_;
-  std::unique_ptr<offline_pages::RequestCoordinatorStubTaco> taco_;
-  MockContentSuggestionsProviderObserver observer_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  // Last so that the dependencies are deleted after the provider.
-  std::unique_ptr<RecentTabSuggestionsProvider> provider_;
-
-  DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTestNoLoad);
-};
-
-// Test that always loads the model before the start of the test.
-class RecentTabSuggestionsProviderTest
-    : public RecentTabSuggestionsProviderTestNoLoad {
- public:
-  RecentTabSuggestionsProviderTest() = default;
-
-  void SetUp() override {
-    // The UI adapter always fires asynchronously upon loading, so we want to
-    // run past that moment before each test.  Expect a call to hide warnings.
-    EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(1);
-    task_runner()->RunUntilIdle();
-    Mock::VerifyAndClearExpectations(observer());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTest);
-};
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) {
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(2);
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          UnorderedElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/2")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/3")))));
-
-  auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3});
-  for (OfflinePageItem& recent_tab : recent_tabs_list) {
-    AddTabAndOfflinePageToModel(recent_tab);
-  }
-  task_runner()->RunUntilIdle();
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) {
-  base::Time now = base::Time::Now();
-  base::Time yesterday = now - base::TimeDelta::FromDays(1);
-  base::Time tomorrow = now + base::TimeDelta::FromDays(1);
-
-  std::vector<OfflinePageItem> offline_pages = {
-      CreateDummyRecentTab(1, now), CreateDummyRecentTab(2, yesterday),
-      CreateDummyRecentTab(3, tomorrow)};
-
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(_, recent_tabs_category(),
-                       ElementsAre(Property(&ContentSuggestion::url,
-                                            GURL("http://dummy.com/1")))));
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(1, now));
-  task_runner()->RunUntilIdle();
-
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          ElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(2, yesterday));
-  task_runner()->RunUntilIdle();
-
-  offline_pages[1].last_access_time =
-      offline_pages[0].last_access_time + base::TimeDelta::FromHours(1);
-
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          ElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/3")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(3, tomorrow));
-  task_runner()->RunUntilIdle();
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) {
-  EXPECT_EQ(
-      ContentSuggestionsAdditionalAction::NONE,
-      provider()->GetCategoryInfo(recent_tabs_category()).additional_action());
-}
-
-// TODO(vitaliii): Break this test into multiple tests. Currently if it fails,
-// it takes long time to find which part of it actually fails.
-TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) {
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
-  auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3});
-  for (OfflinePageItem& recent_tab : recent_tabs_list) {
-    AddTabAndOfflinePageToModel(recent_tab);
-  }
-  task_runner()->RunUntilIdle();
-
-  // Dismiss 2 and 3.
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
-  provider()->DismissSuggestion(GetDummySuggestionId(2));
-  provider()->DismissSuggestion(GetDummySuggestionId(3));
-  Mock::VerifyAndClearExpectations(observer());
-
-  // They should disappear from the reported suggestions.
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          UnorderedElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/4")))));
-
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(4));
-  task_runner()->RunUntilIdle();
-  Mock::VerifyAndClearExpectations(observer());
-
-  // And appear in the dismissed suggestions.
-  std::vector<ContentSuggestion> dismissed_suggestions;
-  provider()->GetDismissedSuggestionsForDebugging(
-      recent_tabs_category(),
-      base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
-  task_runner()->RunUntilIdle();
-  EXPECT_THAT(
-      dismissed_suggestions,
-      UnorderedElementsAre(
-          Property(&ContentSuggestion::url, GURL("http://dummy.com/2")),
-          Property(&ContentSuggestion::url, GURL("http://dummy.com/3"))));
-
-  // Clear dismissed suggestions.
-  provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category());
-  task_runner()->RunUntilIdle();
-
-  // They should be gone from the dismissed suggestions.
-  dismissed_suggestions.clear();
-  provider()->GetDismissedSuggestionsForDebugging(
-      recent_tabs_category(),
-      base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
-  task_runner()->RunUntilIdle();
-  EXPECT_THAT(dismissed_suggestions, IsEmpty());
-
-  // And appear in the reported suggestions for the category again.
-  EXPECT_CALL(*observer(),
-              OnNewSuggestions(_, recent_tabs_category(), SizeIs(5)));
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(5));
-  task_runner()->RunUntilIdle();
-  Mock::VerifyAndClearExpectations(observer());
-}
-
-TEST_F(RecentTabSuggestionsProviderTest,
-       ShouldInvalidateWhenOfflinePageDeleted) {
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
-  std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
-  for (OfflinePageItem& recent_tab : offline_pages)
-    AddTabAndOfflinePageToModel(recent_tab);
-  task_runner()->RunUntilIdle();
-
-  // Invalidation of suggestion 2 should be forwarded.
-  EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(2)));
-  FireOfflinePageDeleted(offline_pages[1]);
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) {
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
-  std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
-  for (OfflinePageItem& recent_tab : offline_pages)
-    AddTabAndOfflinePageToModel(recent_tab);
-  task_runner()->RunUntilIdle();
-  EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
-
-  provider()->DismissSuggestion(GetDummySuggestionId(2));
-  EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1));
-
-  FireOfflinePageDeleted(offline_pages[1]);
-  EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnFetch) {
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
-  std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
-  for (OfflinePageItem& recent_tab : offline_pages)
-    AddTabAndOfflinePageToModel(recent_tab);
-  task_runner()->RunUntilIdle();
-
-  provider()->DismissSuggestion(GetDummySuggestionId(2));
-  provider()->DismissSuggestion(GetDummySuggestionId(3));
-  EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(2));
-
-  FireOfflinePageDeleted(offline_pages[0]);
-  FireOfflinePageDeleted(offline_pages[2]);
-  EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1));
-
-  FireOfflinePageDeleted(offline_pages[1]);
-  EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowSameUrlMutlipleTimes) {
-  base::Time now = base::Time::Now();
-  base::Time yesterday = now - base::TimeDelta::FromDays(1);
-  base::Time tomorrow = now + base::TimeDelta::FromDays(1);
-  std::vector<OfflinePageItem> offline_pages = {
-      CreateDummyRecentTab(1, yesterday), CreateDummyRecentTab(2, now),
-      CreateDummyRecentTab(3, tomorrow)};
-
-  // We leave IDs different, but make the URLs the same.
-  offline_pages[2].url = offline_pages[0].url;
-
-  AddTabAndOfflinePageToModel(offline_pages[0]);
-  AddTabAndOfflinePageToModel(offline_pages[1]);
-  task_runner()->RunUntilIdle();
-  Mock::VerifyAndClearExpectations(observer());
-  EXPECT_CALL(*observer(),
-              OnNewSuggestions(
-                  _, recent_tabs_category(),
-                  UnorderedElementsAre(
-                      Property(&ContentSuggestion::publish_date, now),
-                      Property(&ContentSuggestion::publish_date, tomorrow))));
-
-  AddTabAndOfflinePageToModel(offline_pages[2]);
-  task_runner()->RunUntilIdle();
-}
-
-TEST_F(RecentTabSuggestionsProviderTest,
-       ShouldNotFetchIfAddedOfflinePageIsNotRecentTab) {
-  // It should not fetch when not a recent tab is added, thus, it should not
-  // report the first recent tab (which it is not aware about).
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
-  AddOfflinePageToModel(ntp_snippets::test::CreateDummyOfflinePageItem(
-      2, offline_pages::kDefaultNamespace));
-}
-
-TEST_F(RecentTabSuggestionsProviderTest,
-       ShouldInvalidateSuggestionWhenTabGone) {
-  OfflinePageItem first_tab = CreateDummyRecentTab(1);
-  AddTabAndOfflinePageToModel(first_tab);
-  task_runner()->RunUntilIdle();
-  Mock::VerifyAndClearExpectations(observer());
-
-  EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(1)))
-      .Times(1);
-  RemoveTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
-      first_tab.client_id));
-  // Removing an unknown tab should not cause extra invalidations.
-  RemoveTab(42);
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowPagesWithoutTab) {
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
-  // The provider is not notified about the first recent tab yet (no tab).
-  OfflinePageItem first_tab = CreateDummyRecentTab(1);
-  AddOfflinePageToModel(first_tab);
-
-  Mock::VerifyAndClearExpectations(observer());
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(1);
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          UnorderedElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
-
-  AddTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
-      first_tab.client_id));
-  OfflinePageItem second_tab = CreateDummyRecentTab(2);
-  AddTabAndOfflinePageToModel(second_tab);
-  task_runner()->RunUntilIdle();
-
-  Mock::VerifyAndClearExpectations(observer());
-
-  EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
-  // |RemoveTab| by itself doesn't cause OnNewSuggestions to be called.
-  RemoveTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
-      second_tab.client_id));
-  Mock::VerifyAndClearExpectations(observer());
-
-  // But when we get another tab, OnNewSuggestions will be called.
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          UnorderedElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/3")))));
-
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(3));
-  task_runner()->RunUntilIdle();
-}
-
-// The following test uses a different fixture that does not automatically pump
-// the event loop in SetUp, which means that until |RunUntilIdle| is called, the
-// UI adapter will not be loaded (and should not fire any events).
-
-TEST_F(RecentTabSuggestionsProviderTestNoLoad, ShouldFetchOnLoad) {
-  // Tabs are added to the model before the UI adapter is loaded, so there
-  // should only be a single |OnNewSuggestions| call, at load time.
-  EXPECT_CALL(
-      *observer(),
-      OnNewSuggestions(
-          _, recent_tabs_category(),
-          UnorderedElementsAre(
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
-              Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
-
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(1));
-  AddTabAndOfflinePageToModel(CreateDummyRecentTab(2));
-  // The provider is not notified about the recent tabs yet.
-  task_runner()->RunUntilIdle();
-  // However, it must return both tabs when the model is loaded.
-}
-
-}  // namespace ntp_snippets
diff --git a/components/ntp_snippets/pref_names.cc b/components/ntp_snippets/pref_names.cc
index 3ae3397..f9dc7d3 100644
--- a/components/ntp_snippets/pref_names.cc
+++ b/components/ntp_snippets/pref_names.cc
@@ -57,8 +57,6 @@
     "ntp_suggestions.foreign_sessions.dismissed_ids";
 const char kDismissedOfflinePageDownloadSuggestions[] =
     "ntp_suggestions.downloads.offline_pages.dismissed_ids";
-const char kDismissedRecentOfflineTabSuggestions[] =
-    "ntp_suggestions.offline_pages.recent_tabs.dismissed_ids";
 
 const char kDismissedCategories[] = "ntp_suggestions.dismissed_categories";
 
diff --git a/components/ntp_snippets/pref_names.h b/components/ntp_snippets/pref_names.h
index ac4f3765..7e26cc8 100644
--- a/components/ntp_snippets/pref_names.h
+++ b/components/ntp_snippets/pref_names.h
@@ -69,7 +69,6 @@
 extern const char kDismissedAssetDownloadSuggestions[];
 extern const char kDismissedForeignSessionsSuggestions[];
 extern const char kDismissedOfflinePageDownloadSuggestions[];
-extern const char kDismissedRecentOfflineTabSuggestions[];
 
 extern const char kDismissedCategories[];
 
diff --git a/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index 118d019..868bb0b 100644
--- a/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -281,7 +281,6 @@
   EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News")));
   EXPECT_THAT(sugg.score(), Eq(9001));
   EXPECT_THAT(sugg.download_suggestion_extra(), IsNull());
-  EXPECT_THAT(sugg.recent_tab_suggestion_extra(), IsNull());
   EXPECT_THAT(sugg.notification_extra(), IsNull());
   EXPECT_THAT(sugg.fetch_date(), Eq(fetch_date));
 }
@@ -306,7 +305,6 @@
   EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News")));
   EXPECT_THAT(sugg.score(), Eq(9001));
   EXPECT_THAT(sugg.download_suggestion_extra(), IsNull());
-  EXPECT_THAT(sugg.recent_tab_suggestion_extra(), IsNull());
   ASSERT_THAT(sugg.notification_extra(), NotNull());
   EXPECT_THAT(sugg.notification_extra()->deadline.ToJavaTime(),
               Eq(1467291697000));
diff --git a/components/offline_pages/content/background_loader/background_loader_contents_stub.cc b/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
index c5df23d..9941397c 100644
--- a/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
+++ b/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
@@ -13,9 +13,9 @@
 BackgroundLoaderContentsStub::BackgroundLoaderContentsStub(
     content::BrowserContext* browser_context)
     : BackgroundLoaderContents(), is_loading_(false) {
-  BackgroundLoaderContents::web_contents_.reset(
+  BackgroundLoaderContents::web_contents_ =
       content::WebContentsTester::CreateTestWebContents(browser_context,
-                                                        nullptr));
+                                                        nullptr);
   web_contents_.get()->SetDelegate(this);
 }
 
diff --git a/components/offline_pages/core/BUILD.gn b/components/offline_pages/core/BUILD.gn
index bd8d10f9..b2f88908 100644
--- a/components/offline_pages/core/BUILD.gn
+++ b/components/offline_pages/core/BUILD.gn
@@ -191,7 +191,6 @@
     ":switches",
     ":test_support",
     "prefetch:unit_tests",
-    "recent_tabs:unit_tests",
     "renovations:unit_tests",
     "//base",
     "//base/test:test_support",
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 0c7605a..a9a580f 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -619,6 +619,9 @@
             .pages_allowed_per_url != kUnlimitedPages) {
       RemovePagesMatchingUrlAndNamespace(page_attempted);
     }
+    offline_event_logger_.RecordPageSaved(page_attempted.client_id.name_space,
+                                          page_attempted.url.spec(),
+                                          page_attempted.offline_id);
   }
   ScheduleMaintenanceTasks();
 }
@@ -647,6 +650,7 @@
         "OfflinePages.DeletePageCount",
         model_utils::ToNamespaceEnum(info.client_id.name_space),
         OfflinePagesNamespaceEnumeration::RESULT_COUNT);
+    offline_event_logger_.RecordPageDeleted(info.offline_id);
     for (Observer& observer : observers_)
       observer.OfflinePageDeleted(info);
     if (info.system_download_id != 0)
diff --git a/components/offline_pages/core/offline_page_model_event_logger.cc b/components/offline_pages/core/offline_page_model_event_logger.cc
index 695d355..63ae0ba 100644
--- a/components/offline_pages/core/offline_page_model_event_logger.cc
+++ b/components/offline_pages/core/offline_page_model_event_logger.cc
@@ -18,20 +18,4 @@
   RecordActivity("Page with ID " + id_str + " has been deleted");
 }
 
-void OfflinePageModelEventLogger::RecordPageExpired(int64_t offline_id) {
-  std::string id_str = std::to_string(offline_id);
-  RecordActivity("Page with ID " + id_str + " has been expired");
-}
-
-void OfflinePageModelEventLogger::RecordStoreClearError() {
-  RecordActivity("Offline store clear failed");
-}
-
-void OfflinePageModelEventLogger::RecordStoreCleared() {
-  RecordActivity("Offline store cleared");
-}
-
-void OfflinePageModelEventLogger::RecordStoreReloadError() {
-  RecordActivity("There was an error reloading the offline store");
-}
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_page_model_event_logger.h b/components/offline_pages/core/offline_page_model_event_logger.h
index ae3a05a6..f976dd2 100644
--- a/components/offline_pages/core/offline_page_model_event_logger.h
+++ b/components/offline_pages/core/offline_page_model_event_logger.h
@@ -19,18 +19,6 @@
 
   // Records that a page with |offline_id| has been deleted.
   void RecordPageDeleted(int64_t offline_id);
-
-  // Records that a page with |offline_id| has been expired.
-  void RecordPageExpired(int64_t offline_id);
-
-  // Records that the offline store has been cleared.
-  void RecordStoreCleared();
-
-  // Records that there was an error when clearing the offline store.
-  void RecordStoreClearError();
-
-  // Records that there was an error when reloading the offline store.
-  void RecordStoreReloadError();
 };
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_page_model_event_logger_unittest.cc b/components/offline_pages/core/offline_page_model_event_logger_unittest.cc
index 5f7b690..d416c938 100644
--- a/components/offline_pages/core/offline_page_model_event_logger_unittest.cc
+++ b/components/offline_pages/core/offline_page_model_event_logger_unittest.cc
@@ -17,11 +17,6 @@
 const char kPageSaved[] =
     "http://www.wikipedia.org is saved at last_n with id 12345";
 const char kPageDeleted[] = "Page with ID 12345 has been deleted";
-const char kPageExpired[] = "Page with ID 12345 has been expired";
-const char kRecordStoreClearError[] = "Offline store clear failed";
-const char kRecordStoreCleared[] = "Offline store cleared";
-const char kRecordStoreReloadError[] =
-    "There was an error reloading the offline store";
 
 }  // namespace
 
@@ -30,21 +25,13 @@
   std::vector<std::string> log;
 
   logger.SetIsLogging(true);
-  logger.RecordStoreCleared();
   logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
   logger.RecordPageDeleted(kOfflineId);
-  logger.RecordPageExpired(kOfflineId);
-  logger.RecordStoreClearError();
-  logger.RecordStoreReloadError();
   logger.GetLogs(&log);
 
-  EXPECT_EQ(6u, log.size());
-  EXPECT_EQ(std::string(kRecordStoreCleared), log[5].substr(kTimeLength));
-  EXPECT_EQ(std::string(kPageSaved), log[4].substr(kTimeLength));
-  EXPECT_EQ(std::string(kPageDeleted), log[3].substr(kTimeLength));
-  EXPECT_EQ(std::string(kPageExpired), log[2].substr(kTimeLength));
-  EXPECT_EQ(std::string(kRecordStoreClearError), log[1].substr(kTimeLength));
-  EXPECT_EQ(std::string(kRecordStoreReloadError), log[0].substr(kTimeLength));
+  EXPECT_EQ(2u, log.size());
+  EXPECT_EQ(std::string(kPageSaved), log[1].substr(kTimeLength));
+  EXPECT_EQ(std::string(kPageDeleted), log[0].substr(kTimeLength));
 }
 
 TEST(OfflinePageModelEventLoggerTest, DoesNotRecordWhenLoggingIsOff) {
@@ -52,12 +39,8 @@
   std::vector<std::string> log;
 
   logger.SetIsLogging(false);
-  logger.RecordStoreCleared();
   logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
   logger.RecordPageDeleted(kOfflineId);
-  logger.RecordPageExpired(kOfflineId);
-  logger.RecordStoreClearError();
-  logger.RecordStoreReloadError();
   logger.GetLogs(&log);
 
   EXPECT_EQ(0u, log.size());
@@ -69,7 +52,7 @@
 
   logger.SetIsLogging(true);
   for (size_t i = 0; i < kMaxLogCount + 1; ++i) {
-    logger.RecordStoreCleared();
+    logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
   }
   logger.GetLogs(&log);
 
diff --git a/components/offline_pages/core/recent_tabs/BUILD.gn b/components/offline_pages/core/recent_tabs/BUILD.gn
deleted file mode 100644
index fa8f938a..0000000
--- a/components/offline_pages/core/recent_tabs/BUILD.gn
+++ /dev/null
@@ -1,39 +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.
-
-if (is_android) {
-  import("//build/config/android/rules.gni")
-}
-
-source_set("recent_tabs") {
-  sources = [
-    "recent_tabs_ui_adapter_delegate.cc",
-    "recent_tabs_ui_adapter_delegate.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/offline_pages/core",
-    "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
-    "//url",
-  ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "recent_tabs_ui_adapter_delegate_unittest.cc",
-  ]
-
-  deps = [
-    ":recent_tabs",
-    "//base",
-    "//base/test:test_support",
-    "//components/offline_pages/core",
-    "//components/offline_pages/core:test_support",
-    "//components/offline_pages/core/background:test_support",
-    "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
-    "//testing/gtest",
-  ]
-}
diff --git a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc b/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc
deleted file mode 100644
index 0db7cda..0000000
--- a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc
+++ /dev/null
@@ -1,101 +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 "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "components/offline_pages/core/thumbnail_decoder.h"
-
-namespace offline_pages {
-
-namespace {
-const char kRecentTabsUIAdapterKey[] = "recent-tabs-download-ui-adapter";
-}  // namespace
-
-RecentTabsUIAdapterDelegate::RecentTabsUIAdapterDelegate(
-    OfflinePageModel* model)
-    : model_(model) {}
-
-RecentTabsUIAdapterDelegate::~RecentTabsUIAdapterDelegate() = default;
-
-offline_pages::DownloadUIAdapter*
-RecentTabsUIAdapterDelegate::GetOrCreateRecentTabsUIAdapter(
-    offline_pages::OfflinePageModel* offline_page_model,
-    offline_pages::RequestCoordinator* request_coordinator) {
-  offline_pages::DownloadUIAdapter* recent_tabs_ui_adapter =
-      static_cast<DownloadUIAdapter*>(
-          offline_page_model->GetUserData(kRecentTabsUIAdapterKey));
-
-  if (!recent_tabs_ui_adapter) {
-    auto delegate =
-        std::make_unique<RecentTabsUIAdapterDelegate>(offline_page_model);
-    recent_tabs_ui_adapter =
-        new DownloadUIAdapter(nullptr, offline_page_model, request_coordinator,
-                              nullptr, std::move(delegate));
-    offline_page_model->SetUserData(kRecentTabsUIAdapterKey,
-                                    base::WrapUnique(recent_tabs_ui_adapter));
-  }
-
-  return recent_tabs_ui_adapter;
-}
-
-// static
-RecentTabsUIAdapterDelegate* RecentTabsUIAdapterDelegate::FromDownloadUIAdapter(
-    DownloadUIAdapter* ui_adapter) {
-  return static_cast<RecentTabsUIAdapterDelegate*>(ui_adapter->delegate());
-}
-
-// static
-int RecentTabsUIAdapterDelegate::TabIdFromClientId(const ClientId& client_id) {
-  int tab_id = 0;
-  bool convert_result = base::StringToInt(client_id.id, &tab_id);
-  DCHECK(convert_result);
-  return tab_id;
-}
-
-bool RecentTabsUIAdapterDelegate::IsVisibleInUI(const ClientId& client_id) {
-  return IsRecentTab(client_id);
-}
-
-bool RecentTabsUIAdapterDelegate::IsTemporarilyHiddenInUI(
-    const ClientId& client_id) {
-  return active_tabs_.count(TabIdFromClientId(client_id)) == 0;
-}
-
-void RecentTabsUIAdapterDelegate::SetUIAdapter(DownloadUIAdapter* adapter) {
-  ui_adapter_ = adapter;
-}
-
-void RecentTabsUIAdapterDelegate::RegisterTab(int tab_id) {
-  DCHECK(ui_adapter_);
-  if (active_tabs_.count(tab_id) > 0)
-    return;
-  active_tabs_.insert(tab_id);
-  ui_adapter_->TemporaryHiddenStatusChanged(ClientIdFromTabId(tab_id));
-}
-
-void RecentTabsUIAdapterDelegate::UnregisterTab(int tab_id) {
-  DCHECK(ui_adapter_);
-  if (active_tabs_.count(tab_id) == 0)
-    return;
-  active_tabs_.erase(tab_id);
-  ui_adapter_->TemporaryHiddenStatusChanged(ClientIdFromTabId(tab_id));
-}
-
-// static
-ClientId RecentTabsUIAdapterDelegate::ClientIdFromTabId(int tab_id) {
-  return ClientId(kLastNNamespace, base::IntToString(tab_id));
-}
-
-bool RecentTabsUIAdapterDelegate::IsRecentTab(const ClientId& page) {
-  return model_->GetPolicyController()->IsShownAsRecentlyVisitedSite(
-      page.name_space);
-}
-
-}  // namespace offline_pages
diff --git a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h b/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h
deleted file mode 100644
index 212e423..0000000
--- a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_OFFLINE_PAGES_CORE_RECENT_TABS_RECENT_TABS_UI_ADAPTER_DELEGATE_H_
-#define COMPONENTS_OFFLINE_PAGES_CORE_RECENT_TABS_RECENT_TABS_UI_ADAPTER_DELEGATE_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/observer_list.h"
-#include "base/supports_user_data.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "components/offline_pages/core/offline_page_types.h"
-#include "url/gurl.h"
-
-namespace offline_pages {
-
-// Keeps track of all the tabs open for the profile, and restricts its view of
-// the offline pages to only those that have an open tab.  This begins
-// observation early, as soon as the first Tab is created, and even before that
-// tab gets a web contents.
-//
-// In this UI adapter, |guid| represents the tab ID for a given page.
-class RecentTabsUIAdapterDelegate : public DownloadUIAdapter::Delegate {
- public:
-  explicit RecentTabsUIAdapterDelegate(OfflinePageModel* model);
-  ~RecentTabsUIAdapterDelegate() override;
-
-  static DownloadUIAdapter* GetOrCreateRecentTabsUIAdapter(
-      OfflinePageModel* offline_page_model,
-      RequestCoordinator* request_coordinator);
-  static RecentTabsUIAdapterDelegate* FromDownloadUIAdapter(
-      DownloadUIAdapter* adapter);
-  // This extracts the tab ID out of the |id| field of the client ID using a
-  // string conversion.  Crashes if conversion fails.
-  static int TabIdFromClientId(const ClientId& client_id);
-
-  // This override returns true if the client ID is shown on the NTP as a recent
-  // tab.  This is determined by policy.
-  bool IsVisibleInUI(const ClientId& client_id) override;
-  // This returns true if there does not exist a tab ID for the given client ID.
-  bool IsTemporarilyHiddenInUI(const ClientId& client_id) override;
-  // Sets our reference to the UI adapter so we can notify it of visibility
-  // changes.
-  void SetUIAdapter(DownloadUIAdapter* ui_adapter) override;
-  void OpenItem(const OfflineItem& item, int64_t offline_id) override {}
-
-  // Register/UnregisterTab add and remove tab IDs from the list.  These
-  // functions can be called before a page actually exists with the given tab
-  // ID.
-  // Note that these change temporary visibility and therefore |set_ui_adapter|
-  // must be called before either of these functions.
-  void RegisterTab(int tab_id);
-  void UnregisterTab(int tab_id);
-
- private:
-  // Constructs the client ID assuming that we use the Last N namespace.
-  //
-  // TODO(dewittj): Make this more resilient to adding more namespaces.
-  static ClientId ClientIdFromTabId(int tab_id);
-
-  // Checks a client ID for proper namespace and ID format to be shown in the
-  // Downloads Home UI.
-  bool IsRecentTab(const ClientId& page);
-
-  // Always valid, this class is owned by DownloadUIAdapter, which is owned by
-  // Offline Page Model.
-  OfflinePageModel* model_;
-
-  // This is set by the UI adapter itself.
-  DownloadUIAdapter* ui_adapter_ = nullptr;
-
-  // The tabs we've seen.
-  std::unordered_set<int> active_tabs_;
-
-  DISALLOW_COPY_AND_ASSIGN(RecentTabsUIAdapterDelegate);
-};
-
-}  // namespace offline_pages
-
-#endif  // COMPONENTS_OFFLINE_PAGES_CORE_RECENT_TABS_RECENT_TABS_UI_ADAPTER_DELEGATE_H_
diff --git a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc b/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc
deleted file mode 100644
index 90e4f5b..0000000
--- a/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/offline_pages/core/background/request_coordinator_stub_taco.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/stub_offline_page_model.h"
-#include "components/offline_pages/core/thumbnail_decoder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace offline_pages {
-
-namespace {
-static const char kTestGuid1[] = "1";
-static const char kTestGuid2[] = "2";
-static const char kTestBadGuid[] = "ccccccc-cccc-0ccc-0ccc-ccccccccccc0";
-static const ClientId kTestClientIdOtherNamespace(kAsyncNamespace, kTestGuid1);
-static const ClientId kTestClientIdOtherGuid(kLastNNamespace, kTestBadGuid);
-static const ClientId kTestClientId1(kLastNNamespace, kTestGuid1);
-static const ClientId kTestClientId2(kLastNNamespace, kTestGuid2);
-
-// Creates mock versions for OfflinePageModel, RequestCoordinator and their
-// dependencies, then passes them to DownloadUIAdapter for testing.
-// Note that initially the OfflienPageModel is not "loaded". PumpLoop() will
-// load it, firing ItemsLoaded callback to the Adapter. Hence some tests
-// start from PumpLoop() right away if they don't need to test this.
-class RecentTabsUIAdapterDelegateTest : public testing::Test {
- public:
-  RecentTabsUIAdapterDelegateTest();
-  ~RecentTabsUIAdapterDelegateTest() override;
-
-  // Runs until all of the tasks that are not delayed are gone from the task
-  // queue.
-  void PumpLoop();
-
-  RequestCoordinator* request_coordinator() {
-    return request_coordinator_taco_->request_coordinator();
-  }
-
-  StubOfflinePageModel model;
-  RecentTabsUIAdapterDelegate* adapter_delegate;
-  std::unique_ptr<DownloadUIAdapter> adapter;
-
- private:
-  std::unique_ptr<RequestCoordinatorStubTaco> request_coordinator_taco_;
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle task_runner_handle_;
-};
-
-RecentTabsUIAdapterDelegateTest::RecentTabsUIAdapterDelegateTest()
-    : task_runner_(new base::TestMockTimeTaskRunner()),
-      task_runner_handle_(task_runner_) {
-  request_coordinator_taco_ = std::make_unique<RequestCoordinatorStubTaco>();
-  request_coordinator_taco_->CreateRequestCoordinator();
-
-  auto delegate = std::make_unique<RecentTabsUIAdapterDelegate>(&model);
-  adapter_delegate = delegate.get();
-
-  adapter = std::make_unique<DownloadUIAdapter>(
-      nullptr, &model, request_coordinator_taco_->request_coordinator(),
-      nullptr, std::move(delegate));
-}
-
-RecentTabsUIAdapterDelegateTest::~RecentTabsUIAdapterDelegateTest() = default;
-
-void RecentTabsUIAdapterDelegateTest::PumpLoop() {
-  task_runner_->RunUntilIdle();
-}
-
-TEST_F(RecentTabsUIAdapterDelegateTest, TabIdFromClientId) {
-  EXPECT_EQ(1, RecentTabsUIAdapterDelegate::TabIdFromClientId(kTestClientId1));
-  EXPECT_EQ(2, RecentTabsUIAdapterDelegate::TabIdFromClientId(kTestClientId2));
-}
-
-TEST_F(RecentTabsUIAdapterDelegateTest, IsVisibleInUI) {
-  EXPECT_FALSE(adapter_delegate->IsVisibleInUI(kTestClientIdOtherNamespace));
-  EXPECT_TRUE(adapter_delegate->IsVisibleInUI(kTestClientId1));
-  EXPECT_TRUE(adapter_delegate->IsVisibleInUI(kTestClientId2));
-}
-
-TEST_F(RecentTabsUIAdapterDelegateTest, IsTemporarilyHiddenInUI) {
-  adapter_delegate->RegisterTab(3);
-  adapter_delegate->RegisterTab(4);
-
-  EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
-  EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-
-  adapter_delegate->RegisterTab(1);
-  EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
-  EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-
-  adapter_delegate->RegisterTab(2);
-  EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
-  EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-
-  adapter_delegate->UnregisterTab(2);
-  EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
-  EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-}
-
-}  // namespace
-}  // namespace offline_pages
diff --git a/components/security_interstitials/core/common/resources/interstitial_common.css b/components/security_interstitials/core/common/resources/interstitial_common.css
index bb1ca4f..76380d9 100644
--- a/components/security_interstitials/core/common/resources/interstitial_common.css
+++ b/components/security_interstitials/core/common/resources/interstitial_common.css
@@ -268,9 +268,9 @@
        (min-width: 421px) and (min-height: 240px) and
        (max-height: 560px) {
   body .nav-wrapper {
-    background: #f7f7f7;
+    background: #fff;
     bottom: 0;
-    box-shadow: 0 -22px 40px rgb(247, 247, 247);
+    box-shadow: 0 -22px 40px #fff;
     left: 0;
     margin: 0 auto;
     max-width: 736px;
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 0992c87..4470265 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -98,6 +98,9 @@
     surface_manager_->AddObserver(scheduler_.get());
 
   output_surface_->BindToClient(this);
+  if (output_surface_->software_device())
+    output_surface_->software_device()->BindToClient(this);
+
   InitializeRenderer();
 
   // This depends on assumptions that Display::Initialize will happen on the
@@ -575,6 +578,12 @@
   return it->second;
 }
 
+void Display::SoftwareDeviceUpdatedCALayerParams(
+    const gfx::CALayerParams& ca_layer_params) {
+  if (client_)
+    client_->DisplayDidReceiveCALayerParams(ca_layer_params);
+}
+
 void Display::ForceImmediateDrawAndSwapIfPossible() {
   if (scheduler_)
     scheduler_->ForceImmediateSwapIfPossible();
@@ -633,10 +642,12 @@
       // Skip quad if it is a RenderPassDrawQuad because RenderPassDrawQuad is a
       // special type of DrawQuad where the visible_rect of shared quad state is
       // not entirely covered by draw quads in it; or the DrawQuad size is
-      // smaller than the kMinimumDrawOcclusionSize.
+      // smaller than the kMinimumDrawOcclusionSize; or the DrawQuad is inside
+      // a 3d objects.
       if (quad->material == ContentDrawQuadBase::Material::RENDER_PASS ||
           (quad->visible_rect.width() <= minimum_draw_occlusion_width &&
-           quad->visible_rect.height() <= minimum_draw_occlusion_height)) {
+           quad->visible_rect.height() <= minimum_draw_occlusion_height) ||
+          quad->shared_quad_state->sorting_context_id != 0) {
         ++quad;
         continue;
       }
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index e15a341..4b7d805 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -19,6 +19,7 @@
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/service/display/display_scheduler.h"
 #include "components/viz/service/display/output_surface_client.h"
+#include "components/viz/service/display/software_output_device_client.h"
 #include "components/viz/service/display/surface_aggregator.h"
 #include "components/viz/service/surfaces/latest_local_surface_id_lookup_delegate.h"
 #include "components/viz/service/surfaces/surface_manager.h"
@@ -57,7 +58,8 @@
 class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
                                    public OutputSurfaceClient,
                                    public ContextLostObserver,
-                                   public LatestLocalSurfaceIdLookupDelegate {
+                                   public LatestLocalSurfaceIdLookupDelegate,
+                                   public SoftwareOutputDeviceClient {
  public:
   // The |begin_frame_source| and |scheduler| may be null (together). In that
   // case, DrawAndSwap must be called externally when needed.
@@ -121,6 +123,10 @@
   LocalSurfaceId GetSurfaceAtAggregation(
       const FrameSinkId& frame_sink_id) const override;
 
+  // SoftwareOutputDeviceClient implementation
+  void SoftwareDeviceUpdatedCALayerParams(
+      const gfx::CALayerParams& ca_layer_params) override;
+
   bool has_scheduler() const { return !!scheduler_; }
   DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
 
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index 6bfb8aa..eb7d432 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -2074,6 +2074,62 @@
   TearDownDisplay();
 }
 
+// Test if draw occlusion skips 3d objects. https://crbug.com/833748
+TEST_F(DisplayTest, CompositorFrameZTranslate) {
+  RendererSettings settings;
+  settings.kMinimumDrawOcclusionSize.set_width(0);
+  SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+
+  StubDisplayClient client;
+  display_->Initialize(&client, manager_.surface_manager());
+
+  CompositorFrame frame = MakeDefaultCompositorFrame();
+  gfx::Rect rect1(0, 0, 100, 100);
+  gfx::Rect rect2(0, 0, 200, 100);
+
+  gfx::Transform translate_back;
+  translate_back.Translate3d(0, 0, 100);
+  bool is_clipped = false;
+  bool are_contents_opaque = true;
+  float opacity = 1.f;
+  SharedQuadState* shared_quad_state =
+      frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
+  auto* quad = frame.render_pass_list.front()
+                   ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
+  SharedQuadState* shared_quad_state2 =
+      frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
+  auto* quad2 = frame.render_pass_list.front()
+                    ->quad_list.AllocateAndConstruct<SolidColorDrawQuad>();
+
+  // 2 rects inside of 3d object is completely overlapping.
+  //                         +-----+
+  //                         |     |
+  //                         +-----+
+  {
+    shared_quad_state->SetAll(translate_back, rect1, rect1, rect1, is_clipped,
+                              are_contents_opaque, opacity,
+                              SkBlendMode::kSrcOver, 1);
+    shared_quad_state2->SetAll(gfx::Transform(), rect1, rect1, rect1,
+                               is_clipped, are_contents_opaque, opacity,
+                               SkBlendMode::kSrcOver, 1);
+
+    quad->SetNew(shared_quad_state, rect1, rect1, SK_ColorBLACK, false);
+    quad2->SetNew(shared_quad_state2, rect2, rect1, SK_ColorBLACK, false);
+    EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size());
+    display_->RemoveOverdrawQuads(&frame);
+    // Since both |quad| and |quad2| are inside of a 3d object, DrawOcclusion
+    // will not be applied to them.
+    EXPECT_EQ(2u, frame.render_pass_list.front()->quad_list.size());
+    EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
+                                    ->quad_list.ElementAt(0)
+                                    ->rect.ToString());
+    EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
+                                    ->quad_list.ElementAt(1)
+                                    ->rect.ToString());
+  }
+  TearDownDisplay();
+}
+
 TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
   RendererSettings settings;
   settings.kMinimumDrawOcclusionSize.set_width(0);
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index e1a55fad..c8d5cb9d3 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -655,38 +655,45 @@
   EXPECT_TRUE(renderer_->stencil_enabled());
 }
 
-class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
+class ForbidSynchronousCallGLES2Interface : public TestGLES2Interface {
  public:
-  ForbidSynchronousCallContext() {}
+  ForbidSynchronousCallGLES2Interface() = default;
 
-  void getAttachedShaders(GLuint program,
+  void GetAttachedShaders(GLuint program,
                           GLsizei max_count,
                           GLsizei* count,
                           GLuint* shaders) override {
     ADD_FAILURE();
   }
-  GLint getAttribLocation(GLuint program, const GLchar* name) override {
+
+  GLint GetAttribLocation(GLuint program, const GLchar* name) override {
     ADD_FAILURE();
     return 0;
   }
-  void getBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
-  void getBufferParameteriv(GLenum target,
+
+  void GetBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
+
+  void GetBufferParameteriv(GLenum target,
                             GLenum pname,
                             GLint* value) override {
     ADD_FAILURE();
   }
-  GLenum getError() override {
+
+  GLenum GetError() override {
     ADD_FAILURE();
     return GL_NO_ERROR;
   }
-  void getFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
-  void getFramebufferAttachmentParameteriv(GLenum target,
+
+  void GetFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
+
+  void GetFramebufferAttachmentParameteriv(GLenum target,
                                            GLenum attachment,
                                            GLenum pname,
                                            GLint* value) override {
     ADD_FAILURE();
   }
-  void getIntegerv(GLenum pname, GLint* value) override {
+
+  void GetIntegerv(GLenum pname, GLint* value) override {
     if (pname == GL_MAX_TEXTURE_SIZE) {
       // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
       *value = 1024;
@@ -697,64 +704,66 @@
 
   // We allow querying the shader compilation and program link status in debug
   // mode, but not release.
-  void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
-#ifndef NDEBUG
-    *value = 1;
-#else
+  void GetProgramiv(GLuint program, GLenum pname, GLint* value) override {
     ADD_FAILURE();
-#endif
   }
 
-  void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
-#ifndef NDEBUG
-    *value = 1;
-#else
+  void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override {
     ADD_FAILURE();
-#endif
   }
 
-  void getRenderbufferParameteriv(GLenum target,
+  void GetRenderbufferParameteriv(GLenum target,
                                   GLenum pname,
                                   GLint* value) override {
     ADD_FAILURE();
   }
 
-  void getShaderPrecisionFormat(GLenum shadertype,
+  void GetShaderPrecisionFormat(GLenum shadertype,
                                 GLenum precisiontype,
                                 GLint* range,
                                 GLint* precision) override {
     ADD_FAILURE();
   }
-  void getTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
+
+  void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
     ADD_FAILURE();
   }
-  void getTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
+
+  void GetTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
     ADD_FAILURE();
   }
-  void getUniformfv(GLuint program, GLint location, GLfloat* value) override {
+
+  void GetUniformfv(GLuint program, GLint location, GLfloat* value) override {
     ADD_FAILURE();
   }
-  void getUniformiv(GLuint program, GLint location, GLint* value) override {
+
+  void GetUniformiv(GLuint program, GLint location, GLint* value) override {
     ADD_FAILURE();
   }
-  GLint getUniformLocation(GLuint program, const GLchar* name) override {
+
+  GLint GetUniformLocation(GLuint program, const GLchar* name) override {
     ADD_FAILURE();
     return 0;
   }
-  void getVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
+
+  void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
     ADD_FAILURE();
   }
-  void getVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
+
+  void GetVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
     ADD_FAILURE();
   }
-  GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname) override {
+
+  void GetVertexAttribPointerv(GLuint index,
+                               GLenum pname,
+                               void** pointer) override {
     ADD_FAILURE();
-    return 0;
   }
 };
+
 TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
-  auto context = std::make_unique<ForbidSynchronousCallContext>();
-  auto provider = TestContextProvider::Create(std::move(context));
+  auto gl_owned = std::make_unique<ForbidSynchronousCallGLES2Interface>();
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
   provider->BindToCurrentThread();
 
   cc::FakeOutputSurfaceClient output_surface_client;
@@ -811,22 +820,26 @@
                           resource_provider.get());
 }
 
-class ClearCountingContext : public TestWebGraphicsContext3D {
+class ClearCountingGLES2Interface : public TestGLES2Interface {
  public:
-  ClearCountingContext() { test_capabilities_.discard_framebuffer = true; }
+  ClearCountingGLES2Interface() = default;
 
-  MOCK_METHOD3(discardFramebufferEXT,
+  void InitializeTestContext(TestWebGraphicsContext3D* context) override {
+    context->set_have_discard_framebuffer(true);
+  }
+
+  MOCK_METHOD3(DiscardFramebufferEXT,
                void(GLenum target,
                     GLsizei numAttachments,
                     const GLenum* attachments));
-  MOCK_METHOD1(clear, void(GLbitfield mask));
+  MOCK_METHOD1(Clear, void(GLbitfield mask));
 };
 
 TEST_F(GLRendererTest, OpaqueBackground) {
-  std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
-  ClearCountingContext* context = context_owned.get();
+  auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
+  ClearCountingGLES2Interface* gl = gl_owned.get();
 
-  auto provider = TestContextProvider::Create(std::move(context_owned));
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
   provider->BindToCurrentThread();
 
   cc::FakeOutputSurfaceClient output_surface_client;
@@ -854,23 +867,23 @@
 
   // On DEBUG builds, render passes with opaque background clear to blue to
   // easily see regions that were not drawn on the screen.
-  EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+  EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
       .With(Args<2, 1>(ElementsAre(GL_COLOR_EXT)))
       .Times(1);
 #ifdef NDEBUG
-  EXPECT_CALL(*context, clear(_)).Times(0);
+  EXPECT_CALL(*gl, Clear(_)).Times(0);
 #else
-  EXPECT_CALL(*context, clear(_)).Times(1);
+  EXPECT_CALL(*gl, Clear(_)).Times(1);
 #endif
   DrawFrame(&renderer, viewport_size);
-  Mock::VerifyAndClearExpectations(context);
+  Mock::VerifyAndClearExpectations(gl);
 }
 
 TEST_F(GLRendererTest, TransparentBackground) {
-  std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
-  ClearCountingContext* context = context_owned.get();
+  auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
+  ClearCountingGLES2Interface* gl = gl_owned.get();
 
-  auto provider = TestContextProvider::Create(std::move(context_owned));
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
   provider->BindToCurrentThread();
 
   cc::FakeOutputSurfaceClient output_surface_client;
@@ -896,18 +909,18 @@
       gfx::Transform(), cc::FilterOperations());
   root_pass->has_transparent_background = true;
 
-  EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
-  EXPECT_CALL(*context, clear(_)).Times(1);
+  EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
+  EXPECT_CALL(*gl, Clear(_)).Times(1);
   DrawFrame(&renderer, viewport_size);
 
-  Mock::VerifyAndClearExpectations(context);
+  Mock::VerifyAndClearExpectations(gl);
 }
 
 TEST_F(GLRendererTest, OffscreenOutputSurface) {
-  std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
-  ClearCountingContext* context = context_owned.get();
+  auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
+  ClearCountingGLES2Interface* gl = gl_owned.get();
 
-  auto provider = TestContextProvider::Create(std::move(context_owned));
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
   provider->BindToCurrentThread();
 
   cc::FakeOutputSurfaceClient output_surface_client;
@@ -931,26 +944,29 @@
   cc::AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
                     gfx::Transform(), cc::FilterOperations());
 
-  EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+  EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
       .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0)))
       .Times(1);
-  EXPECT_CALL(*context, clear(_)).Times(AnyNumber());
+  EXPECT_CALL(*gl, Clear(_)).Times(AnyNumber());
   DrawFrame(&renderer, viewport_size);
-  Mock::VerifyAndClearExpectations(context);
+  Mock::VerifyAndClearExpectations(gl);
 }
 
-class TextureStateTrackingContext : public TestWebGraphicsContext3D {
+class TextureStateTrackingGLES2Interface : public TestGLES2Interface {
  public:
-  TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {
-    test_capabilities_.egl_image_external = true;
+  TextureStateTrackingGLES2Interface() : active_texture_(GL_INVALID_ENUM) {}
+
+  void InitializeTestContext(TestWebGraphicsContext3D* context) override {
+    context->set_have_extension_egl_image(true);
   }
 
-  MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
-  MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
-  MOCK_METHOD4(drawElements,
-               void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+  MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
+  MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param));
+  MOCK_METHOD4(
+      DrawElements,
+      void(GLenum mode, GLsizei count, GLenum type, const void* indices));
 
-  void activeTexture(GLenum texture) override {
+  void ActiveTexture(GLenum texture) override {
     EXPECT_NE(texture, active_texture_);
     active_texture_ = texture;
   }
@@ -962,11 +978,10 @@
 };
 
 TEST_F(GLRendererTest, ActiveTextureState) {
-  std::unique_ptr<TextureStateTrackingContext> context_owned(
-      new TextureStateTrackingContext);
-  TextureStateTrackingContext* context = context_owned.get();
+  auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
+  TextureStateTrackingGLES2Interface* gl = gl_owned.get();
 
-  auto provider = TestContextProvider::Create(std::move(context_owned));
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
   provider->BindToCurrentThread();
 
   cc::FakeOutputSurfaceClient output_surface_client;
@@ -987,13 +1002,12 @@
   renderer.SetVisible(true);
 
   // During initialization we are allowed to set any texture parameters.
-  EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
+  EXPECT_CALL(*gl, TexParameteri(_, _, _)).Times(AnyNumber());
 
-  std::unique_ptr<TextureStateTrackingContext> child_context_owned(
-      new TextureStateTrackingContext);
+  auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
 
   auto child_context_provider =
-      TestContextProvider::Create(std::move(child_context_owned));
+      TestContextProvider::Create(std::move(child_gl_owned));
   child_context_provider->BindToCurrentThread();
   auto child_resource_provider =
       cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
@@ -1012,7 +1026,7 @@
 
   // Set up expected texture filter state transitions that match the quads
   // created in AppendOneOfEveryQuadType().
-  Mock::VerifyAndClearExpectations(context);
+  Mock::VerifyAndClearExpectations(gl);
   {
     InSequence sequence;
     // The verified flush flag will be set by
@@ -1024,43 +1038,45 @@
     // (with mailbox), resource2, resource3, resource4, resource9, resource10,
     // resource11, resource12. resource8 has its own mailbox mailbox_sync_token.
     // The rest resources share a common default sync token.
-    EXPECT_CALL(*context, waitSyncToken(_)).Times(2);
-    EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(mailbox_sync_token)))
+    EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(2);
+    EXPECT_CALL(*gl,
+                WaitSyncTokenCHROMIUM(MatchesSyncToken(mailbox_sync_token)))
         .Times(1);
-    EXPECT_CALL(*context, waitSyncToken(_)).Times(7);
+    EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(7);
 
     // yuv_quad is drawn with the default linear filter.
-    EXPECT_CALL(*context, drawElements(_, _, _, _));
+    EXPECT_CALL(*gl, DrawElements(_, _, _, _));
 
     // tile_quad is drawn with GL_NEAREST because it is not transformed or
     // scaled.
-    EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-                                        GL_NEAREST));
-    EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
-                                        GL_NEAREST));
+    EXPECT_CALL(
+        *gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+    EXPECT_CALL(
+        *gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
     // The remaining quads also use GL_LINEAR because nearest neighbor
     // filtering is currently only used with tile quads.
-    EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(8);
+    EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(8);
   }
 
   gfx::Size viewport_size(100, 100);
   DrawFrame(&renderer, viewport_size);
-  Mock::VerifyAndClearExpectations(context);
+  Mock::VerifyAndClearExpectations(gl);
 }
 
-class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D {
+class NoClearRootRenderPassMockGLES2Interface : public TestGLES2Interface {
  public:
-  MOCK_METHOD1(clear, void(GLbitfield mask));
-  MOCK_METHOD4(drawElements,
-               void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+  MOCK_METHOD1(Clear, void(GLbitfield mask));
+  MOCK_METHOD4(
+      DrawElements,
+      void(GLenum mode, GLsizei count, GLenum type, const void* indices));
 };
 
 TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
-  std::unique_ptr<NoClearRootRenderPassMockContext> mock_context_owned(
-      new NoClearRootRenderPassMockContext);
-  NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get();
+  auto mock_gl_owned =
+      std::make_unique<NoClearRootRenderPassMockGLES2Interface>();
+  NoClearRootRenderPassMockGLES2Interface* mock_gl = mock_gl_owned.get();
 
-  auto provider = TestContextProvider::Create(std::move(mock_context_owned));
+  auto provider = TestContextProvider::Create(std::move(mock_gl_owned));
   provider->BindToCurrentThread();
 
   cc::FakeOutputSurfaceClient output_surface_client;
@@ -1105,17 +1121,15 @@
 #endif
 
   // First render pass is not the root one, clearing should happen.
-  EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1));
+  EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(AtLeast(1));
 
   Expectation first_render_pass =
-      EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1);
+      EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _)).Times(1);
 
   // The second render pass is the root one, clearing should be prevented.
-  EXPECT_CALL(*mock_context, clear(clear_bits))
-      .Times(0)
-      .After(first_render_pass);
+  EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(0).After(first_render_pass);
 
-  EXPECT_CALL(*mock_context, drawElements(_, _, _, _))
+  EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _))
       .Times(AnyNumber())
       .After(first_render_pass);
 
@@ -1124,7 +1138,7 @@
 
   // In multiple render passes all but the root pass should clear the
   // framebuffer.
-  Mock::VerifyAndClearExpectations(&mock_context);
+  Mock::VerifyAndClearExpectations(&mock_gl);
 }
 
 class ScissorTestOnClearCheckingGLES2Interface : public TestGLES2Interface {
@@ -2213,9 +2227,9 @@
   SingleOverlayValidator validator_;
 };
 
-class WaitSyncTokenCountingContext : public TestWebGraphicsContext3D {
+class WaitSyncTokenCountingGLES2Interface : public TestGLES2Interface {
  public:
-  MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
+  MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
 };
 
 class MockOverlayScheduler {
@@ -2229,11 +2243,10 @@
 };
 
 TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
-  std::unique_ptr<WaitSyncTokenCountingContext> context_owned(
-      new WaitSyncTokenCountingContext);
-  WaitSyncTokenCountingContext* context = context_owned.get();
+  auto gl_owned = std::make_unique<WaitSyncTokenCountingGLES2Interface>();
+  WaitSyncTokenCountingGLES2Interface* gl = gl_owned.get();
 
-  auto provider = TestContextProvider::Create(std::move(context_owned));
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
   provider->BindToCurrentThread();
 
   MockOverlayScheduler overlay_scheduler;
@@ -2328,7 +2341,8 @@
 
   // Verify that overlay_quad actually gets turned into an overlay, and even
   // though it's not drawn, that its sync point is waited on.
-  EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))).Times(1);
+  EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token)))
+      .Times(1);
 
   EXPECT_CALL(
       overlay_scheduler,
diff --git a/components/viz/service/display/shader.cc b/components/viz/service/display/shader.cc
index d7cd218..62bab35 100644
--- a/components/viz/service/display/shader.cc
+++ b/components/viz/service/display/shader.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/strings/char_traits.h"
 #include "base/strings/stringprintf.h"
 #include "components/viz/service/display/static_geometry_binding.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -18,29 +19,18 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
 
-constexpr bool ConstexprEqual(const char* a, const char* b, size_t length) {
-  for (size_t i = 0; i < length; i++) {
-    if (a[i] != b[i])
-      return false;
-  }
-  return true;
-}
-
 constexpr base::StringPiece StripLambda(base::StringPiece shader) {
-  // Must contain at least "[]() {}" and trailing null (included in size).
-  // TODO(jbroman): Simplify this once we're in a post-C++17 world, where
-  // starts_with and ends_with can easily be made constexpr.
-  DCHECK(shader.size() >= 7);  // NOLINT
-  DCHECK(ConstexprEqual(shader.data(), "[]() {", 6));
+  // Must contain at least "[]() {}".
+  DCHECK(shader.starts_with("[]() {"));
+  DCHECK(shader.ends_with("}"));
   shader.remove_prefix(6);
-  DCHECK(shader[shader.size() - 1] == '}');  // NOLINT
   shader.remove_suffix(1);
   return shader;
 }
 
 // Shaders are passed in with lambda syntax, which tricks clang-format into
 // handling them correctly. StripLambda removes this.
-#define SHADER0(Src) StripLambda(base::StringPiece(#Src, sizeof(#Src) - 1))
+#define SHADER0(Src) StripLambda(#Src)
 
 #define HDR(x)        \
   do {                \
diff --git a/components/viz/service/display/software_output_device.cc b/components/viz/service/display/software_output_device.cc
index 7f8e8fd..bc611f86 100644
--- a/components/viz/service/display/software_output_device.cc
+++ b/components/viz/service/display/software_output_device.cc
@@ -13,6 +13,12 @@
 SoftwareOutputDevice::SoftwareOutputDevice() = default;
 SoftwareOutputDevice::~SoftwareOutputDevice() = default;
 
+void SoftwareOutputDevice::BindToClient(SoftwareOutputDeviceClient* client) {
+  DCHECK(client);
+  DCHECK(!client_);
+  client_ = client;
+}
+
 void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size,
                                   float scale_factor) {
   if (viewport_pixel_size_ == viewport_pixel_size)
diff --git a/components/viz/service/display/software_output_device.h b/components/viz/service/display/software_output_device.h
index 63e233d..396a67bc 100644
--- a/components/viz/service/display/software_output_device.h
+++ b/components/viz/service/display/software_output_device.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/viz/service/display/software_output_device_client.h"
 #include "components/viz/service/viz_service_export.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/gfx/geometry/rect.h"
@@ -18,10 +19,12 @@
 
 namespace gfx {
 class VSyncProvider;
-}
+}  // namespace gfx
 
 namespace viz {
 
+class SoftwareOutputDeviceClient;
+
 // This is a "tear-off" class providing software drawing support to
 // OutputSurface, such as to a platform-provided window framebuffer.
 class VIZ_SERVICE_EXPORT SoftwareOutputDevice {
@@ -29,6 +32,9 @@
   SoftwareOutputDevice();
   virtual ~SoftwareOutputDevice();
 
+  // This may be called only once, and requires a non-nullptr argument.
+  void BindToClient(SoftwareOutputDeviceClient* client);
+
   // Discards any pre-existing backing buffers and allocates memory for a
   // software device of |size|. This must be called before the
   // |SoftwareOutputDevice| can be used in other ways.
@@ -56,6 +62,7 @@
   virtual gfx::VSyncProvider* GetVSyncProvider();
 
  protected:
+  SoftwareOutputDeviceClient* client_ = nullptr;
   gfx::Size viewport_pixel_size_;
   gfx::Rect damage_rect_;
   sk_sp<SkSurface> surface_;
diff --git a/components/viz/service/display/software_output_device_client.h b/components/viz/service/display/software_output_device_client.h
new file mode 100644
index 0000000..695354d2
--- /dev/null
+++ b/components/viz/service/display/software_output_device_client.h
@@ -0,0 +1,26 @@
+// 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_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_
+
+namespace gfx {
+struct CALayerParams;
+}  // namespace gfx
+
+namespace viz {
+
+class SoftwareOutputDeviceClient {
+ public:
+  virtual ~SoftwareOutputDeviceClient() {}
+
+  // Specify the CALayer parameters used to display the content drawn by this
+  // device on macOS.
+  virtual void SoftwareDeviceUpdatedCALayerParams(
+      const gfx::CALayerParams& ca_layer_params) = 0;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc
index bdd3ac6..945e379 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -205,25 +205,13 @@
   if (headless_)
     return std::make_unique<SoftwareOutputDevice>();
 
-#if defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
-  gfx::AcceleratedWidget widget = surface_handle;
-#endif
-
 #if defined(OS_WIN)
   if (!output_device_backing_)
     output_device_backing_ = std::make_unique<OutputDeviceBacking>();
   return std::make_unique<SoftwareOutputDeviceWin>(output_device_backing_.get(),
-                                                   widget);
+                                                   surface_handle);
 #elif defined(OS_MACOSX)
-  // TODO(crbug.com/730660): What do we do to get something we can draw to? Can
-  // we use an IO surface? Can we use CA layers and overlays like we do for gpu
-  // compositing? See https://crrev.com/c/792295 to no longer have
-  // GpuSurfaceTracker. Part of the SoftwareOutputDeviceMac::EndPaint probably
-  // needs to move to the browser process, and we need to set up transport of an
-  // IO surface to here?
-  NOTIMPLEMENTED();
-  (void)widget;
-  return nullptr;
+  return std::make_unique<SoftwareOutputDeviceMac>();
 #elif defined(OS_ANDROID)
   // Android does not do software compositing, so we can't get here.
   NOTREACHED();
@@ -232,11 +220,11 @@
   ui::SurfaceFactoryOzone* factory =
       ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
   std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
-      factory->CreateCanvasForWidget(widget);
+      factory->CreateCanvasForWidget(surface_handle);
   CHECK(surface_ozone);
   return std::make_unique<SoftwareOutputDeviceOzone>(std::move(surface_ozone));
 #elif defined(USE_X11)
-  return std::make_unique<SoftwareOutputDeviceX11>(widget);
+  return std::make_unique<SoftwareOutputDeviceX11>(surface_handle);
 #endif
 }
 
diff --git a/components/viz/service/display_embedder/software_output_device_mac.cc b/components/viz/service/display_embedder/software_output_device_mac.cc
index 79211e9..db7a80d2 100644
--- a/components/viz/service/display_embedder/software_output_device_mac.cc
+++ b/components/viz/service/display_embedder/software_output_device_mac.cc
@@ -7,7 +7,7 @@
 #include "base/mac/foundation_util.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/accelerated_widget_mac/ca_layer_frame_sink.h"
+#include "ui/gfx/ca_layer_params.h"
 #include "ui/gfx/mac/io_surface.h"
 #include "ui/gfx/skia_util.h"
 
@@ -16,8 +16,7 @@
 SoftwareOutputDeviceMac::Buffer::Buffer() = default;
 SoftwareOutputDeviceMac::Buffer::~Buffer() = default;
 
-SoftwareOutputDeviceMac::SoftwareOutputDeviceMac(gfx::AcceleratedWidget widget)
-    : widget_(widget) {}
+SoftwareOutputDeviceMac::SoftwareOutputDeviceMac() {}
 
 SoftwareOutputDeviceMac::~SoftwareOutputDeviceMac() {}
 
@@ -178,17 +177,14 @@
   }
   current_paint_canvas_.reset();
 
-  if (widget_ != gfx::kNullAcceleratedWidget) {
+  if (client_) {
     gfx::CALayerParams ca_layer_params;
     ca_layer_params.is_empty = false;
     ca_layer_params.scale_factor = scale_factor_;
     ca_layer_params.pixel_size = pixel_size_;
     ca_layer_params.io_surface_mach_port.reset(
         IOSurfaceCreateMachPort(current_paint_buffer_->io_surface));
-    ui::CALayerFrameSink* ca_layer_frame_sink =
-        ui::CALayerFrameSink::FromAcceleratedWidget(widget_);
-    if (ca_layer_frame_sink)
-      ca_layer_frame_sink->UpdateCALayerTree(ca_layer_params);
+    client_->SoftwareDeviceUpdatedCALayerParams(ca_layer_params);
   }
 
   current_paint_buffer_ = nullptr;
diff --git a/components/viz/service/display_embedder/software_output_device_mac.h b/components/viz/service/display_embedder/software_output_device_mac.h
index 7329763..5b6160e 100644
--- a/components/viz/service/display_embedder/software_output_device_mac.h
+++ b/components/viz/service/display_embedder/software_output_device_mac.h
@@ -14,7 +14,6 @@
 #include "components/viz/service/viz_service_export.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/native_widget_types.h"
 
 class SkCanvas;
 
@@ -22,7 +21,7 @@
 
 class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice {
  public:
-  explicit SoftwareOutputDeviceMac(gfx::AcceleratedWidget widget);
+  SoftwareOutputDeviceMac();
   ~SoftwareOutputDeviceMac() override;
 
   // SoftwareOutputDevice implementation.
@@ -56,7 +55,6 @@
   void UpdateAndCopyBufferDamage(Buffer* previous_paint_buffer,
                                  const SkRegion& new_damage_rect);
 
-  gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
   gfx::Size pixel_size_;
   float scale_factor_ = 1;
 
diff --git a/components/viz/service/display_embedder/software_output_device_mac_unittest.mm b/components/viz/service/display_embedder/software_output_device_mac_unittest.mm
index ed0b8ad..7bb4d73e 100644
--- a/components/viz/service/display_embedder/software_output_device_mac_unittest.mm
+++ b/components/viz/service/display_embedder/software_output_device_mac_unittest.mm
@@ -12,8 +12,7 @@
 namespace {
 
 TEST(SoftwareOutputDeviceMacTest, Basics) {
-  std::unique_ptr<SoftwareOutputDeviceMac> device(
-      new SoftwareOutputDeviceMac(gfx::kNullAcceleratedWidget));
+  auto device = std::make_unique<SoftwareOutputDeviceMac>();
   gfx::Size pixel_size(512, 512);
   float scale_factor = 1;
 
diff --git a/components/viz/test/test_gles2_interface.cc b/components/viz/test/test_gles2_interface.cc
index 1ce6737..fca1560 100644
--- a/components/viz/test/test_gles2_interface.cc
+++ b/components/viz/test/test_gles2_interface.cc
@@ -380,10 +380,18 @@
   return GL_NO_ERROR;
 }
 
+size_t TestGLES2Interface::NumTextures() const {
+  return test_context_->NumTextures();
+}
+
 void TestGLES2Interface::set_test_context(TestWebGraphicsContext3D* context) {
   DCHECK(!test_context_);
   test_context_ = context;
   InitializeTestContext(test_context_);
 }
 
+void TestGLES2Interface::set_times_bind_texture_succeeds(int times) {
+  test_context_->set_times_bind_texture_succeeds(times);
+}
+
 }  // namespace viz
diff --git a/components/viz/test/test_gles2_interface.h b/components/viz/test/test_gles2_interface.h
index eb7f76a..ab470fe 100644
--- a/components/viz/test/test_gles2_interface.h
+++ b/components/viz/test/test_gles2_interface.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_VIZ_TEST_TEST_GLES2_INTERFACE_H_
 #define COMPONENTS_VIZ_TEST_TEST_GLES2_INTERFACE_H_
 
+#include <stddef.h>
+
 #include "gpu/command_buffer/client/gles2_interface_stub.h"
 
 namespace viz {
@@ -159,7 +161,10 @@
   void LoseContextCHROMIUM(GLenum current, GLenum other) override;
   GLenum GetGraphicsResetStatusKHR() override;
 
+  size_t NumTextures() const;
+
   void set_test_context(TestWebGraphicsContext3D* context);
+  void set_times_bind_texture_succeeds(int times);
 
  protected:
   virtual void InitializeTestContext(TestWebGraphicsContext3D* context) {}
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 2749fcd1..c527f86 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -160,13 +160,6 @@
   ChildProcessLauncherHelper::ResetRegisteredFilesForTesting();
 }
 
-#if defined(OS_ANDROID)
-// static
-size_t ChildProcessLauncher::GetNumberOfRendererSlots() {
-  return ChildProcessLauncherHelper::GetNumberOfRendererSlots();
-}
-#endif  // OS_ANDROID
-
 ChildProcessLauncher::Client* ChildProcessLauncher::ReplaceClientForTest(
     Client* client) {
   Client* ret = client_;
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index c40e71b..0478755 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -152,11 +152,6 @@
   // support multiple shell context creation in unit_tests.
   static void ResetRegisteredFilesForTesting();
 
-#if defined(OS_ANDROID)
-  // Temporary until crbug.com/693484 is fixed.
-  static size_t GetNumberOfRendererSlots();
-#endif  // OS_ANDROID
-
  private:
   friend class internal::ChildProcessLauncherHelper;
 
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h
index f7a66ff..bdec81b 100644
--- a/content/browser/child_process_launcher_helper.h
+++ b/content/browser/child_process_launcher_helper.h
@@ -179,7 +179,6 @@
   void OnChildProcessStarted(JNIEnv* env,
                              const base::android::JavaParamRef<jobject>& obj,
                              jint handle);
-  static size_t GetNumberOfRendererSlots();
 #endif  // OS_ANDROID
 
  private:
diff --git a/content/browser/child_process_launcher_helper_android.cc b/content/browser/child_process_launcher_helper_android.cc
index ee267ce..1c6c7db 100644
--- a/content/browser/child_process_launcher_helper_android.cc
+++ b/content/browser/child_process_launcher_helper_android.cc
@@ -241,13 +241,6 @@
   PostLaunchOnLauncherThread(std::move(process), launch_result);
 }
 
-// static
-size_t ChildProcessLauncherHelper::GetNumberOfRendererSlots() {
-  return static_cast<size_t>(
-      Java_ChildProcessLauncherHelper_getNumberOfRendererSlots(
-          AttachCurrentThread()));
-}
-
 }  // namespace internal
 
 }  // namespace content
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 917b514..1bde18a 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -255,7 +255,7 @@
 #elif defined(USE_X11)
   return std::make_unique<viz::SoftwareOutputDeviceX11>(widget);
 #elif defined(OS_MACOSX)
-  return std::make_unique<viz::SoftwareOutputDeviceMac>(widget);
+  return std::make_unique<viz::SoftwareOutputDeviceMac>();
 #else
   NOTREACHED();
   return std::unique_ptr<viz::SoftwareOutputDevice>();
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 73fcc5e..7a3e181 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -392,7 +392,8 @@
   return Response::Error("Not supported");
 }
 
-Response TargetHandler::DisposeBrowserContext(const std::string& context_id) {
+Response TargetHandler::DisposeBrowserContext(const std::string& context_id,
+                                              bool* out_success) {
   return Response::Error("Not supported");
 }
 
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index 8b6212e4..6bb18ca 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -63,7 +63,8 @@
   Response CloseTarget(const std::string& target_id,
                        bool* out_success) override;
   Response CreateBrowserContext(std::string* out_context_id) override;
-  Response DisposeBrowserContext(const std::string& context_id) override;
+  Response DisposeBrowserContext(const std::string& context_id,
+                                 bool* out_success) override;
   Response CreateTarget(const std::string& url,
                         Maybe<int> width,
                         Maybe<int> height,
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 034a62f..e013d96a 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -4054,7 +4054,7 @@
   contents()->CommitPendingNavigation();
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_controller.CopyStateFrom(controller, true);
 
@@ -4103,7 +4103,7 @@
   EXPECT_EQ(instance1, instance2);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
@@ -4141,7 +4141,7 @@
   contents()->CommitPendingNavigation();
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
@@ -4169,7 +4169,7 @@
   NavigateAndCommit(url2);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->NavigateAndCommit(url4);
@@ -4199,7 +4199,7 @@
   NavigateAndCommit(url2);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->NavigateAndCommit(url4);
@@ -4233,7 +4233,7 @@
   contents()->CommitPendingNavigation();
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_controller.LoadURL(
@@ -4267,7 +4267,7 @@
   NavigateAndCommit(url1);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url2a);
   // Simulate a client redirect, which has the same page ID as entry 2a.
@@ -4308,7 +4308,7 @@
   controller.GoBack();
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
@@ -4395,7 +4395,7 @@
   NavigateAndCommit(url3);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url4);
   other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
@@ -4436,7 +4436,7 @@
   EXPECT_EQ(instance1, instance2);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
@@ -4479,7 +4479,7 @@
   NavigateAndCommit(url3);
 
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url4);
   other_contents->ExpectSetHistoryOffsetAndLength(2, 3);
@@ -4521,7 +4521,7 @@
 
   // Create a WebContents with restored entries.
   std::unique_ptr<TestWebContents> source_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& source_controller =
       source_contents->GetController();
   source_controller.Restore(entries.size() - 1,
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 46d42a11..bd71bd6 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -763,19 +763,19 @@
 class RenderViewHostDestroyer : public WebContentsObserver {
  public:
   RenderViewHostDestroyer(RenderViewHost* render_view_host,
-                          WebContents* web_contents)
+                          std::unique_ptr<WebContents> web_contents)
       : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
         render_view_host_(render_view_host),
-        web_contents_(web_contents) {}
+        web_contents_(std::move(web_contents)) {}
 
   void RenderViewDeleted(RenderViewHost* render_view_host) override {
     if (render_view_host == render_view_host_)
-      delete web_contents_;
+      web_contents_.reset();
   }
 
  private:
   RenderViewHost* render_view_host_;
-  WebContents* web_contents_;
+  std::unique_ptr<WebContents> web_contents_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestroyer);
 };
@@ -797,11 +797,11 @@
   // Create one more tab and navigate to kUrl1.  web_contents is not
   // wrapped as scoped_ptr since it intentionally deleted by destroyer
   // below as part of this test.
-  TestWebContents* web_contents =
+  std::unique_ptr<TestWebContents> web_contents =
       TestWebContents::Create(browser_context(), ntp_rfh->GetSiteInstance());
   web_contents->NavigateAndCommit(kUrl1);
   RenderViewHostDestroyer destroyer(ntp_rfh->GetRenderViewHost(),
-                                    web_contents);
+                                    std::move(web_contents));
 
   // This causes the first tab to navigate to kUrl2, which destroys
   // the ntp_rfh in ShutdownRenderViewHostsInSiteInstance(). When
diff --git a/content/browser/frame_host/render_widget_host_view_guest_unittest.cc b/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
index 799a17c..6fcf2a7 100644
--- a/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
+++ b/content/browser/frame_host/render_widget_host_view_guest_unittest.cc
@@ -147,8 +147,7 @@
     browser_context_.reset(new TestBrowserContext);
     MockRenderProcessHost* process_host =
         new MockRenderProcessHost(browser_context_.get());
-    web_contents_.reset(
-        TestWebContents::Create(browser_context_.get(), nullptr));
+    web_contents_ = TestWebContents::Create(browser_context_.get(), nullptr);
     // We don't own the BPG, the WebContents does.
     browser_plugin_guest_ = new TestBrowserPluginGuest(
         web_contents_.get(), &browser_plugin_guest_delegate_);
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 0fcaeed..469e35d2 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -471,8 +471,8 @@
     browser_context_.reset(new TestBrowserContext());
     scoped_refptr<SiteInstance> site_instance =
         SiteInstance::Create(browser_context_.get());
-    web_contents_.reset(
-        TestWebContents::Create(browser_context_.get(), site_instance.get()));
+    web_contents_ =
+        TestWebContents::Create(browser_context_.get(), site_instance.get());
     SetUpResourceLoaderForUrl(test_redirect_url());
   }
 
diff --git a/content/browser/media/media_source_browsertest.cc b/content/browser/media/media_source_browsertest.cc
index e5571a3b..5e3cb000 100644
--- a/content/browser/media/media_source_browsertest.cc
+++ b/content/browser/media/media_source_browsertest.cc
@@ -24,14 +24,12 @@
 #endif
 const char kWebMVideoOnly[] = "video/webm; codecs=\"vp8\"";
 const char kWebMAudioVideo[] = "video/webm; codecs=\"vorbis, vp8\"";
-
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 const char kMp4FlacAudioOnly[] = "audio/mp4; codecs=\"flac\"";
 
-#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
+#if BUILDFLAG(USE_PROPRIETARY_CODECS) && \
+    BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
 const char kMp2tAudioVideo[] = "video/mp2t; codecs=\"mp4a.40.2, avc1.42E01E\"";
 #endif
-#endif
 
 namespace content {
 
@@ -51,7 +49,6 @@
     command_line->AppendSwitchASCII(
         switches::kAutoplayPolicy,
         switches::autoplay::kNoUserGestureRequiredPolicy);
-    scoped_feature_list_.InitAndDisableFeature(media::kMseFlacInIsobmff);
   }
 
  protected:
@@ -121,12 +118,11 @@
                    true);
 }
 
-IN_PROC_BROWSER_TEST_F(MediaSourceTest,
-                       Playback_AudioOnly_FLAC_MP4_Unsupported) {
-  // The feature is disabled by test setup, so verify playback failure.
-  TestSimplePlayback("bear-flac_frag.mp4", kMp4FlacAudioOnly, media::kFailed);
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
+IN_PROC_BROWSER_TEST_F(MediaSourceTest, Playback_AudioOnly_FLAC_MP4) {
+  TestSimplePlayback("bear-flac_frag.mp4", kMp4FlacAudioOnly, media::kEnded);
 }
-#endif
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
@@ -136,24 +132,4 @@
 #endif
 #endif
 
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-class MediaSourceFlacInIsobmffTest : public content::MediaSourceTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    command_line->AppendSwitchASCII(
-        switches::kAutoplayPolicy,
-        switches::autoplay::kNoUserGestureRequiredPolicy);
-
-    // Enable MSE FLAC-in-MP4 feature.
-    scoped_feature_list_.InitAndEnableFeature(media::kMseFlacInIsobmff);
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(MediaSourceFlacInIsobmffTest,
-                       Playback_AudioOnly_FLAC_MP4_Supported) {
-  // The feature is enabled by test setup, so verify playback success.
-  TestSimplePlayback("bear-flac_frag.mp4", kMp4FlacAudioOnly, media::kEnded);
-}
-#endif
-
 }  // namespace content
diff --git a/content/browser/media/session/audio_focus_manager_unittest.cc b/content/browser/media/session/audio_focus_manager_unittest.cc
index a0bb13d1..459ce508 100644
--- a/content/browser/media/session/audio_focus_manager_unittest.cc
+++ b/content/browser/media/session/audio_focus_manager_unittest.cc
@@ -102,7 +102,7 @@
     session->AbandonSystemAudioFocusIfNeeded();
   }
 
-  WebContents* CreateWebContents() {
+  std::unique_ptr<WebContents> CreateWebContents() {
     return TestWebContents::Create(browser_context_.get(),
         SiteInstance::SiteInstance::Create(browser_context_.get()));
   }
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.h b/content/browser/renderer_host/browser_compositor_view_mac.h
index 1fbbedd..7f0ce8a 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.h
+++ b/content/browser/renderer_host/browser_compositor_view_mac.h
@@ -197,12 +197,6 @@
   gfx::Size dfh_size_dip_;
   display::Display dfh_display_;
 
-  // The viz::ParentLocalSurfaceIdAllocator for the ui::Compositor dispenses
-  // viz::LocalSurfaceIds that are renderered into by the ui::Compositor.
-  viz::ParentLocalSurfaceIdAllocator compositor_local_surface_id_allocator_;
-  gfx::Size compositor_size_pixels_;
-  float compositor_scale_factor_ = 1.f;
-
   // Used to disable screen updates while resizing (because frames are drawn in
   // the GPU process, they can end up appearing on-screen before our window
   // resizes).
diff --git a/content/browser/renderer_host/browser_compositor_view_mac.mm b/content/browser/renderer_host/browser_compositor_view_mac.mm
index b83bbad5..c1c7a42 100644
--- a/content/browser/renderer_host/browser_compositor_view_mac.mm
+++ b/content/browser/renderer_host/browser_compositor_view_mac.mm
@@ -75,6 +75,8 @@
   ui::AcceleratedWidgetMac* accelerated_widget_mac() {
     return accelerated_widget_mac_.get();
   }
+  const gfx::Size pixel_size() const { return size_pixels_; }
+  float scale_factor() const { return scale_factor_; }
 
   // Suspend will prevent the compositor from producing new frames. This should
   // be called to avoid creating spurious frames while changing state.
@@ -82,6 +84,20 @@
   void Suspend();
   void Unsuspend();
 
+  // Update the compositor's surface information, set |root_layer| to be the
+  // compositor root layer, and resize |root_layer|.
+  void UpdateSurfaceAndUnsuspend(const gfx::Size& size_pixels,
+                                 float scale_factor,
+                                 ui::Layer* root_layer);
+  // Invalidate the compositor's surface information.
+  void InvalidateSurface();
+
+  // The viz::ParentLocalSurfaceIdAllocator for the ui::Compositor dispenses
+  // viz::LocalSurfaceIds that are renderered into by the ui::Compositor.
+  viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_;
+  gfx::Size size_pixels_;
+  float scale_factor_ = 1.f;
+
  private:
   RecyclableCompositorMac();
 
@@ -129,6 +145,32 @@
   compositor_suspended_lock_ = nullptr;
 }
 
+void RecyclableCompositorMac::UpdateSurfaceAndUnsuspend(
+    const gfx::Size& size_pixels,
+    float scale_factor,
+    ui::Layer* root_layer) {
+  if (size_pixels != size_pixels_ || scale_factor != scale_factor_) {
+    size_pixels_ = size_pixels;
+    scale_factor_ = scale_factor;
+    compositor()->SetScaleAndSize(scale_factor_, size_pixels_,
+                                  local_surface_id_allocator_.GenerateId());
+  }
+  compositor()->SetRootLayer(root_layer);
+  root_layer->SetBounds(
+      gfx::Rect(gfx::ConvertSizeToDIP(scale_factor, size_pixels)));
+  Unsuspend();
+}
+
+void RecyclableCompositorMac::InvalidateSurface() {
+  size_pixels_ = gfx::Size();
+  scale_factor_ = 1.f;
+  local_surface_id_allocator_.Invalidate();
+  compositor()->SetScaleAndSize(
+      scale_factor_, size_pixels_,
+      local_surface_id_allocator_.GetCurrentLocalSurfaceId());
+  compositor()->SetRootLayer(nullptr);
+}
+
 void RecyclableCompositorMac::OnCompositingDidCommit(
     ui::Compositor* compositor_that_did_commit) {
   DCHECK_EQ(compositor_that_did_commit, compositor());
@@ -353,7 +395,6 @@
   // Transition HasNoCompositor -> HasDetachedCompositor.
   if (state_ == HasNoCompositor && new_state != HasNoCompositor) {
     recyclable_compositor_ = RecyclableCompositorMac::Create();
-    recyclable_compositor_->compositor()->SetRootLayer(root_layer_.get());
     recyclable_compositor_->compositor()->SetBackgroundColor(background_color_);
     recyclable_compositor_->compositor()->SetDisplayColorSpace(
         dfh_display_.color_space());
@@ -372,17 +413,9 @@
     // now (if one is not ready, the compositor will unsuspend on first surface
     // activation).
     if (delegated_frame_host_->HasSavedFrame()) {
-      if (compositor_scale_factor_ != dfh_display_.device_scale_factor() ||
-          compositor_size_pixels_ != dfh_size_pixels_) {
-        compositor_scale_factor_ = dfh_display_.device_scale_factor();
-        compositor_size_pixels_ = dfh_size_pixels_;
-        root_layer_->SetBounds(gfx::Rect(gfx::ConvertSizeToDIP(
-            compositor_scale_factor_, compositor_size_pixels_)));
-        recyclable_compositor_->compositor()->SetScaleAndSize(
-            compositor_scale_factor_, compositor_size_pixels_,
-            compositor_local_surface_id_allocator_.GenerateId());
-      }
-      recyclable_compositor_->Unsuspend();
+      recyclable_compositor_->UpdateSurfaceAndUnsuspend(
+          dfh_size_pixels_, dfh_display_.device_scale_factor(),
+          root_layer_.get());
     }
 
     state_ = HasAttachedCompositor;
@@ -403,13 +436,7 @@
   // Transition HasDetachedCompositor -> HasNoCompositor.
   if (state_ == HasDetachedCompositor && new_state == HasNoCompositor) {
     recyclable_compositor_->accelerated_widget_mac()->ResetNSView();
-    compositor_scale_factor_ = 1.f;
-    compositor_size_pixels_ = gfx::Size();
-    compositor_local_surface_id_allocator_.Invalidate();
-    recyclable_compositor_->compositor()->SetScaleAndSize(
-        compositor_scale_factor_, compositor_size_pixels_,
-        compositor_local_surface_id_allocator_.GetCurrentLocalSurfaceId());
-    recyclable_compositor_->compositor()->SetRootLayer(nullptr);
+    recyclable_compositor_->InvalidateSurface();
     RecyclableCompositorMac::Recycle(std::move(recyclable_compositor_));
     state_ = HasNoCompositor;
   }
@@ -469,27 +496,17 @@
   if (!recyclable_compositor_)
     return;
 
-  recyclable_compositor_->Unsuspend();
-
-  // Resize the compositor to match the current frame size, if needed.
-  if (compositor_size_pixels_ == surface_info.size_in_pixels() &&
-      compositor_scale_factor_ == surface_info.device_scale_factor()) {
-    return;
-  }
-  compositor_size_pixels_ = surface_info.size_in_pixels();
-  compositor_scale_factor_ = surface_info.device_scale_factor();
-  root_layer_->SetBounds(gfx::Rect(gfx::ConvertSizeToDIP(
-      compositor_scale_factor_, compositor_size_pixels_)));
-  recyclable_compositor_->compositor()->SetScaleAndSize(
-      compositor_scale_factor_, compositor_size_pixels_,
-      compositor_local_surface_id_allocator_.GenerateId());
+  recyclable_compositor_->UpdateSurfaceAndUnsuspend(
+      surface_info.size_in_pixels(), surface_info.device_scale_factor(),
+      root_layer_.get());
 
   // Disable screen updates until the frame of the new size appears (because the
   // content is drawn in the GPU process, it may change before we want it to).
   if (repaint_state_ == RepaintState::Paused) {
     bool compositor_is_nsview_size =
-        compositor_size_pixels_ == dfh_size_pixels_ &&
-        compositor_scale_factor_ == dfh_display_.device_scale_factor();
+        recyclable_compositor_->pixel_size() == dfh_size_pixels_ &&
+        recyclable_compositor_->scale_factor() ==
+            dfh_display_.device_scale_factor();
     if (compositor_is_nsview_size || repaint_auto_resize_enabled_) {
       NSDisableScreenUpdates();
       repaint_state_ = RepaintState::ScreenUpdatesDisabled;
diff --git a/content/browser/renderer_host/frame_sink_provider_impl.cc b/content/browser/renderer_host/frame_sink_provider_impl.cc
index 8b1215bfdb..b984d94 100644
--- a/content/browser/renderer_host/frame_sink_provider_impl.cc
+++ b/content/browser/renderer_host/frame_sink_provider_impl.cc
@@ -27,7 +27,21 @@
 void FrameSinkProviderImpl::CreateForWidget(
     int32_t widget_id,
     viz::mojom::CompositorFrameSinkRequest compositor_frame_sink_request,
-    viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client,
+    viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client) {
+  RenderWidgetHostImpl* render_widget_host_impl =
+      RenderWidgetHostImpl::FromID(process_id_, widget_id);
+  if (!render_widget_host_impl) {
+    DLOG(ERROR) << "No RenderWidgetHost exists with id " << widget_id
+                << " in process " << process_id_;
+    return;
+  }
+  render_widget_host_impl->RequestCompositorFrameSink(
+      std::move(compositor_frame_sink_request),
+      std::move(compositor_frame_sink_client));
+}
+
+void FrameSinkProviderImpl::RegisterRenderFrameMetadataObserver(
+    int32_t widget_id,
     mojom::RenderFrameMetadataObserverClientRequest
         render_frame_metadata_observer_client_request,
     mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer) {
@@ -38,9 +52,7 @@
                 << " in process " << process_id_;
     return;
   }
-  render_widget_host_impl->RequestCompositorFrameSink(
-      std::move(compositor_frame_sink_request),
-      std::move(compositor_frame_sink_client),
+  render_widget_host_impl->RegisterRenderFrameMetadataObserver(
       std::move(render_frame_metadata_observer_client_request),
       std::move(render_frame_metadata_observer));
 }
diff --git a/content/browser/renderer_host/frame_sink_provider_impl.h b/content/browser/renderer_host/frame_sink_provider_impl.h
index e717c44..05949c53 100644
--- a/content/browser/renderer_host/frame_sink_provider_impl.h
+++ b/content/browser/renderer_host/frame_sink_provider_impl.h
@@ -25,7 +25,10 @@
   void CreateForWidget(
       int32_t widget_id,
       viz::mojom::CompositorFrameSinkRequest compositor_frame_sink_request,
-      viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client,
+      viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client)
+      override;
+  void RegisterRenderFrameMetadataObserver(
+      int32_t widget_id,
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
       mojom::RenderFrameMetadataObserverPtr observer) override;
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.cc b/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
index d16a615..c0aec90 100644
--- a/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
+++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.cc
@@ -66,6 +66,12 @@
 void RenderFrameMetadataProviderImpl::OnRenderFrameMetadataChanged(
     uint32_t frame_token,
     const cc::RenderFrameMetadata& metadata) {
+  if (metadata.local_surface_id != last_local_surface_id_) {
+    last_local_surface_id_ = metadata.local_surface_id;
+    for (Observer& observer : observers_)
+      observer.OnLocalSurfaceIdChanged(metadata);
+  }
+
   // Both RenderFrameMetadataProviderImpl and FrameTokenMessageQueue are owned
   // by the same RenderWidgetHostImpl. During shutdown the queue is cleared
   // without running the callbacks.
diff --git a/content/browser/renderer_host/render_frame_metadata_provider_impl.h b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
index 48ab56154..fb101fb 100644
--- a/content/browser/renderer_host/render_frame_metadata_provider_impl.h
+++ b/content/browser/renderer_host/render_frame_metadata_provider_impl.h
@@ -67,6 +67,8 @@
 
   cc::RenderFrameMetadata last_render_frame_metadata_;
 
+  base::Optional<viz::LocalSurfaceId> last_local_surface_id_;
+
   // Not owned.
   FrameTokenMessageQueue* const frame_token_message_queue_;
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ece068e..ddda2189 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1273,13 +1273,7 @@
   // On Android we don't maintain a limit of renderer process hosts - we are
   // happy with keeping a lot of these, as long as the number of live renderer
   // processes remains reasonable, and on Android the OS takes care of that.
-  // TODO(boliu): This is a short term workaround before ChildProcessLauncher
-  // can actively kill child processes in LRU order. Bug and process is tracked
-  // in crbug.com/693484. Note this workaround is not perfect and still has
-  // corner case problems.
-  static const size_t kNumRendererSlots =
-      ChildProcessLauncher::GetNumberOfRendererSlots();
-  return kNumRendererSlots;
+  return std::numeric_limits<size_t>::max();
 #endif
 #if defined(OS_CHROMEOS)
   // On Chrome OS new renderer processes are very cheap and there's no OS
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index b8906bb6..ff8cef7 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -38,10 +38,6 @@
 class UkmRecorder;
 }
 
-namespace viz {
-class LocalSurfaceId;
-}
-
 namespace content {
 
 class BrowserAccessibilityManager;
@@ -80,10 +76,8 @@
                                       bool width_changed) {}
 
   // The contents auto-resized and the container should match it.
-  virtual void ResizeDueToAutoResize(
-      RenderWidgetHostImpl* render_widget_host,
-      const gfx::Size& new_size,
-      const viz::LocalSurfaceId& local_surface_id) {}
+  virtual void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host,
+                                     const gfx::Size& new_size) {}
 
   // Callback to give the browser a chance to handle the specified keyboard
   // event before sending it to the renderer. See enum for details on return
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 4f629c96..35e004dc 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2141,47 +2141,42 @@
 
 void RenderWidgetHostImpl::OnResizeOrRepaintACK(
     const ViewHostMsg_ResizeOrRepaint_ACK_Params& params) {
-  TRACE_EVENT0("renderer_host", "RenderWidgetHostImpl::OnResizeOrRepaintACK");
-
-  // Update our knowledge of the RenderWidget's size.
-  current_size_ = params.view_size;
-
-  resize_ack_pending_ = false;
-
-  DCHECK(!params.view_size.IsEmpty());
-
-  DidCompleteResizeOrRepaint(params);
-
-  if (auto_resize_enabled_ && view_) {
-    viz::ScopedSurfaceIdAllocator scoped_allocator =
-        view_->ResizeDueToAutoResize(params.view_size,
-                                     *params.child_allocated_local_surface_id);
-
-    if (delegate_) {
-      delegate_->ResizeDueToAutoResize(
-          this, params.view_size, *params.child_allocated_local_surface_id);
-    }
-  }
+  DidUpdateVisualProperties(params.view_size,
+                            params.child_allocated_local_surface_id);
 }
 
-void RenderWidgetHostImpl::DidCompleteResizeOrRepaint(
-    const ViewHostMsg_ResizeOrRepaint_ACK_Params& params) {
+void RenderWidgetHostImpl::DidUpdateVisualProperties(
+    const gfx::Size& viewport_size_in_dip,
+    const base::Optional<viz::LocalSurfaceId>&
+        child_allocated_local_surface_id) {
   TRACE_EVENT0("renderer_host",
-               "RenderWidgetHostImpl::DidCompleteResizeOrRepaint");
+               "RenderWidgetHostImpl::DidUpdateVisualProperties");
+
+  // Update our knowledge of the RenderWidget's size.
+  DCHECK(!viewport_size_in_dip.IsEmpty());
+  // TODO(fsamuel): The fact that we translate the viewport_size from pixels
+  // to DIP is concerning. This could result in invariants violations.
+  current_size_ = viewport_size_in_dip;
+
+  resize_ack_pending_ = false;
 
   NotificationService::current()->Notify(
       NOTIFICATION_RENDER_WIDGET_HOST_DID_COMPLETE_RESIZE_OR_REPAINT,
       Source<RenderWidgetHost>(this), NotificationService::NoDetails());
 
-  // We don't need to update the view if the view is hidden. We must do this
-  // early return after the ACK is sent, however, or the renderer will not send
-  // us more data.
-  if (is_hidden_)
-    return;
-
   // If we got an ack, then perhaps we have another change of visual properties
   // to send?
-  SynchronizeVisualProperties();
+  if (!is_hidden_)
+    SynchronizeVisualProperties();
+
+  if (auto_resize_enabled_ && view_) {
+    viz::ScopedSurfaceIdAllocator scoped_allocator =
+        view_->ResizeDueToAutoResize(viewport_size_in_dip,
+                                     *child_allocated_local_surface_id);
+
+    if (delegate_)
+      delegate_->ResizeDueToAutoResize(this, viewport_size_in_dip);
+  }
 }
 
 void RenderWidgetHostImpl::OnSetCursor(const WebCursor& cursor) {
@@ -2743,13 +2738,7 @@
 
 void RenderWidgetHostImpl::RequestCompositorFrameSink(
     viz::mojom::CompositorFrameSinkRequest compositor_frame_sink_request,
-    viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client,
-    mojom::RenderFrameMetadataObserverClientRequest
-        render_frame_metadata_observer_client_request,
-    mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer) {
-  render_frame_metadata_provider_.Bind(
-      std::move(render_frame_metadata_observer_client_request),
-      std::move(render_frame_metadata_observer));
+    viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client) {
   if (enable_viz_) {
       // Connects the viz process end of CompositorFrameSink message pipes. The
       // renderer compositor may request a new CompositorFrameSink on context
@@ -2785,6 +2774,15 @@
   renderer_compositor_frame_sink_ = std::move(compositor_frame_sink_client);
 }
 
+void RenderWidgetHostImpl::RegisterRenderFrameMetadataObserver(
+    mojom::RenderFrameMetadataObserverClientRequest
+        render_frame_metadata_observer_client_request,
+    mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer) {
+  render_frame_metadata_provider_.Bind(
+      std::move(render_frame_metadata_observer_client_request),
+      std::move(render_frame_metadata_observer));
+}
+
 bool RenderWidgetHostImpl::HasGestureStopped() {
   return !input_router_->HasPendingEvents();
 }
@@ -3102,4 +3100,13 @@
     touch_emulator_->SetDoubleTapSupportForPageEnabled(!is_mobile_optimized);
 }
 
+void RenderWidgetHostImpl::OnLocalSurfaceIdChanged(
+    const cc::RenderFrameMetadata& metadata) {
+  if (!enable_surface_synchronization_)
+    return;
+  gfx::Size viewport_size_in_dip = gfx::ScaleToCeiledSize(
+      metadata.viewport_size_in_pixels, 1.f / metadata.device_scale_factor);
+  DidUpdateVisualProperties(viewport_size_in_dip, metadata.local_surface_id);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 7cae9ef7..57dacf6 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -609,7 +609,9 @@
 
   void RequestCompositorFrameSink(
       viz::mojom::CompositorFrameSinkRequest compositor_frame_sink_request,
-      viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client,
+      viz::mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client);
+
+  void RegisterRenderFrameMetadataObserver(
       mojom::RenderFrameMetadataObserverClientRequest
           render_frame_metadata_observer_client_request,
       mojom::RenderFrameMetadataObserverPtr render_frame_metadata_observer);
@@ -817,9 +819,10 @@
   void OnFrameSwapMessagesReceived(uint32_t frame_token,
                                    std::vector<IPC::Message> messages);
 
-  // Called after resize or repaint has completed in the renderer.
-  void DidCompleteResizeOrRepaint(
-      const ViewHostMsg_ResizeOrRepaint_ACK_Params& params);
+  // Called when visual properties have changed in the renderer.
+  void DidUpdateVisualProperties(const gfx::Size& viewport_size_in_dip,
+                                 const base::Optional<viz::LocalSurfaceId>&
+                                     child_allocated_local_surface_id);
 
   // Give key press listeners a chance to handle this key press. This allow
   // widgets that don't have focus to still handle key presses.
@@ -885,6 +888,8 @@
   // RenderFrameMetadataProvider::Observer implementation.
   void OnRenderFrameMetadataChanged() override;
   void OnRenderFrameSubmission() override {}
+  void OnLocalSurfaceIdChanged(
+      const cc::RenderFrameMetadata& metadata) override;
 
   // true if a renderer has once been valid. We use this flag to display a sad
   // tab only when we lose our renderer and not if a paint occurs during
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index e3d8341..4156c085 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -719,7 +719,9 @@
             std::move(render_frame_metadata_observer_client_info));
 
     host_->RequestCompositorFrameSink(
-        std::move(sink_request), std::move(renderer_compositor_frame_sink_ptr_),
+        std::move(sink_request),
+        std::move(renderer_compositor_frame_sink_ptr_));
+    host_->RegisterRenderFrameMetadataObserver(
         std::move(render_frame_metadata_observer_client_request),
         std::move(renderer_render_frame_metadata_observer_ptr));
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index dc00f30..7dad684b 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -111,6 +111,9 @@
 
 void RenderWidgetHostViewBase::OnRenderFrameSubmission() {}
 
+void RenderWidgetHostViewBase::OnLocalSurfaceIdChanged(
+    const cc::RenderFrameMetadata& metadata) {}
+
 void RenderWidgetHostViewBase::SetBackgroundColorToDefault() {
   SetBackgroundColor(SK_ColorWHITE);
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index a7dd53e..cd7fba6d 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -150,6 +150,8 @@
   // RenderFrameMetadataProvider::Observer
   void OnRenderFrameMetadataChanged() override;
   void OnRenderFrameSubmission() override;
+  void OnLocalSurfaceIdChanged(
+      const cc::RenderFrameMetadata& metadata) override;
 
   void SetPopupType(blink::WebPopupType popup_type);
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 6cd9b0f..eed2f40e 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -11700,6 +11700,60 @@
   EXPECT_LE(compositing_rect.y(), expected_offset + 2);
 }
 
+// Verify that OOPIF select element popup menu coordinates account for scroll
+// offset in containers embedding frame.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, PopupMenuInTallIframeTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "/frame_tree/page_with_tall_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL(
+      "baz.com", "/site_isolation/page-with-select.html"));
+  NavigateFrameToURL(child_node, site_url);
+
+  scoped_refptr<UpdateViewportIntersectionMessageFilter> filter =
+      new UpdateViewportIntersectionMessageFilter();
+  root->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+  // Position the select element so that it is out of the viewport, then scroll
+  // it into view.
+  EXPECT_TRUE(ExecuteScript(
+      child_node, "document.querySelector('select').style.top='2000px';"));
+  EXPECT_TRUE(ExecuteScript(root, "window.scrollTo(0, 1900);"));
+
+  // Wait for a viewport intersection update to be dispatched to the child, and
+  // ensure it is processed by the browser before continuing.
+  filter->Wait();
+  {
+    // This yields the UI thread in order to ensure that the new viewport
+    // intersection is sent to the to child renderer before the mouse click
+    // below.
+    base::RunLoop loop;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  loop.QuitClosure());
+    loop.Run();
+  }
+
+  scoped_refptr<ShowWidgetMessageFilter> show_widget_filter =
+      new ShowWidgetMessageFilter();
+  child_node->current_frame_host()->GetProcess()->AddFilter(
+      show_widget_filter.get());
+
+  SimulateMouseClick(child_node->current_frame_host()->GetRenderWidgetHost(),
+                     55, 2005);
+
+  // Dismiss the popup.
+  SimulateMouseClick(child_node->current_frame_host()->GetRenderWidgetHost(), 1,
+                     1);
+
+  // The test passes if this wait returns, indicating that the popup was
+  // scrolled into view and the OOPIF renderer displayed it. Other tests verify
+  // the correctness of popup menu coordinates.
+  show_widget_filter->Wait();
+}
+
 namespace {
 
 // Helper class to intercept DidCommitProvisionalLoad messages and inject a
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 4ccf2aa..e4fc772b 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -3219,76 +3219,6 @@
   CreateContextMenuTestHelper(shell(), embedded_test_server());
 }
 
-class ShowWidgetMessageFilter : public content::BrowserMessageFilter {
- public:
-  ShowWidgetMessageFilter()
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-      : content::BrowserMessageFilter(FrameMsgStart),
-#else
-      : content::BrowserMessageFilter(ViewMsgStart),
-#endif
-        message_loop_runner_(new content::MessageLoopRunner) {
-  }
-
-  bool OnMessageReceived(const IPC::Message& message) override {
-    IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message)
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-      IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
-#else
-      IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
-#endif
-    IPC_END_MESSAGE_MAP()
-    return false;
-  }
-
-  gfx::Rect last_initial_rect() const { return initial_rect_; }
-
-  int last_routing_id() const { return routing_id_; }
-
-  void Wait() {
-    initial_rect_ = gfx::Rect();
-    routing_id_ = MSG_ROUTING_NONE;
-    message_loop_runner_->Run();
-  }
-
-  void Reset() {
-    initial_rect_ = gfx::Rect();
-    routing_id_ = MSG_ROUTING_NONE;
-    message_loop_runner_ = new content::MessageLoopRunner;
-  }
-
- private:
-  ~ShowWidgetMessageFilter() override {}
-
-  void OnShowWidget(int route_id, const gfx::Rect& initial_rect) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::BindOnce(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
-                       route_id, initial_rect));
-  }
-
-#if defined(OS_MACOSX) || defined(OS_ANDROID)
-  void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
-                   MSG_ROUTING_NONE, params.bounds));
-  }
-#endif
-
-  void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect) {
-    initial_rect_ = initial_rect;
-    routing_id_ = route_id;
-    message_loop_runner_->Quit();
-  }
-
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  gfx::Rect initial_rect_;
-  int routing_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter);
-};
-
 // Test that clicking a select element in an out-of-process iframe creates
 // a popup menu in the correct position.
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, PopupMenuTest) {
diff --git a/content/browser/web_contents/aura/gesture_nav_simple_unittest.cc b/content/browser/web_contents/aura/gesture_nav_simple_unittest.cc
index 9864bef..f3da97e 100644
--- a/content/browser/web_contents/aura/gesture_nav_simple_unittest.cc
+++ b/content/browser/web_contents/aura/gesture_nav_simple_unittest.cc
@@ -19,16 +19,24 @@
 // A subclass of TestWebContents that offers a fake content window.
 class GestureNavTestWebContents : public TestWebContents {
  public:
+  explicit GestureNavTestWebContents(
+      BrowserContext* browser_context,
+      std::unique_ptr<aura::Window> fake_native_view,
+      std::unique_ptr<aura::Window> fake_contents_window)
+      : TestWebContents(browser_context),
+        fake_native_view_(std::move(fake_native_view)),
+        fake_contents_window_(std::move(fake_contents_window)) {}
   ~GestureNavTestWebContents() override {}
 
-  static GestureNavTestWebContents* Create(
+  static std::unique_ptr<GestureNavTestWebContents> Create(
       BrowserContext* browser_context,
       scoped_refptr<SiteInstance> instance,
       std::unique_ptr<aura::Window> fake_native_view,
       std::unique_ptr<aura::Window> fake_contents_window) {
-    auto* web_contents = new GestureNavTestWebContents(
-        browser_context, std::move(fake_native_view),
-        std::move(fake_contents_window));
+    std::unique_ptr<GestureNavTestWebContents> web_contents =
+        std::make_unique<GestureNavTestWebContents>(
+            browser_context, std::move(fake_native_view),
+            std::move(fake_contents_window));
     web_contents->Init(
         WebContents::CreateParams(browser_context, std::move(instance)));
     return web_contents;
@@ -41,15 +49,6 @@
     return fake_contents_window_.get();
   }
 
- protected:
-  explicit GestureNavTestWebContents(
-      BrowserContext* browser_context,
-      std::unique_ptr<aura::Window> fake_native_view,
-      std::unique_ptr<aura::Window> fake_contents_window)
-      : TestWebContents(browser_context),
-        fake_native_view_(std::move(fake_native_view)),
-        fake_contents_window_(std::move(fake_contents_window)) {}
-
  private:
   std::unique_ptr<aura::Window> fake_native_view_;
   std::unique_ptr<aura::Window> fake_contents_window_;
diff --git a/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc b/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc
index 64c159c..a592c0b7 100644
--- a/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc
+++ b/content/browser/web_contents/aura/overscroll_navigation_overlay_unittest.cc
@@ -71,16 +71,25 @@
 // A subclass of TestWebContents that offers a fake content window.
 class OverscrollTestWebContents : public TestWebContents {
  public:
+  explicit OverscrollTestWebContents(
+      BrowserContext* browser_context,
+      std::unique_ptr<aura::Window> fake_native_view,
+      std::unique_ptr<aura::Window> fake_contents_window)
+      : TestWebContents(browser_context),
+        fake_native_view_(std::move(fake_native_view)),
+        fake_contents_window_(std::move(fake_contents_window)),
+        is_being_destroyed_(false) {}
   ~OverscrollTestWebContents() override {}
 
-  static OverscrollTestWebContents* Create(
+  static std::unique_ptr<OverscrollTestWebContents> Create(
       BrowserContext* browser_context,
       scoped_refptr<SiteInstance> instance,
       std::unique_ptr<aura::Window> fake_native_view,
       std::unique_ptr<aura::Window> fake_contents_window) {
-    OverscrollTestWebContents* web_contents = new OverscrollTestWebContents(
-        browser_context, std::move(fake_native_view),
-        std::move(fake_contents_window));
+    std::unique_ptr<OverscrollTestWebContents> web_contents =
+        std::make_unique<OverscrollTestWebContents>(
+            browser_context, std::move(fake_native_view),
+            std::move(fake_contents_window));
     web_contents->Init(
         WebContents::CreateParams(browser_context, std::move(instance)));
     return web_contents;
@@ -100,16 +109,6 @@
 
   bool IsBeingDestroyed() const override { return is_being_destroyed_; }
 
- protected:
-  explicit OverscrollTestWebContents(
-      BrowserContext* browser_context,
-      std::unique_ptr<aura::Window> fake_native_view,
-      std::unique_ptr<aura::Window> fake_contents_window)
-      : TestWebContents(browser_context),
-        fake_native_view_(std::move(fake_native_view)),
-        fake_contents_window_(std::move(fake_contents_window)),
-        is_being_destroyed_(false) {}
-
  private:
   std::unique_ptr<aura::Window> fake_native_view_;
   std::unique_ptr<aura::Window> fake_contents_window_;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 3a9d68d..189b3f0 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -266,8 +266,7 @@
 
 std::unique_ptr<WebContents> WebContents::Create(
     const WebContents::CreateParams& params) {
-  return base::WrapUnique(
-      WebContentsImpl::CreateWithOpener(params, FindOpenerRFH(params)));
+  return WebContentsImpl::CreateWithOpener(params, FindOpenerRFH(params));
 }
 
 std::unique_ptr<WebContents> WebContents::CreateWithSessionStorage(
@@ -643,14 +642,15 @@
   SetDelegate(nullptr);
 }
 
-WebContentsImpl* WebContentsImpl::CreateWithOpener(
+std::unique_ptr<WebContentsImpl> WebContentsImpl::CreateWithOpener(
     const WebContents::CreateParams& params,
     RenderFrameHostImpl* opener_rfh) {
   TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener");
   FrameTreeNode* opener = nullptr;
   if (opener_rfh)
     opener = opener_rfh->frame_tree_node();
-  WebContentsImpl* new_contents = new WebContentsImpl(params.browser_context);
+  std::unique_ptr<WebContentsImpl> new_contents(
+      new WebContentsImpl(params.browser_context));
   new_contents->SetOpenerForNewContents(opener, params.opener_suppressed);
 
   // If the opener is sandboxed, a new popup must inherit the opener's sandbox
@@ -684,7 +684,7 @@
   if (params.guest_delegate) {
     // This makes |new_contents| act as a guest.
     // For more info, see comment above class BrowserPluginGuest.
-    BrowserPluginGuest::Create(new_contents, params.guest_delegate);
+    BrowserPluginGuest::Create(new_contents.get(), params.guest_delegate);
     // We are instantiating a WebContents for browser plugin. Set its subframe
     // bit to true.
     new_contents->is_subframe_ = true;
@@ -1701,7 +1701,7 @@
   if (opener)
     opener_rfh = opener->current_frame_host();
   std::unique_ptr<WebContentsImpl> tc =
-      base::WrapUnique(CreateWithOpener(create_params, opener_rfh));
+      CreateWithOpener(create_params, opener_rfh);
   tc->GetController().CopyStateFrom(controller_, true);
   for (auto& observer : observers_)
     observer.DidCloneToNewWebContents(this, tc.get());
@@ -2941,8 +2941,7 @@
 
 void WebContentsImpl::ResizeDueToAutoResize(
     RenderWidgetHostImpl* render_widget_host,
-    const gfx::Size& new_size,
-    const viz::LocalSurfaceId& local_surface_id) {
+    const gfx::Size& new_size) {
   if (render_widget_host != GetRenderViewHost()->GetWidget())
     return;
 
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ef7ca07..a5cfbff9 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -137,7 +137,7 @@
 
   ~WebContentsImpl() override;
 
-  static WebContentsImpl* CreateWithOpener(
+  static std::unique_ptr<WebContentsImpl> CreateWithOpener(
       const WebContents::CreateParams& params,
       RenderFrameHostImpl* opener_rfh);
 
@@ -696,10 +696,8 @@
   void RenderWidgetWasResized(RenderWidgetHostImpl* render_widget_host,
                               const ScreenInfo& screen_info,
                               bool width_changed) override;
-  void ResizeDueToAutoResize(
-      RenderWidgetHostImpl* render_widget_host,
-      const gfx::Size& new_size,
-      const viz::LocalSurfaceId& local_surface_id) override;
+  void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host,
+                             const gfx::Size& new_size) override;
   gfx::Size GetAutoResizeSize() override;
   void ResetAutoResizeSize() override;
   KeyboardEventProcessingResult PreHandleKeyboardEvent(
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index a3e61b4..c4067cf5 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -2582,7 +2582,7 @@
   // Create another NavigationController.
   GURL url3("http://foo2");
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
   other_contents->NavigateAndCommit(url3);
   other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
@@ -2607,7 +2607,7 @@
 
   // Create another NavigationController.
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& other_controller = other_contents->GetController();
 
   // Navigate it to url2.
@@ -2657,7 +2657,7 @@
 
   // Create and navigate another WebContents.
   std::unique_ptr<TestWebContents> other_contents(
-      static_cast<TestWebContents*>(CreateTestWebContents()));
+      static_cast<TestWebContents*>(CreateTestWebContents().release()));
   TestWebContentsObserver other_observer(other_contents.get());
   other_contents->NavigateAndCommit(url_normalized);
 
@@ -2670,7 +2670,7 @@
 // crash.
 TEST_F(WebContentsImplTest, PendingContentsDestroyed) {
   std::unique_ptr<WebContentsImpl> other_contents(
-      static_cast<WebContentsImpl*>(CreateTestWebContents()));
+      static_cast<WebContentsImpl*>(CreateTestWebContents().release()));
   content::TestWebContents* raw_other_contents =
       static_cast<TestWebContents*>(other_contents.get());
   contents()->AddPendingContents(std::move(other_contents));
@@ -2687,7 +2687,7 @@
 
 TEST_F(WebContentsImplTest, PendingContentsShown) {
   std::unique_ptr<WebContents> other_contents(
-      static_cast<WebContents*>(CreateTestWebContents()));
+      static_cast<WebContents*>(CreateTestWebContents().release()));
   content::WebContents* raw_other_contents = other_contents.get();
   content::TestWebContents* test_web_contents =
       static_cast<content::TestWebContents*>(other_contents.get());
diff --git a/content/common/external_ipc_dumper.cc b/content/common/external_ipc_dumper.cc
index ec04130..f9ab7e69 100644
--- a/content/common/external_ipc_dumper.cc
+++ b/content/common/external_ipc_dumper.cc
@@ -27,6 +27,7 @@
 
 namespace content {
 
+NO_SANITIZE("cfi-icall")
 IPC::ChannelProxy::OutgoingMessageFilter* LoadExternalIPCDumper(
     const base::FilePath& dump_directory) {
   base::FilePath module_path;
diff --git a/content/common/frame_sink_provider.mojom b/content/common/frame_sink_provider.mojom
index ad84346d..003f761e 100644
--- a/content/common/frame_sink_provider.mojom
+++ b/content/common/frame_sink_provider.mojom
@@ -1,3 +1,7 @@
+// 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.
+
 module content.mojom;
 
 import "content/common/render_frame_metadata.mojom";
@@ -11,7 +15,10 @@
   CreateForWidget(
       int32 widget_id,
       viz.mojom.CompositorFrameSink& compositor_frame_sink_request,
-      viz.mojom.CompositorFrameSinkClient compositor_frame_sink_client,
+      viz.mojom.CompositorFrameSinkClient compositor_frame_sink_client);
+
+   RegisterRenderFrameMetadataObserver(
+      int32  widget_id,
       RenderFrameMetadataObserverClient&
         render_frame_metadata_observer_client_request,
       RenderFrameMetadataObserver render_frame_metadata_observer);
diff --git a/content/common/render_frame_metadata.mojom b/content/common/render_frame_metadata.mojom
index 94748c6..3558eae 100644
--- a/content/common/render_frame_metadata.mojom
+++ b/content/common/render_frame_metadata.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "services/viz/public/interfaces/compositing/local_surface_id.mojom";
 import "services/viz/public/interfaces/compositing/selection.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
@@ -32,6 +33,15 @@
   // - page prevents zooming in or out (i.e. min and max page scale factors
   // are the same).
   bool is_mobile_optimized;
+
+  // The device scale factor used to generate CompositorFrame.
+  float device_scale_factor;
+
+  // The size of the viewport used to generate a CompositorFrame.
+  gfx.mojom.Size viewport_size_in_pixels;
+
+  // The last viz::LocalSurfaceId used to submit a CompositorFrame.
+  viz.mojom.LocalSurfaceId? local_surface_id;
 };
 
 // This interface is provided by the renderer. It can optionally enable
diff --git a/content/common/render_frame_metadata_struct_traits.cc b/content/common/render_frame_metadata_struct_traits.cc
index 2c2927c..00b3b1cf 100644
--- a/content/common/render_frame_metadata_struct_traits.cc
+++ b/content/common/render_frame_metadata_struct_traits.cc
@@ -18,8 +18,11 @@
   out->root_background_color = data.root_background_color();
   out->is_scroll_offset_at_top = data.is_scroll_offset_at_top();
   out->is_mobile_optimized = data.is_mobile_optimized();
+  out->device_scale_factor = data.device_scale_factor();
   return data.ReadRootScrollOffset(&out->root_scroll_offset) &&
-         data.ReadSelection(&out->selection);
+         data.ReadSelection(&out->selection) &&
+         data.ReadViewportSizeInPixels(&out->viewport_size_in_pixels) &&
+         data.ReadLocalSurfaceId(&out->local_surface_id);
 }
 
 }  // namespace mojo
diff --git a/content/common/render_frame_metadata_struct_traits.h b/content/common/render_frame_metadata_struct_traits.h
index 74aac781..06d5181 100644
--- a/content/common/render_frame_metadata_struct_traits.h
+++ b/content/common/render_frame_metadata_struct_traits.h
@@ -8,6 +8,7 @@
 #include "base/optional.h"
 #include "cc/trees/render_frame_metadata.h"
 #include "content/common/render_frame_metadata.mojom-shared.h"
+#include "services/viz/public/cpp/compositing/local_surface_id_struct_traits.h"
 
 namespace mojo {
 
@@ -37,6 +38,20 @@
     return metadata.is_mobile_optimized;
   }
 
+  static float device_scale_factor(const cc::RenderFrameMetadata& metadata) {
+    return metadata.device_scale_factor;
+  }
+
+  static const gfx::Size& viewport_size_in_pixels(
+      const cc::RenderFrameMetadata& metadata) {
+    return metadata.viewport_size_in_pixels;
+  }
+
+  static const base::Optional<viz::LocalSurfaceId>& local_surface_id(
+      const cc::RenderFrameMetadata& metadata) {
+    return metadata.local_surface_id;
+  }
+
   static bool Read(content::mojom::RenderFrameMetadataDataView data,
                    cc::RenderFrameMetadata* out);
 };
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
index 6d6ea3c..1f6bc66 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BindingManager.java
@@ -29,7 +29,4 @@
 
     /** Called when the embedding application is brought to foreground. */
     void onBroughtToForeground();
-
-    /** Releases all moderate bindings. */
-    void releaseAllModerateBindings();
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
index c981be40..eeacfb4 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BindingManagerImpl.java
@@ -168,10 +168,4 @@
         assert LauncherThread.runningOnLauncherThread();
         removeConnection(connection);
     }
-
-    @Override
-    public void releaseAllModerateBindings() {
-        assert LauncherThread.runningOnLauncherThread();
-        removeAllConnections();
-    }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
index 7d50494..4428041 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncherHelper.java
@@ -214,11 +214,10 @@
                 ? new GpuProcessCallback()
                 : null;
 
-        ChildProcessLauncherHelper processLauncher = new ChildProcessLauncherHelper(
+        ChildProcessLauncherHelper helper = new ChildProcessLauncherHelper(
                 nativePointer, commandLine, filesToBeMapped, sandboxed, binderCallback);
-        processLauncher.mLauncher.start(
-                true /* doSetupConnection */, true /* queueIfNoFreeConnection */);
-        return processLauncher;
+        helper.start();
+        return helper;
     }
 
     /**
@@ -327,7 +326,7 @@
         if (!sandboxed) {
             if (sPrivilegedChildConnectionAllocator == null) {
                 sPrivilegedChildConnectionAllocator =
-                        ChildConnectionAllocator.create(context, LauncherThread.getHandler(),
+                        ChildConnectionAllocator.create(context, LauncherThread.getHandler(), null,
                                 packageName, PRIVILEGED_SERVICES_NAME, NUM_PRIVILEGED_SERVICES_KEY,
                                 bindToCaller, bindAsExternalService, true /* useStrongBinding */);
             }
@@ -339,20 +338,28 @@
                     "Create a new ChildConnectionAllocator with package name = %s,"
                             + " sandboxed = true",
                     packageName);
+            Runnable freeSlotRunnable = () -> {
+                ChildProcessConnection lowestRank =
+                        sSandboxedChildConnectionRanking.getLowestRankedConnection();
+                if (lowestRank != null) {
+                    lowestRank.kill();
+                }
+            };
+
             ChildConnectionAllocator connectionAllocator = null;
             if (sSandboxedServicesCountForTesting != -1) {
                 // Testing case where allocator settings are overriden.
                 String serviceName = !TextUtils.isEmpty(sSandboxedServicesNameForTesting)
                         ? sSandboxedServicesNameForTesting
                         : SandboxedProcessService.class.getName();
-                connectionAllocator = ChildConnectionAllocator.createForTest(packageName,
-                        serviceName, sSandboxedServicesCountForTesting, bindToCaller,
+                connectionAllocator = ChildConnectionAllocator.createForTest(freeSlotRunnable,
+                        packageName, serviceName, sSandboxedServicesCountForTesting, bindToCaller,
                         bindAsExternalService, false /* useStrongBinding */);
             } else {
-                connectionAllocator =
-                        ChildConnectionAllocator.create(context, LauncherThread.getHandler(),
-                                packageName, SANDBOXED_SERVICES_NAME, NUM_SANDBOXED_SERVICES_KEY,
-                                bindToCaller, bindAsExternalService, false /* useStrongBinding */);
+                connectionAllocator = ChildConnectionAllocator.create(context,
+                        LauncherThread.getHandler(), freeSlotRunnable, packageName,
+                        SANDBOXED_SERVICES_NAME, NUM_SANDBOXED_SERVICES_KEY, bindToCaller,
+                        bindAsExternalService, false /* useStrongBinding */);
             }
             if (sSandboxedServiceFactoryForTesting != null) {
                 connectionAllocator.setConnectionFactoryForTesting(
@@ -361,25 +368,6 @@
             sSandboxedChildConnectionAllocator = connectionAllocator;
             sSandboxedChildConnectionRanking = new ChildProcessRanking(
                     sSandboxedChildConnectionAllocator.getNumberOfServices());
-
-            final ChildConnectionAllocator finalConnectionAllocator = connectionAllocator;
-            connectionAllocator.addListener(new ChildConnectionAllocator.Listener() {
-                @Override
-                public void onConnectionAllocated(
-                        ChildConnectionAllocator allocator, ChildProcessConnection connection) {
-                    assert connection != null;
-                    assert allocator == finalConnectionAllocator;
-                    if (!allocator.isFreeConnectionAvailable()) {
-                        // Proactively releases all the moderate bindings once all the sandboxed
-                        // services are allocated, which will be very likely to have some of them
-                        // killed by OOM killer.
-                        BindingManager manager = getBindingManager();
-                        if (manager != null) {
-                            manager.releaseAllModerateBindings();
-                        }
-                    }
-                }
-            });
         }
         return sSandboxedChildConnectionAllocator;
     }
@@ -407,6 +395,10 @@
         }
     }
 
+    private void start() {
+        mLauncher.start(true /* doSetupConnection */, true /* queueIfNoFreeConnection */);
+    }
+
     /**
      * @return The type of process as specified in the command line at
      * {@link ContentSwitches#SWITCH_PROCESS_TYPE}.
@@ -548,25 +540,6 @@
         }
     }
 
-    @CalledByNative
-    private static int getNumberOfRendererSlots() {
-        assert ThreadUtils.runningOnUiThread();
-        if (sSandboxedServicesCountForTesting != -1) {
-            return sSandboxedServicesCountForTesting;
-        }
-
-        final Context context = ContextUtils.getApplicationContext();
-        final String packageName = ChildProcessCreationParams.getPackageNameForService();
-        try {
-            return ChildConnectionAllocator.getNumberOfServices(
-                    context, packageName, NUM_SANDBOXED_SERVICES_KEY);
-        } catch (RuntimeException e) {
-            // Unittest packages do not declare services. Some tests require a realistic number
-            // to test child process policies, so pick a high-ish number here.
-            return 65535;
-        }
-    }
-
     // Can be called on a number of threads, including launcher, and binder.
     private static native void nativeOnChildProcessStarted(
             long nativeChildProcessLauncherHelper, int pid);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
index e86212d..db6c180 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherIntegrationTest.java
@@ -137,4 +137,36 @@
             }
         });
     }
+
+    @Test
+    @MediumTest
+    public void testIntentionalKillToFreeServiceSlot() throws Throwable {
+        final TestChildProcessConnectionFactory factory = new TestChildProcessConnectionFactory();
+        final List<TestChildProcessConnection> connections = factory.getConnections();
+        ChildProcessLauncherHelper.setSandboxServicesSettingsForTesting(
+                factory, 1, null /* use default service name */);
+        // Doing a cross-domain navigation would need to kill the first process in order to create
+        // the second process.
+
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrlSync(
+                "content/test/data/android/vsync.html");
+        NavigationController navigationController =
+                mActivityTestRule.getWebContents().getNavigationController();
+        TestCallbackHelperContainer testCallbackHelperContainer =
+                new TestCallbackHelperContainer(activity.getActiveWebContents());
+
+        mActivityTestRule.loadUrl(navigationController, testCallbackHelperContainer,
+                new LoadUrlParams(UrlUtils.getIsolatedTestFileUrl(
+                        "content/test/data/android/geolocation.html")));
+        mActivityTestRule.loadUrl(
+                navigationController, testCallbackHelperContainer, new LoadUrlParams("data:,foo"));
+
+        ChildProcessLauncherTestUtils.runOnLauncherThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                Assert.assertEquals(2, connections.size());
+                Assert.assertTrue(connections.get(0).isKilledByUs());
+            }
+        });
+    }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
index 7dd0c570..54c9470 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -107,9 +107,9 @@
                     public ChildConnectionAllocator call() {
                         Context context = InstrumentationRegistry.getTargetContext();
                         return ChildConnectionAllocator.create(context, LauncherThread.getHandler(),
-                                SERVICE_PACKAGE_NAME, SERVICE_NAME, SERVICE_COUNT_META_DATA_KEY,
-                                false /* bindToCaller */, false /* bindAsExternalService */,
-                                false /* useStrongBinding */);
+                                null, SERVICE_PACKAGE_NAME, SERVICE_NAME,
+                                SERVICE_COUNT_META_DATA_KEY, false /* bindToCaller */,
+                                false /* bindAsExternalService */, false /* useStrongBinding */);
                     }
                 });
     }
@@ -356,7 +356,7 @@
                         new Callable<ChildConnectionAllocator>() {
                             @Override
                             public ChildConnectionAllocator call() {
-                                return ChildConnectionAllocator.createForTest(
+                                return ChildConnectionAllocator.createForTest(null,
                                         "org.chromium.wrong_package", "WrongService",
                                         2 /* serviceCount */, false /* bindToCaller */,
                                         false /* bindAsExternalService */,
diff --git a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
index c0a6e8f..0d38b31 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/BindingManagerImplTest.java
@@ -188,33 +188,6 @@
         }
     }
 
-    /**
-     * Verifies that BindingManager.releaseAllModerateBindings() drops all the moderate bindings.
-     */
-    @Test
-    @Feature({"ProcessManagement"})
-    public void testModerateBindingDropOnReleaseAllModerateBindings() {
-        final BindingManagerImpl manager = mManager;
-
-        ChildProcessConnection[] connections = new ChildProcessConnection[4];
-        for (int i = 0; i < connections.length; i++) {
-            connections[i] = createTestChildProcessConnection(i + 1 /* pid */, manager);
-        }
-
-        // Verify that each connection has a moderate binding after binding and releasing a strong
-        // binding.
-        for (ChildProcessConnection connection : connections) {
-            Assert.assertTrue(connection.isModerateBindingBound());
-        }
-
-        // Call BindingManager.releaseAllModerateBindings() and verify that all the moderate
-        // bindings drop.
-        manager.releaseAllModerateBindings();
-        for (ChildProcessConnection connection : connections) {
-            Assert.assertFalse(connection.isModerateBindingBound());
-        }
-    }
-
     /*
      * Test that Chrome is sent to the background, that the initially added moderate bindings are
      * removed and are not re-added when Chrome is brought back to the foreground.
diff --git a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
index 7386ba7..1e5f786 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/SpareChildConnectionTest.java
@@ -40,7 +40,7 @@
 
     // A connection allocator not used to create connections.
     private final ChildConnectionAllocator mWrongConnectionAllocator =
-            ChildConnectionAllocator.createForTest("org.chromium.test", "TestServiceName",
+            ChildConnectionAllocator.createForTest(null, "org.chromium.test", "TestServiceName",
                     3 /* serviceCount */, false /* bindToCaller */,
                     false /* bindAsExternalService */, false /* useStrongBinding */);
 
@@ -87,7 +87,7 @@
         LauncherThread.setCurrentThreadAsLauncherThread();
 
         mConnectionAllocator =
-                ChildConnectionAllocator.createForTest("org.chromium.test.spare_connection",
+                ChildConnectionAllocator.createForTest(null, "org.chromium.test.spare_connection",
                         "TestServiceName", 5 /* serviceCount */, false /* bindToCaller */,
                         false /* bindAsExternalService */, false /* useStrongBinding */);
         mConnectionAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
diff --git a/content/public/browser/render_frame_metadata_provider.h b/content/public/browser/render_frame_metadata_provider.h
index b64eedd..25b86d3 100644
--- a/content/public/browser/render_frame_metadata_provider.h
+++ b/content/public/browser/render_frame_metadata_provider.h
@@ -31,6 +31,14 @@
 
     virtual void OnRenderFrameMetadataChanged() = 0;
     virtual void OnRenderFrameSubmission() = 0;
+
+    // Called to indicate that the viz::LocalSurfaceId within the
+    // RenderFrameMetadata has changed. For production builds, this means that
+    // the child_sequence_number of the viz::LocalSurfaceId has changed. For
+    // unit tests, this means that any part of the viz::LocalSurfaceId has
+    // changed.
+    virtual void OnLocalSurfaceIdChanged(
+        const cc::RenderFrameMetadata& metadata) = 0;
   };
 
   RenderFrameMetadataProvider() = default;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 229ff2a..bb2802b 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1930,6 +1930,9 @@
     Quit();
 }
 
+void RenderFrameSubmissionObserver::OnLocalSurfaceIdChanged(
+    const cc::RenderFrameMetadata& metadata) {}
+
 MainThreadFrameObserver::MainThreadFrameObserver(
     RenderWidgetHost* render_widget_host)
     : render_widget_host_(render_widget_host),
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index efce49b..e2954ad2 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -738,6 +738,8 @@
   // RenderFrameMetadataProvider::Observer
   void OnRenderFrameMetadataChanged() override;
   void OnRenderFrameSubmission() override;
+  void OnLocalSurfaceIdChanged(
+      const cc::RenderFrameMetadata& metadata) override;
 
   // If true then the next OnRenderFrameSubmission will cancel the blocking
   // |run_loop_| otherwise the blocking will continue until the next
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index fed8cfb..66f556e 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -217,15 +217,17 @@
 }
 
 void RenderViewHostTestHarness::DeleteContents() {
-  SetContents(nullptr);
+  contents_.reset();
 }
 
-void RenderViewHostTestHarness::SetContents(WebContents* contents) {
-  contents_.reset(contents);
+void RenderViewHostTestHarness::SetContents(
+    std::unique_ptr<WebContents> contents) {
+  contents_ = std::move(contents);
 }
 
-WebContents* RenderViewHostTestHarness::CreateTestWebContents() {
-  // Make sure we ran SetUp() already.
+std::unique_ptr<WebContents>
+RenderViewHostTestHarness::CreateTestWebContents() {
+// Make sure we ran SetUp() already.
 #if defined(OS_WIN)
   DCHECK(ole_initializer_ != NULL);
 #endif
@@ -283,7 +285,7 @@
   if (IsBrowserSideNavigationEnabled())
     BrowserSideNavigationTearDown();
 
-  SetContents(nullptr);
+  DeleteContents();
 #if defined(USE_AURA)
   aura_test_helper_->TearDown();
   ui::TerminateContextFactoryForTests();
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index 5e899b2b..7c4655c 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -228,11 +228,11 @@
 
   // Sets the current WebContents for tests that want to alter it. Takes
   // ownership of the WebContents passed.
-  void SetContents(WebContents* contents);
+  void SetContents(std::unique_ptr<WebContents> contents);
 
   // Creates a new test-enabled WebContents. Ownership passes to the
   // caller.
-  WebContents* CreateTestWebContents();
+  std::unique_ptr<WebContents> CreateTestWebContents();
 
   // Cover for |contents()->NavigateAndCommit(url)|. See
   // WebContentsTester::NavigateAndCommit for details.
diff --git a/content/public/test/web_contents_tester.cc b/content/public/test/web_contents_tester.cc
index df76c6f..6c3cf24 100644
--- a/content/public/test/web_contents_tester.cc
+++ b/content/public/test/web_contents_tester.cc
@@ -23,7 +23,7 @@
 }
 
 // static
-WebContents* WebContentsTester::CreateTestWebContents(
+std::unique_ptr<WebContents> WebContentsTester::CreateTestWebContents(
     BrowserContext* browser_context,
     scoped_refptr<SiteInstance> instance) {
   return TestWebContents::Create(browser_context, std::move(instance));
diff --git a/content/public/test/web_contents_tester.h b/content/public/test/web_contents_tester.h
index 2aac5fb..b1c7190 100644
--- a/content/public/test/web_contents_tester.h
+++ b/content/public/test/web_contents_tester.h
@@ -63,7 +63,7 @@
   static WebContentsTester* For(WebContents* contents);
 
   // Creates a WebContents enabled for testing.
-  static WebContents* CreateTestWebContents(
+  static std::unique_ptr<WebContents> CreateTestWebContents(
       BrowserContext* browser_context,
       scoped_refptr<SiteInstance> instance);
 
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 3fb5462..e2cf1e3 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -857,9 +857,11 @@
   return web_layer_.get();
 }
 
-void BrowserPlugin::SetLayer(std::unique_ptr<blink::WebLayer> web_layer) {
-  if (container_)
-    container_->SetWebLayer(web_layer.get());
+void BrowserPlugin::SetLayer(std::unique_ptr<blink::WebLayer> web_layer,
+                             bool prevent_contents_opaque_changes) {
+  if (container_) {
+    container_->SetWebLayer(web_layer.get(), prevent_contents_opaque_changes);
+  }
   web_layer_ = std::move(web_layer);
 }
 
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index c24d895..67ed581 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -218,7 +218,8 @@
 
   // ChildFrameCompositor:
   blink::WebLayer* GetLayer() override;
-  void SetLayer(std::unique_ptr<blink::WebLayer> web_layer) override;
+  void SetLayer(std::unique_ptr<blink::WebLayer> web_layer,
+                bool prevent_contents_opaque_changes) override;
   SkBitmap* GetSadPageBitmap() override;
 
   // This indicates whether this BrowserPlugin has been attached to a
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index 620cab0..78bccec 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -66,8 +66,10 @@
     }
   }
 
+  bool prevent_contents_opaque_changes = false;
   child_frame_compositor_->SetLayer(
-      std::make_unique<cc_blink::WebLayerImpl>(crashed_layer));
+      std::make_unique<cc_blink::WebLayerImpl>(crashed_layer),
+      prevent_contents_opaque_changes);
 }
 
 void ChildFrameCompositingHelper::SetPrimarySurfaceId(
@@ -87,19 +89,18 @@
   surface_layer_->SetPrimarySurfaceId(surface_id, deadline);
   surface_layer_->SetFallbackSurfaceId(fallback_surface_id_);
 
-  std::unique_ptr<cc_blink::WebLayerImpl> layer(
-      new cc_blink::WebLayerImpl(surface_layer_));
-  // TODO(lfg): Investigate if it's possible to propagate the information about
-  // the child surface's opacity. https://crbug.com/629851.
-  layer->SetOpaque(false);
-  layer->SetContentsOpaqueIsFixed(true);
-  child_frame_compositor_->SetLayer(std::move(layer));
+  auto layer_owned = std::make_unique<cc_blink::WebLayerImpl>(surface_layer_);
+  auto* layer = layer_owned.get();
+
+  // TODO(lfg): Investigate if it's possible to propagate the information
+  // about the child surface's opacity. https://crbug.com/629851.
+  bool prevent_contents_opaque_changes = true;
+  child_frame_compositor_->SetLayer(std::move(layer_owned),
+                                    prevent_contents_opaque_changes);
 
   UpdateVisibility(true);
 
-  static_cast<cc_blink::WebLayerImpl*>(child_frame_compositor_->GetLayer())
-      ->layer()
-      ->SetBounds(frame_size_in_dip);
+  layer->SetBounds(frame_size_in_dip);
 }
 
 void ChildFrameCompositingHelper::SetFallbackSurfaceId(
diff --git a/content/renderer/child_frame_compositing_helper_unittest.cc b/content/renderer/child_frame_compositing_helper_unittest.cc
index b84e214..aec2de79 100644
--- a/content/renderer/child_frame_compositing_helper_unittest.cc
+++ b/content/renderer/child_frame_compositing_helper_unittest.cc
@@ -22,7 +22,8 @@
 
   blink::WebLayer* GetLayer() override { return web_layer_.get(); }
 
-  void SetLayer(std::unique_ptr<blink::WebLayer> web_layer) override {
+  void SetLayer(std::unique_ptr<blink::WebLayer> web_layer,
+                bool prevent_contents_opaque_changes) override {
     web_layer_ = std::move(web_layer);
   }
 
diff --git a/content/renderer/child_frame_compositor.h b/content/renderer/child_frame_compositor.h
index cee6610..7466f2a 100644
--- a/content/renderer/child_frame_compositor.h
+++ b/content/renderer/child_frame_compositor.h
@@ -19,7 +19,8 @@
   virtual blink::WebLayer* GetLayer() = 0;
 
   // Passes ownership of a blink::WebLayer to the ChildFrameCompositor.
-  virtual void SetLayer(std::unique_ptr<blink::WebLayer> web_layer) = 0;
+  virtual void SetLayer(std::unique_ptr<blink::WebLayer> web_layer,
+                        bool prevent_contents_opaque_changes) = 0;
 
   // Returns a sad page bitmap used when the child frame has crashed.
   virtual SkBitmap* GetSadPageBitmap() = 0;
diff --git a/content/renderer/media/stream/webmediaplayer_ms.cc b/content/renderer/media/stream/webmediaplayer_ms.cc
index 7e045d07d..7b379d2 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms.cc
@@ -962,7 +962,7 @@
 
   // Opacity can be changed during the session without resetting
   // |video_weblayer_|.
-  video_weblayer_->layer()->SetContentsOpaque(is_opaque);
+  video_weblayer_->SetOpaque(is_opaque);
 }
 
 void WebMediaPlayerMS::OnRotationChanged(media::VideoRotation video_rotation,
@@ -974,8 +974,7 @@
   std::unique_ptr<cc_blink::WebLayerImpl> rotated_weblayer =
       base::WrapUnique(new cc_blink::WebLayerImpl(
           cc::VideoLayer::Create(compositor_.get(), video_rotation)));
-  rotated_weblayer->layer()->SetContentsOpaque(is_opaque);
-  rotated_weblayer->SetContentsOpaqueIsFixed(true);
+  rotated_weblayer->SetOpaque(is_opaque);
   get_client()->SetWebLayer(rotated_weblayer.get());
   video_weblayer_ = std::move(rotated_weblayer);
 }
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 67cc02c..71e1ef90 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -2209,7 +2209,7 @@
 
   if (texture_layer_ || compositor_layer_) {
     if (!layer_bound_to_fullscreen_)
-      container_->SetWebLayer(nullptr);
+      container_->SetWebLayer(nullptr, false);
     else if (fullscreen_container_)
       fullscreen_container_->SetLayer(nullptr);
     web_layer_.reset();
@@ -2241,8 +2241,7 @@
     // wants to do, and that lets it not recreate a context if
     // wmode=transparent was specified.
     opaque = opaque || fullscreen_container_;
-    layer->layer()->SetContentsOpaque(opaque);
-    layer->SetContentsOpaqueIsFixed(true);
+    layer->SetOpaque(opaque);
     web_layer_ = std::move(layer);
   } else if (want_compositor_layer) {
     compositor_layer_ = bound_compositor_->layer();
@@ -2253,7 +2252,7 @@
     if (fullscreen_container_) {
       fullscreen_container_->SetLayer(web_layer_.get());
     } else {
-      container_->SetWebLayer(web_layer_.get());
+      container_->SetWebLayer(web_layer_.get(), true);
     }
     if (is_flash_plugin_) {
       web_layer_->CcLayer()->SetMayContainVideo(true);
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index f375cfa..6ef8d1fd 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -869,9 +869,10 @@
   return web_layer_.get();
 }
 
-void RenderFrameProxy::SetLayer(std::unique_ptr<blink::WebLayer> web_layer) {
+void RenderFrameProxy::SetLayer(std::unique_ptr<blink::WebLayer> web_layer,
+                                bool prevent_contents_opaque_changes) {
   if (web_frame())
-    web_frame()->SetWebLayer(web_layer.get());
+    web_frame()->SetWebLayer(web_layer.get(), prevent_contents_opaque_changes);
   web_layer_ = std::move(web_layer);
 }
 
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 00184f9..69ba3d4 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -266,7 +266,8 @@
 
   // ChildFrameCompositor:
   blink::WebLayer* GetLayer() override;
-  void SetLayer(std::unique_ptr<blink::WebLayer> web_layer) override;
+  void SetLayer(std::unique_ptr<blink::WebLayer> web_layer,
+                bool prevent_contents_opaque_changes) override;
   SkBitmap* GetSadPageBitmap() override;
 
   const viz::LocalSurfaceId& GetLocalSurfaceId() const;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 980248d..366e92c 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -2051,6 +2051,9 @@
         ->RequestLayerTreeFrameSink(
             gpu_->CreateContextProvider(std::move(channel)),
             GetGpuMemoryBufferManager(), callback);
+    frame_sink_provider_->RegisterRenderFrameMetadataObserver(
+        routing_id, std::move(render_frame_metadata_observer_client_request),
+        std::move(render_frame_metadata_observer_ptr));
     return;
   }
 #endif
@@ -2065,8 +2068,9 @@
     DCHECK(!layout_test_mode());
     frame_sink_provider_->CreateForWidget(
         routing_id, std::move(compositor_frame_sink_request),
-        std::move(compositor_frame_sink_client),
-        std::move(render_frame_metadata_observer_client_request),
+        std::move(compositor_frame_sink_client));
+    frame_sink_provider_->RegisterRenderFrameMetadataObserver(
+        routing_id, std::move(render_frame_metadata_observer_client_request),
         std::move(render_frame_metadata_observer_ptr));
     callback.Run(std::make_unique<viz::ClientLayerTreeFrameSink>(
         nullptr, nullptr, &params));
@@ -2155,8 +2159,9 @@
 #endif
   frame_sink_provider_->CreateForWidget(
       routing_id, std::move(compositor_frame_sink_request),
-      std::move(compositor_frame_sink_client),
-      std::move(render_frame_metadata_observer_client_request),
+      std::move(compositor_frame_sink_client));
+  frame_sink_provider_->RegisterRenderFrameMetadataObserver(
+      routing_id, std::move(render_frame_metadata_observer_client_request),
       std::move(render_frame_metadata_observer_ptr));
   params.gpu_memory_buffer_manager = GetGpuMemoryBufferManager();
   callback.Run(std::make_unique<viz::ClientLayerTreeFrameSink>(
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index eac38ae2..b502b84 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -818,7 +818,7 @@
   // Ack the resize if we have to, so that the next time we're visible we get a
   // fresh VisualProperties right away; otherwise we'll start painting based on
   // a stale VisualProperties.
-  DidResizeOrRepaintAck();
+  DidUpdateVisualProperties();
 }
 
 void RenderWidget::OnWasShown(bool needs_repainting,
@@ -971,7 +971,7 @@
 }
 
 void RenderWidget::DidCommitCompositorFrame() {
-  DidResizeOrRepaintAck();
+  DidUpdateVisualProperties();
 }
 
 void RenderWidget::DidCompletePageScaleAnimation() {}
@@ -2528,19 +2528,24 @@
   widget_binding_.Bind(std::move(request));
 }
 
-void RenderWidget::DidResizeOrRepaintAck() {
+bool RenderWidget::IsSurfaceSynchronizationEnabled() const {
+  return compositor_ && compositor_->IsSurfaceSynchronizationEnabled();
+}
+
+void RenderWidget::DidUpdateVisualProperties() {
   if (!needs_visual_properties_ack_ || size_.IsEmpty())
     return;
 
-  ViewHostMsg_ResizeOrRepaint_ACK_Params params;
-  params.view_size = size_;
-  if (child_local_surface_id_allocator_.GetCurrentLocalSurfaceId().is_valid()) {
-    params.child_allocated_local_surface_id =
+  if (!IsSurfaceSynchronizationEnabled()) {
+    ViewHostMsg_ResizeOrRepaint_ACK_Params params;
+    params.view_size = size_;
+    const viz::LocalSurfaceId& local_surface_id =
         child_local_surface_id_allocator_.GetCurrentLocalSurfaceId();
-    DCHECK(params.child_allocated_local_surface_id.value().is_valid());
+    if (local_surface_id.is_valid())
+      params.child_allocated_local_surface_id = local_surface_id;
+    Send(new ViewHostMsg_ResizeOrRepaint_ACK(routing_id_, params));
   }
 
-  Send(new ViewHostMsg_ResizeOrRepaint_ACK(routing_id_, params));
   needs_visual_properties_ack_ = false;
 }
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 94b0896..10126bd 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -484,7 +484,9 @@
     TTFAP_5MIN_AFTER_BACKGROUNDED,
   };
 
-  void DidResizeOrRepaintAck();
+  bool IsSurfaceSynchronizationEnabled() const;
+
+  void DidUpdateVisualProperties();
 
   base::WeakPtr<RenderWidget> AsWeakPtr();
 
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 90863d1d..fe60df56 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -417,14 +417,7 @@
 
   // Issue an auto-resize.
   widget()->DidAutoResize(auto_size);
-  widget()->sink()->ClearMessages();
   widget()->DidCommitCompositorFrame();
-  const IPC::Message* message = widget()->sink()->GetUniqueMessageMatching(
-      ViewHostMsg_ResizeOrRepaint_ACK::ID);
-  ASSERT_TRUE(message);
-  ViewHostMsg_ResizeOrRepaint_ACK::Param params;
-  ViewHostMsg_ResizeOrRepaint_ACK::Read(message, &params);
-  EXPECT_EQ(auto_size, std::get<0>(params).view_size);
 
   // Issue another auto-resize but keep it in-flight.
   constexpr gfx::Size auto_size2(200, 200);
diff --git a/content/shell/renderer/layout_test/blink_test_helpers.cc b/content/shell/renderer/layout_test/blink_test_helpers.cc
index 47609d7..af6f7427 100644
--- a/content/shell/renderer/layout_test/blink_test_helpers.cc
+++ b/content/shell/renderer/layout_test/blink_test_helpers.cc
@@ -8,6 +8,8 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
@@ -33,20 +35,19 @@
 // Note that this isn't applied to external/wpt because tests in external/wpt
 // are accessed via http.
 WebURL RewriteAbsolutePathInCsswgTest(const std::string& utf8_url) {
-  const char kFileScheme[] = "file:///";
-  const int kFileSchemeLen = base::size(kFileScheme) - 1;
-  if (utf8_url.compare(0, kFileSchemeLen, kFileScheme, kFileSchemeLen) != 0)
+  static constexpr base::StringPiece kFileScheme = "file:///";
+  if (!base::StartsWith(utf8_url, kFileScheme, base::CompareCase::SENSITIVE))
     return WebURL();
   if (utf8_url.find("/LayoutTests/") != std::string::npos)
     return WebURL();
 #if defined(OS_WIN)
   // +3 for a drive letter, :, and /.
-  const int kFileSchemeAndDriveLen = kFileSchemeLen + 3;
+  static constexpr size_t kFileSchemeAndDriveLen = kFileScheme.size() + 3;
   if (utf8_url.size() <= kFileSchemeAndDriveLen)
     return WebURL();
   std::string path = utf8_url.substr(kFileSchemeAndDriveLen);
 #else
-  std::string path = utf8_url.substr(kFileSchemeLen);
+  std::string path = utf8_url.substr(kFileScheme.size());
 #endif
   base::FilePath new_path = content::GetWebKitRootDirFilePath()
                                 .Append(FILE_PATH_LITERAL("LayoutTests/"))
@@ -179,30 +180,28 @@
     return WebURL(GURL(utf8_url));
   }
 
-  const char kGenPrefix[] = "file:///gen/";
-  const int kGenPrefixLen = base::size(kGenPrefix) - 1;
+  static constexpr base::StringPiece kGenPrefix = "file:///gen/";
 
   // Map "file:///gen/" to "file://<build directory>/gen/".
-  if (!utf8_url.compare(0, kGenPrefixLen, kGenPrefix, kGenPrefixLen)) {
+  if (base::StartsWith(utf8_url, kGenPrefix, base::CompareCase::SENSITIVE)) {
     base::FilePath gen_directory_path =
         GetBuildDirectory().Append(FILE_PATH_LITERAL("gen/"));
     std::string new_url = std::string("file://") +
                           gen_directory_path.AsUTF8Unsafe() +
-                          utf8_url.substr(kGenPrefixLen);
+                          utf8_url.substr(kGenPrefix.size());
     return WebURL(GURL(new_url));
   }
 
-  const char kPrefix[] = "file:///tmp/LayoutTests/";
-  const int kPrefixLen = base::size(kPrefix) - 1;
+  static constexpr base::StringPiece kPrefix = "file:///tmp/LayoutTests/";
 
-  if (utf8_url.compare(0, kPrefixLen, kPrefix, kPrefixLen))
+  if (!base::StartsWith(utf8_url, kPrefix, base::CompareCase::SENSITIVE))
     return WebURL(GURL(utf8_url));
 
   base::FilePath replace_path =
       GetWebKitRootDirFilePath().Append(FILE_PATH_LITERAL("LayoutTests/"));
   std::string utf8_path = replace_path.AsUTF8Unsafe();
   std::string new_url =
-      std::string("file://") + utf8_path + utf8_url.substr(kPrefixLen);
+      std::string("file://") + utf8_path + utf8_url.substr(kPrefix.size());
   return WebURL(GURL(new_url));
 }
 
diff --git a/content/shell/test_runner/test_plugin.cc b/content/shell/test_runner/test_plugin.cc
index cfe56dd..cfe063c 100644
--- a/content/shell/test_runner/test_plugin.cc
+++ b/content/shell/test_runner/test_plugin.cc
@@ -187,8 +187,9 @@
     return false;
 
   layer_ = cc::TextureLayer::CreateForMailbox(this);
-  web_layer_ = base::WrapUnique(new cc_blink::WebLayerImpl(layer_));
-  container_->SetWebLayer(web_layer_.get());
+  web_layer_ = std::make_unique<cc_blink::WebLayerImpl>(layer_);
+  bool prevent_contents_opaque_changes = false;
+  container_->SetWebLayer(web_layer_.get(), prevent_contents_opaque_changes);
   if (re_request_touch_events_) {
     container_->RequestTouchEventType(
         blink::WebPluginContainer::kTouchEventRequestTypeSynthesizedMouse);
@@ -204,7 +205,7 @@
   if (layer_.get())
     layer_->ClearTexture();
   if (container_)
-    container_->SetWebLayer(nullptr);
+    container_->SetWebLayer(nullptr, false);
   web_layer_.reset();
   layer_ = nullptr;
   DestroyScene();
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index 6e93d9c..f55ffd18 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -22,8 +22,8 @@
 #include "content/browser/frame_host/render_frame_host_delegate.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/renderer_host/delegated_frame_host.h"
-#include "content/common/frame_messages.h"
 #include "content/common/frame_visual_properties.h"
+#include "content/common/view_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -397,4 +397,63 @@
   return static_cast<bad_message::BadMessageReason>(bucket.min);
 }
 
+ShowWidgetMessageFilter::ShowWidgetMessageFilter()
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+    : content::BrowserMessageFilter(FrameMsgStart),
+#else
+    : content::BrowserMessageFilter(ViewMsgStart),
+#endif
+      message_loop_runner_(new content::MessageLoopRunner) {
+}
+
+ShowWidgetMessageFilter::~ShowWidgetMessageFilter() {}
+
+bool ShowWidgetMessageFilter::OnMessageReceived(const IPC::Message& message) {
+  IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message)
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
+#else
+    IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
+#endif
+  IPC_END_MESSAGE_MAP()
+  return false;
+}
+
+void ShowWidgetMessageFilter::Wait() {
+  initial_rect_ = gfx::Rect();
+  routing_id_ = MSG_ROUTING_NONE;
+  message_loop_runner_->Run();
+}
+
+void ShowWidgetMessageFilter::Reset() {
+  initial_rect_ = gfx::Rect();
+  routing_id_ = MSG_ROUTING_NONE;
+  message_loop_runner_ = new content::MessageLoopRunner;
+}
+
+void ShowWidgetMessageFilter::OnShowWidget(int route_id,
+                                           const gfx::Rect& initial_rect) {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this, route_id,
+                     initial_rect));
+}
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+void ShowWidgetMessageFilter::OnShowPopup(
+    const FrameHostMsg_ShowPopup_Params& params) {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this,
+                 MSG_ROUTING_NONE, params.bounds));
+}
+#endif
+
+void ShowWidgetMessageFilter::OnShowWidgetOnUI(int route_id,
+                                               const gfx::Rect& initial_rect) {
+  initial_rect_ = initial_rect;
+  routing_id_ = route_id;
+  message_loop_runner_->Quit();
+}
+
 }  // namespace content
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index b1505ecd..bb0260e 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -21,11 +21,14 @@
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
+#include "build/build_config.h"
 #include "content/browser/bad_message.h"
+#include "content/common/frame_messages.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/file_chooser_params.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -217,6 +220,38 @@
   DISALLOW_COPY_AND_ASSIGN(RenderProcessHostKillWaiter);
 };
 
+class ShowWidgetMessageFilter : public content::BrowserMessageFilter {
+ public:
+  ShowWidgetMessageFilter();
+
+  bool OnMessageReceived(const IPC::Message& message) override;
+
+  gfx::Rect last_initial_rect() const { return initial_rect_; }
+
+  int last_routing_id() const { return routing_id_; }
+
+  void Wait();
+
+  void Reset();
+
+ private:
+  ~ShowWidgetMessageFilter() override;
+
+  void OnShowWidget(int route_id, const gfx::Rect& initial_rect);
+
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
+  void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params);
+#endif
+
+  void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect);
+
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  gfx::Rect initial_rect_;
+  int routing_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter);
+};
+
 }  // namespace content
 
 #endif  // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
diff --git a/content/test/mock_render_widget_host_delegate.cc b/content/test/mock_render_widget_host_delegate.cc
index 21b765ec..9d2404e 100644
--- a/content/test/mock_render_widget_host_delegate.cc
+++ b/content/test/mock_render_widget_host_delegate.cc
@@ -16,8 +16,7 @@
 
 void MockRenderWidgetHostDelegate::ResizeDueToAutoResize(
     RenderWidgetHostImpl* render_widget_host,
-    const gfx::Size& new_size,
-    const viz::LocalSurfaceId& local_surface_id) {}
+    const gfx::Size& new_size) {}
 
 KeyboardEventProcessingResult
 MockRenderWidgetHostDelegate::PreHandleKeyboardEvent(
diff --git a/content/test/mock_render_widget_host_delegate.h b/content/test/mock_render_widget_host_delegate.h
index 63afaf1..048ff0de 100644
--- a/content/test/mock_render_widget_host_delegate.h
+++ b/content/test/mock_render_widget_host_delegate.h
@@ -33,10 +33,8 @@
   }
 
   // RenderWidgetHostDelegate:
-  void ResizeDueToAutoResize(
-      RenderWidgetHostImpl* render_widget_host,
-      const gfx::Size& new_size,
-      const viz::LocalSurfaceId& local_surface_id) override;
+  void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host,
+                             const gfx::Size& new_size) override;
   KeyboardEventProcessingResult PreHandleKeyboardEvent(
       const NativeWebKeyboardEvent& event) override;
   void ExecuteEditCommand(const std::string& command,
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 19b8d6f33..b4c52cc2 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -61,9 +61,11 @@
   }
 }
 
-TestWebContents* TestWebContents::Create(BrowserContext* browser_context,
-                                         scoped_refptr<SiteInstance> instance) {
-  TestWebContents* test_web_contents = new TestWebContents(browser_context);
+std::unique_ptr<TestWebContents> TestWebContents::Create(
+    BrowserContext* browser_context,
+    scoped_refptr<SiteInstance> instance) {
+  std::unique_ptr<TestWebContents> test_web_contents(
+      new TestWebContents(browser_context));
   test_web_contents->Init(CreateParams(browser_context, std::move(instance)));
   return test_web_contents;
 }
@@ -262,8 +264,8 @@
 }
 
 std::unique_ptr<WebContents> TestWebContents::Clone() {
-  std::unique_ptr<WebContentsImpl> contents = base::WrapUnique(
-      Create(GetBrowserContext(), SiteInstance::Create(GetBrowserContext())));
+  std::unique_ptr<WebContentsImpl> contents =
+      Create(GetBrowserContext(), SiteInstance::Create(GetBrowserContext()));
   contents->GetController().CopyStateFrom(controller_, true);
   return contents;
 }
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index 9e2285f1f..42e76c93 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -44,8 +44,9 @@
  public:
   ~TestWebContents() override;
 
-  static TestWebContents* Create(BrowserContext* browser_context,
-                                 scoped_refptr<SiteInstance> instance);
+  static std::unique_ptr<TestWebContents> Create(
+      BrowserContext* browser_context,
+      scoped_refptr<SiteInstance> instance);
   static TestWebContents* Create(const CreateParams& params);
 
   // WebContentsImpl overrides (returning the same values, but in Test* types)
diff --git a/content/test/test_web_contents_factory.cc b/content/test/test_web_contents_factory.cc
index d27e6a8..f271518 100644
--- a/content/test/test_web_contents_factory.cc
+++ b/content/test/test_web_contents_factory.cc
@@ -30,8 +30,8 @@
 
 WebContents* TestWebContentsFactory::CreateWebContents(
     BrowserContext* context) {
-  web_contents_.push_back(base::WrapUnique(
-      WebContentsTester::CreateTestWebContents(context, nullptr)));
+  web_contents_.push_back(
+      WebContentsTester::CreateTestWebContents(context, nullptr));
   DCHECK(web_contents_.back());
   return web_contents_.back().get();
 }
diff --git a/extensions/browser/api/declarative/rules_registry.cc b/extensions/browser/api/declarative/rules_registry.cc
index 8a53ab2..b84cc3a1 100644
--- a/extensions/browser/api/declarative/rules_registry.cc
+++ b/extensions/browser/api/declarative/rules_registry.cc
@@ -87,7 +87,7 @@
       ready_(/*signaled=*/!cache_delegate),  // Immediately ready if no cache
                                              // delegate to wait for.
       last_generated_rule_identifier_id_(0),
-      weak_ptr_factory_(browser_context_ ? this : NULL) {
+      weak_ptr_factory_(this) {
   if (cache_delegate) {
     cache_delegate_ = cache_delegate->GetWeakPtr();
     cache_delegate->Init(this);
diff --git a/extensions/common/api/declarative_net_request/test_utils.cc b/extensions/common/api/declarative_net_request/test_utils.cc
index 77b7606..be77366 100644
--- a/extensions/common/api/declarative_net_request/test_utils.cc
+++ b/extensions/common/api/declarative_net_request/test_utils.cc
@@ -156,9 +156,9 @@
   JSONFileValueSerializer(extension_dir.Append(json_rules_filepath))
       .Serialize(rules);
 
-  // Persists an empty background script if needed.
+  // Persists a background script if needed.
   if (has_background_script) {
-    std::string content;
+    std::string content = "chrome.test.sendMessage('ready');";
     CHECK_EQ(static_cast<int>(content.length()),
              base::WriteFile(extension_dir.Append(kBackgroundScriptFilepath),
                              content.c_str(), content.length()));
diff --git a/extensions/common/api/declarative_net_request/test_utils.h b/extensions/common/api/declarative_net_request/test_utils.h
index 46610ca..877e086 100644
--- a/extensions/common/api/declarative_net_request/test_utils.h
+++ b/extensions/common/api/declarative_net_request/test_utils.h
@@ -84,8 +84,10 @@
 
 // Writes the declarative |rules| in the given |extension_dir| together with the
 // manifest file. |hosts| specifies the host permissions, the extensions should
-// have. If |has_background_script| is true, an empty background script
-// ("background.js") will also be persisted for the extension.
+// have. If |has_background_script| is true, a background script
+// ("background.js") will also be persisted for the extension. Clients can
+// listen in to the "ready" message from the background page to detect its
+// loading.
 void WriteManifestAndRuleset(
     const base::FilePath& extension_dir,
     const base::FilePath::CharType* json_rules_filepath,
diff --git a/extensions/test/extension_test_message_listener.cc b/extensions/test/extension_test_message_listener.cc
index 6119574..20167d5 100644
--- a/extensions/test/extension_test_message_listener.cc
+++ b/extensions/test/extension_test_message_listener.cc
@@ -76,6 +76,7 @@
   satisfied_ = false;
   failed_ = false;
   message_.clear();
+  extension_id_for_message_.clear();
   replied_ = false;
 }
 
@@ -89,13 +90,19 @@
   // extension.
   extensions::TestSendMessageFunction* function =
       content::Source<extensions::TestSendMessageFunction>(source).ptr();
+
+  std::string sender_extension_id;
+  if (function->extension())
+    sender_extension_id = function->extension_id();
+
   if (satisfied_ ||
-      (!extension_id_.empty() && function->extension_id() != extension_id_)) {
+      (!extension_id_.empty() && sender_extension_id != extension_id_)) {
     return;
   }
 
   // We should have an empty message if we're not already satisfied.
   CHECK(message_.empty());
+  CHECK(extension_id_for_message_.empty());
 
   std::pair<std::string, bool*>* message_details =
       content::Details<std::pair<std::string, bool*>>(details).ptr();
@@ -106,6 +113,7 @@
     // empty string.
     *message_details->second = true;
     message_ = message;
+    extension_id_for_message_ = sender_extension_id;
     satisfied_ = true;
     failed_ = (message_ == failure_message_);
 
diff --git a/extensions/test/extension_test_message_listener.h b/extensions/test/extension_test_message_listener.h
index 596632b9..4a728001 100644
--- a/extensions/test/extension_test_message_listener.h
+++ b/extensions/test/extension_test_message_listener.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/common/extension_id.h"
 
 namespace extensions {
 class TestSendMessageFunction;
@@ -94,7 +95,8 @@
   ~ExtensionTestMessageListener() override;
 
   // This returns true immediately if we've already gotten the expected
-  // message, or waits until it arrives.
+  // message, or waits until it arrives. Once this returns true, message() and
+  // extension_id_for_message() accessors can be used.
   // Returns false if the wait is interrupted and we still haven't gotten the
   // message, or if the message was equal to |failure_message_|.
   bool WaitUntilSatisfied() WARN_UNUSED_RESULT;
@@ -127,6 +129,10 @@
 
   const std::string& message() const { return message_; }
 
+  const extensions::ExtensionId& extension_id_for_message() const {
+    return extension_id_for_message_;
+  }
+
  private:
   // Implements the content::NotificationObserver interface.
   void Observe(int type,
@@ -167,6 +173,9 @@
   // If we received a message that was the failure message.
   bool failed_;
 
+  // The extension id from which |message_| was received.
+  extensions::ExtensionId extension_id_for_message_;
+
   // The function we need to reply to.
   scoped_refptr<extensions::TestSendMessageFunction> function_;
 };
diff --git a/google_apis/test/embedded_setup_chromeos.html b/google_apis/test/embedded_setup_chromeos.html
index 339bcb1..150402b 100644
--- a/google_apis/test/embedded_setup_chromeos.html
+++ b/google_apis/test/embedded_setup_chromeos.html
@@ -65,9 +65,22 @@
               passwordBytes: password,
               keyType: 'KEY_TYPE_PASSWORD_PLAIN'}
       }, '/');
-  var msg = {
+  var services = document.getElementById("services").value;
+  if (services) {
+    services = JSON.parse(services);
+    if (!services)
+      services = "Failed to parse test services JSON.";
+  } else if (email.endsWith('@corp.example.com') ||
+             email.endsWith('@example.test')) {
+    // SAML tests.
+    services = [];
+  } else {
+    services = "Services are not set for testing.";
+  }
+
+  msg = {
     'method': 'userInfo',
-    'services': [],
+    'services': services,
   };
   gaia.chromeOSLogin.parent_webview_.postMessage(msg,
       gaia.chromeOSLogin.parent_webview_url_);
@@ -140,6 +153,7 @@
   <div id="page2" hidden>
     Password
     <input id="password" name="password" type="password" spellcheck="false" autocomplete="off" formnovalidate="">
+    <input id="services" name="services" type="text" spellcheck="false" autocomplete="off" formnovalidate="">
   </div><br>
   <div id='nextButton' onclick='goNext();'>Next</div>
 </body>
diff --git a/headless/lib/browser/headless_devtools_client_impl.cc b/headless/lib/browser/headless_devtools_client_impl.cc
index 66ff3f3..5bcd2d1 100644
--- a/headless/lib/browser/headless_devtools_client_impl.cc
+++ b/headless/lib/browser/headless_devtools_client_impl.cc
@@ -200,11 +200,24 @@
       NOTREACHED() << "Badly formed event parameters";
       return false;
     }
-    it->second.Run(*result_dict);
+    // DevTools assumes event handling is async so we must post a task here or
+    // we risk breaking things.
+    browser_main_thread_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&HeadlessDevToolsClientImpl::DispatchEventTask,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       std::move(owning_message), &it->second, result_dict));
   }
   return true;
 }
 
+void HeadlessDevToolsClientImpl::DispatchEventTask(
+    std::unique_ptr<base::Value> owning_message,
+    const EventHandler* event_handler,
+    const base::DictionaryValue* result_dict) {
+  event_handler->Run(*result_dict);
+}
+
 void HeadlessDevToolsClientImpl::AgentHostClosed(
     content::DevToolsAgentHost* agent_host) {
   DCHECK_EQ(agent_host_, agent_host);
diff --git a/headless/lib/browser/protocol/target_handler.cc b/headless/lib/browser/protocol/target_handler.cc
index 6c80576..f4e5537 100644
--- a/headless/lib/browser/protocol/target_handler.cc
+++ b/headless/lib/browser/protocol/target_handler.cc
@@ -82,21 +82,16 @@
   return Response::OK();
 }
 
-Response TargetHandler::DisposeBrowserContext(const std::string& context_id) {
+Response TargetHandler::DisposeBrowserContext(const std::string& context_id,
+                                              bool* out_success) {
   HeadlessBrowserContext* context =
       browser()->GetBrowserContextForId(context_id);
 
-  if (!context)
-    return Response::InvalidParams("browserContextId");
-
-  std::vector<HeadlessWebContents*> web_contents = context->GetAllWebContents();
-  while (!web_contents.empty()) {
-    for (auto* wc : web_contents)
-      wc->Close();
-    // Since HeadlessWebContents::Close spawns a nested run loop to await
-    // closing, new web_contents could be opened. We need to re-query pages and
-    // close them too.
-    web_contents = context->GetAllWebContents();
+  *out_success = false;
+  if (context && context != browser()->GetDefaultBrowserContext() &&
+      context->GetAllWebContents().empty()) {
+    *out_success = true;
+    context->Close();
   }
   return Response::OK();
 }
diff --git a/headless/lib/browser/protocol/target_handler.h b/headless/lib/browser/protocol/target_handler.h
index f1100b4e..0f5a182 100644
--- a/headless/lib/browser/protocol/target_handler.h
+++ b/headless/lib/browser/protocol/target_handler.h
@@ -28,7 +28,8 @@
   Response CloseTarget(const std::string& target_id,
                        bool* out_success) override;
   Response CreateBrowserContext(std::string* out_context_id) override;
-  Response DisposeBrowserContext(const std::string& context_id) override;
+  Response DisposeBrowserContext(const std::string& context_id,
+                                 bool* out_success) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TargetHandler);
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index 9cd9553..6a3beb52 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -513,6 +513,7 @@
 
   void OnDisposeBrowserContextResult(
       std::unique_ptr<target::DisposeBrowserContextResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
     FinishAsynchronousTest();
   }
 
@@ -522,27 +523,16 @@
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainCreateAndDeleteBrowserContextTest);
 
-class TargetDomainDisposeContextSucceedsIfInUse
-    : public target::Observer,
-      public HeadlessAsyncDevTooledBrowserTest {
+class TargetDomainDisposeContextFailsIfInUse
+    : public HeadlessAsyncDevTooledBrowserTest {
   void RunDevTooledTest() override {
     EXPECT_TRUE(embedded_test_server()->Start());
+
     EXPECT_EQ(1u, GetAllWebContents(browser()).size());
-
-    devtools_client_->GetTarget()->AddObserver(this);
-    devtools_client_->GetTarget()->SetDiscoverTargets(
-        target::SetDiscoverTargetsParams::Builder().SetDiscover(true).Build(),
-        base::BindOnce(&TargetDomainDisposeContextSucceedsIfInUse::
-                           OnDiscoverTargetsEnabled,
-                       base::Unretained(this)));
-  }
-
-  void OnDiscoverTargetsEnabled(
-      std::unique_ptr<target::SetDiscoverTargetsResult> result) {
     devtools_client_->GetTarget()->GetExperimental()->CreateBrowserContext(
         target::CreateBrowserContextParams::Builder().Build(),
         base::BindOnce(
-            &TargetDomainDisposeContextSucceedsIfInUse::OnContextCreated,
+            &TargetDomainDisposeContextFailsIfInUse::OnContextCreated,
             base::Unretained(this)));
   }
 
@@ -556,7 +546,7 @@
             .SetBrowserContextId(context_id_)
             .Build(),
         base::BindOnce(
-            &TargetDomainDisposeContextSucceedsIfInUse::OnCreateTargetResult,
+            &TargetDomainDisposeContextFailsIfInUse::OnCreateTargetResult,
             base::Unretained(this)));
   }
 
@@ -564,38 +554,54 @@
       std::unique_ptr<target::CreateTargetResult> result) {
     page_id_ = result->GetTargetId();
 
-    destroyed_targets_.clear();
     devtools_client_->GetTarget()->GetExperimental()->DisposeBrowserContext(
         target::DisposeBrowserContextParams::Builder()
             .SetBrowserContextId(context_id_)
             .Build(),
-        base::BindOnce(&TargetDomainDisposeContextSucceedsIfInUse::
+        base::BindOnce(&TargetDomainDisposeContextFailsIfInUse::
                            OnDisposeBrowserContextResult,
                        base::Unretained(this)));
   }
 
-  void OnTargetDestroyed(const target::TargetDestroyedParams& params) override {
-    destroyed_targets_.push_back(params.GetTargetId());
-  }
-
   void OnDisposeBrowserContextResult(
       std::unique_ptr<target::DisposeBrowserContextResult> result) {
-    EXPECT_EQ(destroyed_targets_.size(), 1u);
-    EXPECT_EQ(destroyed_targets_[0], page_id_);
-    devtools_client_->GetTarget()->RemoveObserver(this);
+    EXPECT_FALSE(result->GetSuccess());
+
+    // Close the page and try again.
+    devtools_client_->GetTarget()->GetExperimental()->CloseTarget(
+        target::CloseTargetParams::Builder().SetTargetId(page_id_).Build(),
+        base::BindOnce(
+            &TargetDomainDisposeContextFailsIfInUse::OnCloseTargetResult,
+            base::Unretained(this)));
+  }
+
+  void OnCloseTargetResult(std::unique_ptr<target::CloseTargetResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
+
+    devtools_client_->GetTarget()->GetExperimental()->DisposeBrowserContext(
+        target::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_)
+            .Build(),
+        base::BindOnce(&TargetDomainDisposeContextFailsIfInUse::
+                           OnDisposeBrowserContextResult2,
+                       base::Unretained(this)));
+  }
+
+  void OnDisposeBrowserContextResult2(
+      std::unique_ptr<target::DisposeBrowserContextResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
     FinishAsynchronousTest();
   }
 
  private:
-  std::vector<std::string> destroyed_targets_;
   std::string context_id_;
   std::string page_id_;
 };
 
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainDisposeContextSucceedsIfInUse);
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(TargetDomainDisposeContextFailsIfInUse);
 
 class TargetDomainCreateTwoContexts : public HeadlessAsyncDevTooledBrowserTest,
-                                      public target::Observer,
+                                      public target::ExperimentalObserver,
                                       public page::Observer {
  public:
   void RunDevTooledTest() override {
@@ -606,15 +612,7 @@
     devtools_client_->GetPage()->Enable(run_loop.QuitClosure());
     run_loop.Run();
 
-    devtools_client_->GetTarget()->AddObserver(this);
-    devtools_client_->GetTarget()->SetDiscoverTargets(
-        target::SetDiscoverTargetsParams::Builder().SetDiscover(true).Build(),
-        base::BindOnce(&TargetDomainCreateTwoContexts::OnDiscoverTargetsEnabled,
-                       base::Unretained(this)));
-  }
-
-  void OnDiscoverTargetsEnabled(
-      std::unique_ptr<target::SetDiscoverTargetsResult> result) {
+    devtools_client_->GetTarget()->GetExperimental()->AddObserver(this);
     devtools_client_->GetTarget()->GetExperimental()->CreateBrowserContext(
         target::CreateBrowserContextParams::Builder().Build(),
         base::BindOnce(&TargetDomainCreateTwoContexts::OnContextOneCreated,
@@ -811,18 +809,18 @@
         EXPECT_EQ("", value_value->GetString())
             << "Page 2 should not share cookies from page one";
 
-        devtools_client_->GetTarget()->GetExperimental()->DisposeBrowserContext(
-            target::DisposeBrowserContextParams::Builder()
-                .SetBrowserContextId(context_id_one_)
+        devtools_client_->GetTarget()->GetExperimental()->CloseTarget(
+            target::CloseTargetParams::Builder()
+                .SetTargetId(page_id_one_)
                 .Build(),
-            base::BindOnce(&TargetDomainCreateTwoContexts::OnCloseContext,
+            base::BindOnce(&TargetDomainCreateTwoContexts::OnCloseTarget,
                            base::Unretained(this)));
 
-        devtools_client_->GetTarget()->GetExperimental()->DisposeBrowserContext(
-            target::DisposeBrowserContextParams::Builder()
-                .SetBrowserContextId(context_id_two_)
+        devtools_client_->GetTarget()->GetExperimental()->CloseTarget(
+            target::CloseTargetParams::Builder()
+                .SetTargetId(page_id_two_)
                 .Build(),
-            base::BindOnce(&TargetDomainCreateTwoContexts::OnCloseContext,
+            base::BindOnce(&TargetDomainCreateTwoContexts::OnCloseTarget,
                            base::Unretained(this)));
 
         devtools_client_->GetTarget()->GetExperimental()->RemoveObserver(this);
@@ -830,17 +828,33 @@
     }
   }
 
-  void OnTargetDestroyed(const target::TargetDestroyedParams& params) override {
-    ++page_close_count_;
+  void OnCloseTarget(std::unique_ptr<target::CloseTargetResult> result) {
+    page_close_count_++;
+
+    if (page_close_count_ < 2)
+      return;
+
+    devtools_client_->GetTarget()->GetExperimental()->DisposeBrowserContext(
+        target::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_one_)
+            .Build(),
+        base::BindOnce(&TargetDomainCreateTwoContexts::OnCloseContext,
+                       base::Unretained(this)));
+
+    devtools_client_->GetTarget()->GetExperimental()->DisposeBrowserContext(
+        target::DisposeBrowserContextParams::Builder()
+            .SetBrowserContextId(context_id_two_)
+            .Build(),
+        base::BindOnce(&TargetDomainCreateTwoContexts::OnCloseContext,
+                       base::Unretained(this)));
   }
 
   void OnCloseContext(
       std::unique_ptr<target::DisposeBrowserContextResult> result) {
+    EXPECT_TRUE(result->GetSuccess());
     if (++context_closed_count_ < 2)
       return;
-    EXPECT_EQ(page_close_count_, 2);
 
-    devtools_client_->GetTarget()->RemoveObserver(this);
     FinishAsynchronousTest();
   }
 
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 05ff2bf..85cc6e88 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -1256,6 +1256,11 @@
     }
     builders {
       mixins: "android-try"
+      name: "android_clang_dbg_recipe"
+      dimensions: "os:Ubuntu-14.04"
+    }
+    builders {
+      mixins: "android-try"
       name: "android_compile_dbg"
       dimensions: "os:Ubuntu-14.04"
     }
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 b1ebdbf..ba67c33b 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -23,8 +23,8 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h"
-#import "ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h"
+#import "ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/image_util/image_util.h"
@@ -74,7 +74,7 @@
 
 @interface BookmarkEditViewController ()<BookmarkFolderViewControllerDelegate,
                                          BookmarkModelBridgeObserver,
-                                         BookmarkTextFieldItemDelegate,
+                                         LegacyBookmarkTextFieldItemDelegate,
                                          TextFieldValidation> {
   // Flag to ignore bookmark model changes notifications.
   BOOL _ignoresBookmarkModelChanges;
@@ -108,9 +108,9 @@
 @property(nonatomic, strong) UIBarButtonItem* doneItem;
 
 // CollectionViewItem-s from the collection.
-@property(nonatomic, strong) BookmarkTextFieldItem* nameItem;
-@property(nonatomic, strong) BookmarkParentFolderItem* folderItem;
-@property(nonatomic, strong) BookmarkTextFieldItem* URLItem;
+@property(nonatomic, strong) LegacyBookmarkTextFieldItem* nameItem;
+@property(nonatomic, strong) LegacyBookmarkParentFolderItem* folderItem;
+@property(nonatomic, strong) LegacyBookmarkTextFieldItem* URLItem;
 
 // Reports the changes to the delegate, that has the responsibility to save the
 // bookmark.
@@ -327,7 +327,8 @@
 
   [model addSectionWithIdentifier:SectionIdentifierInfo];
 
-  self.nameItem = [[BookmarkTextFieldItem alloc] initWithType:ItemTypeName];
+  self.nameItem =
+      [[LegacyBookmarkTextFieldItem alloc] initWithType:ItemTypeName];
   self.nameItem.accessibilityIdentifier = @"Title Field";
   self.nameItem.placeholder =
       l10n_util::GetNSString(IDS_IOS_BOOKMARK_NAME_FIELD_HEADER);
@@ -336,11 +337,11 @@
   [model addItem:self.nameItem toSectionWithIdentifier:SectionIdentifierInfo];
 
   self.folderItem =
-      [[BookmarkParentFolderItem alloc] initWithType:ItemTypeFolder];
+      [[LegacyBookmarkParentFolderItem alloc] initWithType:ItemTypeFolder];
   self.folderItem.title = bookmark_utils_ios::TitleForBookmarkNode(self.folder);
   [model addItem:self.folderItem toSectionWithIdentifier:SectionIdentifierInfo];
 
-  self.URLItem = [[BookmarkTextFieldItem alloc] initWithType:ItemTypeURL];
+  self.URLItem = [[LegacyBookmarkTextFieldItem alloc] initWithType:ItemTypeURL];
   self.URLItem.accessibilityIdentifier = @"URL Field";
   self.URLItem.placeholder =
       l10n_util::GetNSString(IDS_IOS_BOOKMARK_URL_FIELD_HEADER);
@@ -410,9 +411,9 @@
   [self dismiss];
 }
 
-#pragma mark - BookmarkTextFieldItemDelegate
+#pragma mark - LegacyBookmarkTextFieldItemDelegate
 
-- (void)textDidChangeForItem:(BookmarkTextFieldItem*)item {
+- (void)textDidChangeForItem:(LegacyBookmarkTextFieldItem*)item {
   [self updateSaveButtonState];
 }
 
@@ -440,8 +441,8 @@
       [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
   if ([self.collectionViewModel itemTypeForIndexPath:indexPath] ==
       ItemTypeURL) {
-    BookmarkTextFieldCell* URLCell =
-        base::mac::ObjCCastStrict<BookmarkTextFieldCell>(cell);
+    LegacyBookmarkTextFieldCell* URLCell =
+        base::mac::ObjCCastStrict<LegacyBookmarkTextFieldCell>(cell);
     URLCell.textField.textValidator = self;
   }
   return cell;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
index b3d808a..a7c0285 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_folder_editor_view_controller.h
@@ -6,7 +6,7 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
+#import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 
 @class BookmarkFolderEditorViewController;
 
@@ -40,7 +40,7 @@
 // the title and selecting the parent folder of the bookmark.
 // This controller monitors the state of the bookmark model, so changes to the
 // bookmark model can affect this controller's state.
-@interface BookmarkFolderEditorViewController : CollectionViewController
+@interface BookmarkFolderEditorViewController : ChromeTableViewController
 
 @property(nonatomic, weak) id<BookmarkFolderEditorViewControllerDelegate>
     delegate;
@@ -62,8 +62,8 @@
                        folder:(const bookmarks::BookmarkNode*)folder
                  browserState:(ios::ChromeBrowserState*)browserState;
 
-- (instancetype)initWithLayout:(UICollectionViewLayout*)layout
-                         style:(CollectionViewControllerStyle)style
+- (instancetype)initWithTableViewStyle:(UICollectionViewLayout*)layout
+                           appBarStyle:(ChromeTableViewControllerStyle)style
     NS_UNAVAILABLE;
 
 @end
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 2b8ada4..6923ce0 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/ui/bookmarks/bookmark_elevated_toolbar.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_utils_ios.h"
@@ -25,6 +24,8 @@
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/material_components/utils.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
+#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #import "ios/chrome/browser/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"
@@ -73,9 +74,6 @@
 @property(nonatomic, weak) UIBarButtonItem* doneItem;
 @property(nonatomic, strong) BookmarkTextFieldItem* titleItem;
 @property(nonatomic, strong) BookmarkParentFolderItem* parentFolderItem;
-// Bottom toolbar with DELETE button that only appears when the edited folder
-// allows deletion.
-@property(nonatomic, weak) BookmarksElevatedToolbar* toolbar;
 
 // |bookmarkModel| must not be NULL and must be loaded.
 - (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel
@@ -87,12 +85,10 @@
 // Configures collection view model.
 - (void)setupCollectionViewModel;
 
-// Adds toolbar with DELETE button.
+// Bottom toolbar with DELETE button that only appears when the edited folder
+// allows deletion.
 - (void)addToolbar;
 
-// Removes toolbar.
-- (void)removeToolbar;
-
 @end
 
 @implementation BookmarkFolderEditorViewController
@@ -107,7 +103,6 @@
 @synthesize doneItem = _doneItem;
 @synthesize titleItem = _titleItem;
 @synthesize parentFolderItem = _parentFolderItem;
-@synthesize toolbar = _toolbar;
 
 #pragma mark - Class methods
 
@@ -143,9 +138,9 @@
 - (instancetype)initWithBookmarkModel:(bookmarks::BookmarkModel*)bookmarkModel {
   DCHECK(bookmarkModel);
   DCHECK(bookmarkModel->loaded());
-  UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
   self =
-      [super initWithLayout:layout style:CollectionViewControllerStyleAppBar];
+      [super initWithTableViewStyle:UITableViewStylePlain
+                        appBarStyle:ChromeTableViewControllerStyleWithAppBar];
   if (self) {
     _bookmarkModel = bookmarkModel;
 
@@ -165,7 +160,12 @@
 
 - (void)viewDidLoad {
   [super viewDidLoad];
-  self.collectionView.backgroundColor = [UIColor whiteColor];
+  self.tableView.backgroundColor = self.styler.tableViewBackgroundColor;
+  self.tableView.estimatedRowHeight = 150.0;
+  self.tableView.rowHeight = UITableViewAutomaticDimension;
+  self.tableView.sectionHeaderHeight = 0;
+  self.tableView.sectionFooterHeight = 0;
+  [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
 
   // Add Done button.
   UIBarButtonItem* doneItem = [[UIBarButtonItem alloc]
@@ -201,7 +201,6 @@
     backItem.accessibilityIdentifier = @"Back";
     self.navigationItem.leftBarButtonItem = backItem;
   }
-
   [self updateEditingState];
   [self setupCollectionViewModel];
 }
@@ -366,39 +365,17 @@
   return YES;
 }
 
-#pragma mark - UICollectionViewDelegate
+#pragma mark - UITableViewDelegate
 
-- (void)collectionView:(UICollectionView*)collectionView
-    didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
-  [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
-  if ([self.collectionViewModel itemTypeForIndexPath:indexPath] ==
+- (void)tableView:(UITableView*)tableView
+    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  DCHECK_EQ(tableView, self.tableView);
+  if ([self.tableViewModel itemTypeForIndexPath:indexPath] ==
       ItemTypeParentFolder) {
     [self changeParentFolder];
   }
 }
 
-#pragma mark - UICollectionViewFlowLayout
-
-- (CGSize)collectionView:(UICollectionView*)collectionView
-                    layout:(UICollectionViewLayout*)collectionViewLayout
-    sizeForItemAtIndexPath:(NSIndexPath*)indexPath {
-  switch ([self.collectionViewModel itemTypeForIndexPath:indexPath]) {
-    case ItemTypeFolderTitle: {
-      const CGFloat kTitleCellHeight = 96;
-      return CGSizeMake(CGRectGetWidth(collectionView.bounds),
-                        kTitleCellHeight);
-    }
-    case ItemTypeParentFolder: {
-      const CGFloat kParentFolderCellHeight = 50;
-      return CGSizeMake(CGRectGetWidth(collectionView.bounds),
-                        kParentFolderCellHeight);
-    }
-    default:
-      NOTREACHED();
-      return CGSizeZero;
-  }
-}
-
 #pragma mark - Private
 
 - (void)setParentFolder:(const BookmarkNode*)parentFolder {
@@ -424,23 +401,24 @@
 
 - (void)updateParentFolderState {
   NSIndexPath* folderSelectionIndexPath =
-      [self.collectionViewModel indexPathForItemType:ItemTypeParentFolder
-                                   sectionIdentifier:SectionIdentifierInfo];
+      [self.tableViewModel indexPathForItemType:ItemTypeParentFolder
+                              sectionIdentifier:SectionIdentifierInfo];
   self.parentFolderItem.title =
       bookmark_utils_ios::TitleForBookmarkNode(self.parentFolder);
-  [self.collectionView reloadItemsAtIndexPaths:@[ folderSelectionIndexPath ]];
+  [self.tableView reloadRowsAtIndexPaths:@[ folderSelectionIndexPath ]
+                        withRowAnimation:UITableViewRowAnimationNone];
 
-  if (self.editingExistingFolder && !self.toolbar)
+  if (self.editingExistingFolder && self.navigationController.isToolbarHidden)
     [self addToolbar];
 
-  if (!self.editingExistingFolder && self.toolbar)
-    [self removeToolbar];
+  if (!self.editingExistingFolder && !self.navigationController.isToolbarHidden)
+    self.navigationController.toolbarHidden = YES;
 }
 
 - (void)setupCollectionViewModel {
   [self loadModel];
 
-  [self.collectionViewModel addSectionWithIdentifier:SectionIdentifierInfo];
+  [self.tableViewModel addSectionWithIdentifier:SectionIdentifierInfo];
 
   BookmarkTextFieldItem* titleItem =
       [[BookmarkTextFieldItem alloc] initWithType:ItemTypeFolderTitle];
@@ -451,8 +429,8 @@
   titleItem.placeholder =
       l10n_util::GetNSString(IDS_IOS_BOOKMARK_NEW_EDITOR_NAME_LABEL);
   titleItem.accessibilityIdentifier = @"Title";
-  [self.collectionViewModel addItem:titleItem
-            toSectionWithIdentifier:SectionIdentifierInfo];
+  [self.tableViewModel addItem:titleItem
+       toSectionWithIdentifier:SectionIdentifierInfo];
   titleItem.delegate = self;
   self.titleItem = titleItem;
 
@@ -460,35 +438,27 @@
       [[BookmarkParentFolderItem alloc] initWithType:ItemTypeParentFolder];
   parentFolderItem.title =
       bookmark_utils_ios::TitleForBookmarkNode(self.parentFolder);
-  [self.collectionViewModel addItem:parentFolderItem
-            toSectionWithIdentifier:SectionIdentifierInfo];
+  [self.tableViewModel addItem:parentFolderItem
+       toSectionWithIdentifier:SectionIdentifierInfo];
   self.parentFolderItem = parentFolderItem;
 }
 
 - (void)addToolbar {
-  // Add bottom toolbar with Delete button.
-  BookmarksElevatedToolbar* buttonBar = [[BookmarksElevatedToolbar alloc] init];
-  MDCButton* deleteButton = [[MDCFlatButton alloc] init];
-  [deleteButton setTitle:l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_DELETE)
-                forState:UIControlStateNormal];
-  [deleteButton addTarget:self
-                   action:@selector(deleteFolder)
-         forControlEvents:UIControlEventTouchUpInside];
+  self.navigationController.toolbarHidden = NO;
+  NSString* titleString = l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_DELETE);
+  UIBarButtonItem* deleteButton =
+      [[UIBarButtonItem alloc] initWithTitle:titleString
+                                       style:UIBarButtonItemStylePlain
+                                      target:self
+                                      action:@selector(deleteFolder)];
   deleteButton.accessibilityIdentifier = @"Delete Folder";
+  deleteButton.tintColor = [UIColor blackColor];
 
-  [buttonBar setButton:deleteButton];
-  [self.view addSubview:buttonBar];
-
-  // Constraint |buttonBar| to be in bottom.
-  buttonBar.translatesAutoresizingMaskIntoConstraints = NO;
-  ApplyVisualConstraints(@[ @"H:|[buttonBar]|", @"V:[buttonBar]|" ],
-                         NSDictionaryOfVariableBindings(buttonBar));
-  self.toolbar = buttonBar;
-}
-
-- (void)removeToolbar {
-  [self.toolbar removeFromSuperview];
-  self.toolbar = nil;
+  UIBarButtonItem* spaceButton = [[UIBarButtonItem alloc]
+      initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
+                           target:nil
+                           action:nil];
+  [self setToolbarItems:@[ deleteButton, spaceButton ] animated:NO];
 }
 
 - (void)updateSaveButtonState {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index 8df69ff..ec57837a 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -1658,8 +1658,7 @@
   [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Folder Editor")]
       assertWithMatcher:grey_notNil()];
 
-  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
-                                          IDS_IOS_BOOKMARK_GROUP_DELETE)]
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Delete Folder")]
       performAction:grey_tap()];
 
   // Wait for Undo toast to go away from screen.
@@ -2073,8 +2072,7 @@
       performAction:grey_tap()];
 
   // Delete it.
-  [[EarlGrey selectElementWithMatcher:ButtonWithAccessibilityLabelId(
-                                          IDS_IOS_BOOKMARK_GROUP_DELETE)]
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Delete Folder")]
       performAction:grey_tap()];
 
   // Wait until it's gone.
diff --git a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
index 9fc3129..2d82fcd 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/cells/BUILD.gn
@@ -12,6 +12,10 @@
     "bookmark_table_signin_promo_cell.mm",
     "bookmark_text_field_item.h",
     "bookmark_text_field_item.mm",
+    "legacy_bookmark_parent_folder_item.h",
+    "legacy_bookmark_parent_folder_item.mm",
+    "legacy_bookmark_text_field_item.h",
+    "legacy_bookmark_text_field_item.mm",
   ]
 
   deps = [
@@ -23,6 +27,8 @@
     "//ios/chrome/browser/ui/collection_view/cells",
     "//ios/chrome/browser/ui/colors",
     "//ios/chrome/browser/ui/icons",
+    "//ios/chrome/browser/ui/table_view:styler",
+    "//ios/chrome/browser/ui/table_view/cells",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/ui",
     "//ios/third_party/material_components_ios",
@@ -43,6 +49,7 @@
   deps = [
     ":cells",
     "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/table_view:styler",
     "//ios/third_party/material_components_ios",
     "//testing/gtest",
     "//third_party/ocmock",
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
index 089ce93..2911634 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -7,11 +7,10 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
 
 // Item to display the name of the parent folder of a bookmark node.
-@interface BookmarkParentFolderItem : CollectionViewItem
+@interface BookmarkParentFolderItem : TableViewItem
 
 // The title of the bookmark folder it represents.
 @property(nonatomic, copy) NSString* title;
@@ -19,7 +18,7 @@
 @end
 
 // Cell class associated to BookmarkParentFolderItem.
-@interface BookmarkParentFolderCell : MDCCollectionViewCell
+@interface BookmarkParentFolderCell : UITableViewCell
 
 // Label that displays the item's title.
 @property(nonatomic, readonly, strong) UILabel* parentFolderNameLabel;
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 1e5b3e3..da67b89 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
@@ -1,9 +1,10 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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/bookmarks/cells/bookmark_parent_folder_item.h"
 
+#include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -15,11 +16,6 @@
 #error "This file requires ARC support."
 #endif
 
-@interface BookmarkParentFolderCell ()
-@property(nonatomic, readwrite, strong) UILabel* parentFolderNameLabel;
-@property(nonatomic, strong) UILabel* decorationLabel;
-@end
-
 @implementation BookmarkParentFolderItem
 
 @synthesize title = _title;
@@ -33,22 +29,31 @@
   return self;
 }
 
-#pragma mark CollectionViewItem
+#pragma mark TableViewItem
 
-- (void)configureCell:(BookmarkParentFolderCell*)cell {
-  [super configureCell:cell];
+- (void)configureCell:(UITableViewCell*)tableCell
+           withStyler:(ChromeTableViewStyler*)styler {
+  [super configureCell:tableCell withStyler:styler];
+  BookmarkParentFolderCell* cell =
+      base::mac::ObjCCastStrict<BookmarkParentFolderCell>(tableCell);
   cell.parentFolderNameLabel.text = self.title;
 }
 
 @end
 
+@interface BookmarkParentFolderCell ()
+@property(nonatomic, readwrite, strong) UILabel* parentFolderNameLabel;
+@property(nonatomic, strong) UILabel* decorationLabel;
+@end
+
 @implementation BookmarkParentFolderCell
 
 @synthesize parentFolderNameLabel = _parentFolderNameLabel;
 @synthesize decorationLabel = _decorationLabel;
 
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
+- (instancetype)initWithStyle:(UITableViewCellStyle)style
+              reuseIdentifier:(NSString*)reuseIdentifier {
+  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
   if (!self)
     return nil;
 
@@ -59,12 +64,15 @@
   const CGFloat kVerticalPadding = 8;
   const CGFloat kParentFolderLabelTopPadding = 7;
 
+  UIView* containerView = [[UIView alloc] initWithFrame:CGRectZero];
+  containerView.translatesAutoresizingMaskIntoConstraints = NO;
+
   _decorationLabel = [[UILabel alloc] init];
   _decorationLabel.translatesAutoresizingMaskIntoConstraints = NO;
   _decorationLabel.text = l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_BUTTON);
   _decorationLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
   _decorationLabel.textColor = bookmark_utils_ios::lightTextColor();
-  [self.contentView addSubview:_decorationLabel];
+  [containerView addSubview:_decorationLabel];
 
   _parentFolderNameLabel = [[UILabel alloc] init];
   _parentFolderNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
@@ -73,25 +81,29 @@
   _parentFolderNameLabel.textColor =
       [UIColor colorWithWhite:33.0 / 255.0 alpha:1.0];
   _parentFolderNameLabel.textAlignment = NSTextAlignmentNatural;
-  [self.contentView addSubview:_parentFolderNameLabel];
+  [containerView addSubview:_parentFolderNameLabel];
 
   UIImageView* navigationChevronImage = [[UIImageView alloc] init];
   UIImage* image = TintImage([ChromeIcon chevronIcon], [UIColor grayColor]);
   navigationChevronImage.image = image;
   navigationChevronImage.translatesAutoresizingMaskIntoConstraints = NO;
-  [self.contentView addSubview:navigationChevronImage];
+  [containerView addSubview:navigationChevronImage];
+
+  [self.contentView addSubview:containerView];
 
   // Set up the constraints.
   [NSLayoutConstraint activateConstraints:@[
-    [_decorationLabel.topAnchor constraintEqualToAnchor:self.topAnchor
-                                               constant:kVerticalPadding],
-    [_decorationLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
-                                                   constant:kHorizontalPadding],
+    [_decorationLabel.topAnchor
+        constraintEqualToAnchor:containerView.topAnchor],
+    [_decorationLabel.leadingAnchor
+        constraintEqualToAnchor:containerView.leadingAnchor],
     [_parentFolderNameLabel.topAnchor
         constraintEqualToAnchor:_decorationLabel.bottomAnchor
                        constant:kParentFolderLabelTopPadding],
     [_parentFolderNameLabel.leadingAnchor
         constraintEqualToAnchor:_decorationLabel.leadingAnchor],
+    [_parentFolderNameLabel.bottomAnchor
+        constraintEqualToAnchor:containerView.bottomAnchor],
     [navigationChevronImage.centerYAnchor
         constraintEqualToAnchor:_parentFolderNameLabel.centerYAnchor],
     [navigationChevronImage.leadingAnchor
@@ -99,11 +111,20 @@
     [navigationChevronImage.widthAnchor
         constraintEqualToConstant:navigationChevronImage.image.size.width],
     [navigationChevronImage.trailingAnchor
-        constraintEqualToAnchor:self.trailingAnchor
+        constraintEqualToAnchor:containerView.trailingAnchor],
+    [containerView.leadingAnchor
+        constraintEqualToAnchor:self.contentView.leadingAnchor
+                       constant:kHorizontalPadding],
+    [containerView.trailingAnchor
+        constraintEqualToAnchor:self.contentView.trailingAnchor
                        constant:-kHorizontalPadding],
+    [containerView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor
+                                            constant:kVerticalPadding],
+    [containerView.bottomAnchor
+        constraintEqualToAnchor:self.contentView.bottomAnchor
+                       constant:-kVerticalPadding],
   ]];
 
-  self.shouldHideSeparator = YES;
   return self;
 }
 
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm
index cd6d122..55d823c 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item_unittest.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_parent_folder_item.h"
 
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -22,9 +23,10 @@
       [[BookmarkParentFolderItem alloc] initWithType:0];
   BookmarkParentFolderCell* cell =
       [[BookmarkParentFolderCell alloc] initWithFrame:CGRectZero];
+  ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
 
   item.title = @"Foo";
-  [item configureCell:cell];
+  [item configureCell:cell withStyler:styler];
   EXPECT_NSEQ(@"Foo", cell.parentFolderNameLabel.text);
 }
 
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 df3cffba..51fd641 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
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -7,8 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
 
 @class BookmarkTextFieldItem;
 @protocol TextFieldStyling;
@@ -22,7 +21,7 @@
 
 @end
 
-@interface BookmarkTextFieldItem : CollectionViewItem
+@interface BookmarkTextFieldItem : TableViewItem
 
 // The text field content.
 @property(nonatomic, copy) NSString* text;
@@ -35,7 +34,7 @@
 
 @end
 
-@interface BookmarkTextFieldCell : MDCCollectionViewCell
+@interface BookmarkTextFieldCell : UITableViewCell
 
 // Text field to display the title or the URL of the bookmark node.
 @property(nonatomic, readonly, strong) UITextField<TextFieldStyling>* textField;
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 d41f952..e7364e49 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
@@ -1,10 +1,11 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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/bookmarks/cells/bookmark_text_field_item.h"
 
 #include "base/logging.h"
+#include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/text_field_styling.h"
@@ -13,11 +14,6 @@
 #error "This file requires ARC support."
 #endif
 
-@interface BookmarkTextFieldCell ()
-@property(nonatomic, readwrite, strong)
-    UITextField<TextFieldStyling>* textField;
-@end
-
 @implementation BookmarkTextFieldItem
 
 @synthesize text = _text;
@@ -32,10 +28,14 @@
   return self;
 }
 
-#pragma mark CollectionViewItem
+#pragma mark TableViewItem
 
-- (void)configureCell:(BookmarkTextFieldCell*)cell {
-  [super configureCell:cell];
+- (void)configureCell:(UITableViewCell*)tableCell
+           withStyler:(ChromeTableViewStyler*)styler {
+  [super configureCell:tableCell withStyler:styler];
+
+  BookmarkTextFieldCell* cell =
+      base::mac::ObjCCastStrict<BookmarkTextFieldCell>(tableCell);
   cell.textField.text = self.text;
   cell.textField.placeholder = self.placeholder;
   cell.textField.tag = self.type;
@@ -58,14 +58,19 @@
 
 @end
 
+@interface BookmarkTextFieldCell ()
+@property(nonatomic, readwrite, strong)
+    UITextField<TextFieldStyling>* textField;
+@end
+
 @implementation BookmarkTextFieldCell
 
 @synthesize textField = _textField;
 
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
+- (instancetype)initWithStyle:(UITableViewCellStyle)style
+              reuseIdentifier:(NSString*)reuseIdentifier {
+  self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
   if (self) {
-
     _textField =
         ios::GetChromeBrowserProvider()->CreateStyledTextField(CGRectZero);
     _textField.translatesAutoresizingMaskIntoConstraints = NO;
@@ -77,15 +82,18 @@
     const CGFloat kHorizontalPadding = 15;
     const CGFloat kTopPadding = 8;
     [NSLayoutConstraint activateConstraints:@[
-      [_textField.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
-                                               constant:kHorizontalPadding],
-      [_textField.topAnchor constraintEqualToAnchor:self.topAnchor
+      [_textField.leadingAnchor
+          constraintEqualToAnchor:self.contentView.leadingAnchor
+                         constant:kHorizontalPadding],
+      [_textField.topAnchor constraintEqualToAnchor:self.contentView.topAnchor
                                            constant:kTopPadding],
-      [_textField.trailingAnchor constraintEqualToAnchor:self.trailingAnchor
-                                                constant:-kHorizontalPadding],
+      [_textField.trailingAnchor
+          constraintEqualToAnchor:self.contentView.trailingAnchor
+                         constant:-kHorizontalPadding],
+      [_textField.bottomAnchor
+          constraintEqualToAnchor:self.contentView.bottomAnchor
+                         constant:-kTopPadding],
     ]];
-
-    self.shouldHideSeparator = YES;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm
index 239c1ed..eebf1ed1 100644
--- a/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item_unittest.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_text_field_item.h"
 
+#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
@@ -23,9 +24,10 @@
       [[BookmarkTextFieldCell alloc] initWithFrame:CGRectZero];
   id mockDelegate =
       [OCMockObject mockForProtocol:@protocol(BookmarkTextFieldItemDelegate)];
+  ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
 
   item.delegate = mockDelegate;
-  [item configureCell:cell];
+  [item configureCell:cell withStyler:styler];
   EXPECT_EQ(mockDelegate, cell.textField.delegate);
 
   [[mockDelegate expect] textDidChangeForItem:item];
@@ -36,9 +38,10 @@
   BookmarkTextFieldItem* item = [[BookmarkTextFieldItem alloc] initWithType:0];
   BookmarkTextFieldCell* cell =
       [[BookmarkTextFieldCell alloc] initWithFrame:CGRectZero];
+  ChromeTableViewStyler* styler = [[ChromeTableViewStyler alloc] init];
 
   item.text = @"Foo";
-  [item configureCell:cell];
+  [item configureCell:cell withStyler:styler];
   EXPECT_NSEQ(@"Foo", cell.textField.text);
 }
 
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h
new file mode 100644
index 0000000..0d36c90
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_PARENT_FOLDER_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_PARENT_FOLDER_ITEM_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
+
+// Item to display the name of the parent folder of a bookmark node.
+@interface LegacyBookmarkParentFolderItem : CollectionViewItem
+
+// The title of the bookmark folder it represents.
+@property(nonatomic, copy) NSString* title;
+
+@end
+
+// Cell class associated to LegacyBookmarkParentFolderItem.
+@interface LegacyBookmarkParentFolderCell : MDCCollectionViewCell
+
+// Label that displays the item's title.
+@property(nonatomic, readonly, strong) UILabel* parentFolderNameLabel;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_PARENT_FOLDER_ITEM_H_
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.mm b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.mm
new file mode 100644
index 0000000..76e1f6c5
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.mm
@@ -0,0 +1,124 @@
+// 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.
+
+#import "ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_parent_folder_item.h"
+
+#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/chrome/browser/ui/icons/chrome_icon.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface LegacyBookmarkParentFolderCell ()
+@property(nonatomic, readwrite, strong) UILabel* parentFolderNameLabel;
+@property(nonatomic, strong) UILabel* decorationLabel;
+@end
+
+@implementation LegacyBookmarkParentFolderItem
+
+@synthesize title = _title;
+
+- (instancetype)initWithType:(NSInteger)type {
+  self = [super initWithType:type];
+  if (self) {
+    self.accessibilityIdentifier = @"Change Folder";
+    self.cellClass = [LegacyBookmarkParentFolderCell class];
+  }
+  return self;
+}
+
+#pragma mark CollectionViewItem
+
+- (void)configureCell:(LegacyBookmarkParentFolderCell*)cell {
+  [super configureCell:cell];
+  cell.parentFolderNameLabel.text = self.title;
+}
+
+@end
+
+@implementation LegacyBookmarkParentFolderCell
+
+@synthesize parentFolderNameLabel = _parentFolderNameLabel;
+@synthesize decorationLabel = _decorationLabel;
+
+- (instancetype)initWithFrame:(CGRect)frame {
+  self = [super initWithFrame:frame];
+  if (!self)
+    return nil;
+
+  self.isAccessibilityElement = YES;
+  self.accessibilityTraits |= UIAccessibilityTraitButton;
+
+  const CGFloat kHorizontalPadding = 15;
+  const CGFloat kVerticalPadding = 8;
+  const CGFloat kParentFolderLabelTopPadding = 7;
+
+  _decorationLabel = [[UILabel alloc] init];
+  _decorationLabel.translatesAutoresizingMaskIntoConstraints = NO;
+  _decorationLabel.text = l10n_util::GetNSString(IDS_IOS_BOOKMARK_GROUP_BUTTON);
+  _decorationLabel.font = [[MDCTypography fontLoader] regularFontOfSize:12];
+  _decorationLabel.textColor = bookmark_utils_ios::lightTextColor();
+  [self.contentView addSubview:_decorationLabel];
+
+  _parentFolderNameLabel = [[UILabel alloc] init];
+  _parentFolderNameLabel.translatesAutoresizingMaskIntoConstraints = NO;
+  _parentFolderNameLabel.font =
+      [[MDCTypography fontLoader] regularFontOfSize:16];
+  _parentFolderNameLabel.textColor =
+      [UIColor colorWithWhite:33.0 / 255.0 alpha:1.0];
+  _parentFolderNameLabel.textAlignment = NSTextAlignmentNatural;
+  [self.contentView addSubview:_parentFolderNameLabel];
+
+  UIImageView* navigationChevronImage = [[UIImageView alloc] init];
+  UIImage* image = TintImage([ChromeIcon chevronIcon], [UIColor grayColor]);
+  navigationChevronImage.image = image;
+  navigationChevronImage.translatesAutoresizingMaskIntoConstraints = NO;
+  [self.contentView addSubview:navigationChevronImage];
+
+  // Set up the constraints.
+  [NSLayoutConstraint activateConstraints:@[
+    [_decorationLabel.topAnchor constraintEqualToAnchor:self.topAnchor
+                                               constant:kVerticalPadding],
+    [_decorationLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor
+                                                   constant:kHorizontalPadding],
+    [_parentFolderNameLabel.topAnchor
+        constraintEqualToAnchor:_decorationLabel.bottomAnchor
+                       constant:kParentFolderLabelTopPadding],
+    [_parentFolderNameLabel.leadingAnchor
+        constraintEqualToAnchor:_decorationLabel.leadingAnchor],
+    [navigationChevronImage.centerYAnchor
+        constraintEqualToAnchor:_parentFolderNameLabel.centerYAnchor],
+    [navigationChevronImage.leadingAnchor
+        constraintEqualToAnchor:_parentFolderNameLabel.trailingAnchor],
+    [navigationChevronImage.widthAnchor
+        constraintEqualToConstant:navigationChevronImage.image.size.width],
+    [navigationChevronImage.trailingAnchor
+        constraintEqualToAnchor:self.trailingAnchor
+                       constant:-kHorizontalPadding],
+  ]];
+
+  self.shouldHideSeparator = YES;
+  return self;
+}
+
+- (void)prepareForReuse {
+  [super prepareForReuse];
+  self.parentFolderNameLabel.text = nil;
+}
+
+- (NSString*)accessibilityLabel {
+  return self.parentFolderNameLabel.text;
+}
+
+- (NSString*)accessibilityHint {
+  return l10n_util::GetNSString(
+      IDS_IOS_BOOKMARK_EDIT_PARENT_FOLDER_BUTTON_HINT);
+}
+
+@end
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h
new file mode 100644
index 0000000..b2fc511
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_TEXT_FIELD_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_BOOKMARKS_CELLS_LEGACY_BOOKMARK_TEXT_FIELD_ITEM_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
+
+@class LegacyBookmarkTextFieldItem;
+@protocol TextFieldStyling;
+
+// Delegates the cell's text field's events.
+@protocol LegacyBookmarkTextFieldItemDelegate<UITextFieldDelegate>
+
+// Called when the |text| of the item was changed via the textfield. The item's
+// |text| is up-to-date when this is called.
+- (void)textDidChangeForItem:(LegacyBookmarkTextFieldItem*)item;
+
+@end
+
+@interface LegacyBookmarkTextFieldItem : CollectionViewItem
+
+// The text field content.
+@property(nonatomic, copy) NSString* text;
+
+// The text field placeholder.
+@property(nonatomic, copy) NSString* placeholder;
+
+// Receives the text field events.
+@property(nonatomic, weak) id<LegacyBookmarkTextFieldItemDelegate> delegate;
+
+@end
+
+@interface LegacyBookmarkTextFieldCell : MDCCollectionViewCell
+
+// 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_LEGACY_BOOKMARK_TEXT_FIELD_ITEM_H_
diff --git a/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.mm b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.mm
new file mode 100644
index 0000000..b6acb9b
--- /dev/null
+++ b/ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.mm
@@ -0,0 +1,103 @@
+// 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.
+
+#import "ios/chrome/browser/ui/bookmarks/cells/legacy_bookmark_text_field_item.h"
+
+#include "base/logging.h"
+#import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#import "ios/public/provider/chrome/browser/ui/text_field_styling.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface LegacyBookmarkTextFieldCell ()
+@property(nonatomic, readwrite, strong)
+    UITextField<TextFieldStyling>* textField;
+@end
+
+@implementation LegacyBookmarkTextFieldItem
+
+@synthesize text = _text;
+@synthesize placeholder = _placeholder;
+@synthesize delegate = _delegate;
+
+- (instancetype)initWithType:(NSInteger)type {
+  self = [super initWithType:type];
+  if (self) {
+    self.cellClass = [LegacyBookmarkTextFieldCell class];
+  }
+  return self;
+}
+
+#pragma mark CollectionViewItem
+
+- (void)configureCell:(LegacyBookmarkTextFieldCell*)cell {
+  [super configureCell:cell];
+  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];
+}
+
+#pragma mark UIControlEventEditingChanged
+
+- (void)textFieldDidChange:(UITextField*)textField {
+  DCHECK_EQ(textField.tag, self.type);
+  self.text = textField.text;
+  [self.delegate textDidChangeForItem:self];
+}
+
+@end
+
+@implementation LegacyBookmarkTextFieldCell
+
+@synthesize textField = _textField;
+
+- (instancetype)initWithFrame:(CGRect)frame {
+  self = [super initWithFrame:frame];
+  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.leadingAnchor
+                                               constant:kHorizontalPadding],
+      [_textField.topAnchor constraintEqualToAnchor:self.topAnchor
+                                           constant:kTopPadding],
+      [_textField.trailingAnchor constraintEqualToAnchor:self.trailingAnchor
+                                                constant:-kHorizontalPadding],
+    ]];
+
+    self.shouldHideSeparator = YES;
+  }
+  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/third_party/material_components_ios/README.chromium b/ios/third_party/material_components_ios/README.chromium
index d3d75a5b..2b03271 100644
--- a/ios/third_party/material_components_ios/README.chromium
+++ b/ios/third_party/material_components_ios/README.chromium
@@ -1,7 +1,7 @@
 Name: Material Components for iOS
 URL: https://github.com/material-components/material-components-ios
 Version: 0
-Revision: 5ee7e2e3a845c5ca7e3d8a5a0d2ab4faddb52da5
+Revision: dc1eae3b21358b4761a09e7c586bc69f3695eb6e
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 2127862..a1467fa 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -174,9 +174,8 @@
     deps += [ "//media/remoting:media_remoting_tests" ]
   }
 
-  if (proprietary_codecs) {
-    configs += [ "//third_party/opus:opus_config" ]
-  }
+  # The test needs OPUS_FIXED_POINT conditional define.
+  configs += [ "//third_party/opus:opus_config" ]
 }
 
 test("media_perftests") {
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 0891a26..c7aa2bf1 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -269,10 +269,6 @@
 const base::Feature kMseBufferByPts{"MseBufferByPts",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Support FLAC codec within ISOBMFF streams used with Media Source Extensions.
-const base::Feature kMseFlacInIsobmff{"MseFlacInIsobmff",
-                                      base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enable new cpu load estimator. Intended for evaluation in local
 // testing and origin-trial.
 // TODO(nisse): Delete once we have switched over to always using the
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 2c3d82c..c9077f9e 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -115,7 +115,6 @@
 MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC;
 MEDIA_EXPORT extern const base::Feature kMojoVideoDecoder;
 MEDIA_EXPORT extern const base::Feature kMseBufferByPts;
-MEDIA_EXPORT extern const base::Feature kMseFlacInIsobmff;
 MEDIA_EXPORT extern const base::Feature kNewAudioRenderingMixingStrategy;
 MEDIA_EXPORT extern const base::Feature kNewEncodeCpuLoadEstimator;
 MEDIA_EXPORT extern const base::Feature kNewRemotePlaybackPipeline;
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
index b625de0..294cd39 100644
--- a/media/base/mime_util_unittest.cc
+++ b/media/base/mime_util_unittest.cc
@@ -326,10 +326,8 @@
   // Valid FLAC string with MP4. Neither decoding nor demuxing is proprietary.
   EXPECT_TRUE(ParseAudioCodecString("audio/mp4", "flac", &out_is_ambiguous,
                                     &out_codec));
-  if (kUsePropCodecs) {
-    EXPECT_FALSE(out_is_ambiguous);
-    EXPECT_EQ(kCodecFLAC, out_codec);
-  }
+  EXPECT_FALSE(out_is_ambiguous);
+  EXPECT_EQ(kCodecFLAC, out_codec);
 
   // Ambiguous AAC string.
   // TODO(chcunningha): This can probably be allowed. I think we treat all
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 5f55d6a..3780302 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -385,8 +385,7 @@
 
 void WebMediaPlayerImpl::RegisterContentsLayer(blink::WebLayer* web_layer) {
   DCHECK(bridge_);
-  bridge_->GetWebLayer()->CcLayer()->SetContentsOpaque(opaque_);
-  bridge_->GetWebLayer()->SetContentsOpaqueIsFixed(true);
+  bridge_->GetWebLayer()->SetOpaque(opaque_);
   client_->SetWebLayer(web_layer);
 }
 
@@ -1606,8 +1605,7 @@
       video_weblayer_.reset(new cc_blink::WebLayerImpl(cc::VideoLayer::Create(
           compositor_.get(),
           pipeline_metadata_.video_decoder_config.video_rotation())));
-      video_weblayer_->layer()->SetContentsOpaque(opaque_);
-      video_weblayer_->SetContentsOpaqueIsFixed(true);
+      video_weblayer_->SetOpaque(opaque_);
       client_->SetWebLayer(video_weblayer_.get());
     } else {
       vfc_task_runner_->PostTask(
@@ -1867,13 +1865,11 @@
   DCHECK_NE(ready_state_, WebMediaPlayer::kReadyStateHaveNothing);
 
   opaque_ = opaque;
-  // Modify content opaqueness of cc::Layer directly so that
-  // SetContentsOpaqueIsFixed is ignored.
   if (!surface_layer_for_video_enabled_) {
     if (video_weblayer_)
-      video_weblayer_->layer()->SetContentsOpaque(opaque_);
+      video_weblayer_->SetOpaque(opaque_);
   } else if (bridge_->GetWebLayer()) {
-    bridge_->GetWebLayer()->CcLayer()->SetContentsOpaque(opaque_);
+    bridge_->GetWebLayer()->SetOpaque(opaque_);
   }
 }
 
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index 6b3ce992..6df10b2 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -201,7 +201,6 @@
           12719);
 }
 
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST_F(AudioFileReaderTest, MP3) {
   RunTest("sfx.mp3",
           "1.30,2.72,4.56,5.08,3.74,2.03,",
@@ -225,6 +224,7 @@
           44928);
 }
 
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST_F(AudioFileReaderTest, AAC) {
   RunTest("sfx.m4a", "1.81,1.66,2.32,3.27,4.46,3.36,", 1, 44100,
           base::TimeDelta::FromMicroseconds(371660), 16391, 13312);
diff --git a/media/filters/audio_video_metadata_extractor_unittest.cc b/media/filters/audio_video_metadata_extractor_unittest.cc
index 022efcc..7e5793a 100644
--- a/media/filters/audio_video_metadata_extractor_unittest.cc
+++ b/media/filters/audio_video_metadata_extractor_unittest.cc
@@ -185,6 +185,7 @@
 
   EXPECT_EQ(0u, extractor->attached_images_bytes().size());
 }
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 TEST(AudioVideoMetadataExtractorTest, AudioMP3) {
   std::unique_ptr<AudioVideoMetadataExtractor> extractor =
@@ -259,6 +260,5 @@
 
   EXPECT_EQ(0u, extractor->attached_images_bytes().size());
 }
-#endif
 
 }  // namespace media
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index e630715..50fc1bc8 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -235,12 +235,6 @@
   if (!SBSTREAM_IS_SET) {
     DCHECK_EQ(state_, UNINITIALIZED);
 
-    // FLAC in MSE here is only supported if in ISOBMFF, which has feature flag.
-    // Though the MP4StreamParser shouldn't produce FLAC decoder configs if the
-    // feature is disabled, double-check feature support here in debug builds.
-    DCHECK(config.codec() != kCodecFLAC ||
-           base::FeatureList::IsEnabled(kMseFlacInIsobmff));
-
     // Enable partial append window support for most audio codecs (notably: not
     // opus).
     partial_append_window_trimming_enabled_ =
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index d4b55e6..253d889 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -1230,7 +1230,6 @@
   base::RunLoop().Run();
 }
 
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 // Ensure ID3v1 tag reading is disabled.  id3_test.mp3 has an ID3v1 tag with the
 // field "title" set to "sample for id3 test".
 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
@@ -1238,9 +1237,7 @@
   InitializeDemuxer();
   EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
 }
-#endif
 
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 // Ensure MP3 files with large image/video based ID3 tags demux okay.  FFmpeg
 // will hand us a video stream to the data which will likely be in a format we
 // don't accept as video; e.g. PNG.
@@ -1260,7 +1257,6 @@
   EXPECT_FALSE(GetStream(DemuxerStream::VIDEO));
   EXPECT_TRUE(GetStream(DemuxerStream::AUDIO));
 }
-#endif
 
 // Ensure a video with an unsupported audio track still results in the video
 // stream being demuxed. Because we disable the speex parser for ogg, the audio
@@ -1303,6 +1299,7 @@
   InitializeDemuxer();
   ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
 }
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 class Mp3SeekFFmpegDemuxerTest
     : public FFmpegDemuxerTest,
@@ -1344,6 +1341,7 @@
                                           "bear-audio-10s-VBR-has-TOC.mp3",
                                           "bear-audio-10s-VBR-no-TOC.mp3"));
 
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 static void ValidateAnnexB(DemuxerStream* stream,
                            DemuxerStream::Status status,
                            scoped_refptr<DecoderBuffer> buffer) {
@@ -1710,7 +1708,6 @@
                    44100, kSampleFormatS32);
 }
 
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST_F(FFmpegDemuxerTest, Read_Flac_Mp4) {
   CreateDemuxer("bear-flac.mp4");
   InitializeDemuxer();
@@ -1732,7 +1729,6 @@
   VerifyFlacStream(GetStream(DemuxerStream::AUDIO), 32, CHANNEL_LAYOUT_STEREO,
                    192000, kSampleFormatS32);
 }
-#endif  // USE_PROPRIETARY_CODECS
 
 // Verify that FFmpeg demuxer falls back to choosing disabled streams for
 // seeking if there's no suitable enabled stream found.
diff --git a/media/filters/ffmpeg_glue_unittest.cc b/media/filters/ffmpeg_glue_unittest.cc
index 2289d83..e51019c 100644
--- a/media/filters/ffmpeg_glue_unittest.cc
+++ b/media/filters/ffmpeg_glue_unittest.cc
@@ -299,17 +299,17 @@
   ExpectContainer(container_names::CONTAINER_WAV);
 }
 
+TEST_F(FFmpegGlueContainerTest, MP3) {
+  InitializeAndOpen("sfx.mp3");
+  ExpectContainer(container_names::CONTAINER_MP3);
+}
+
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST_F(FFmpegGlueContainerTest, MOV) {
   InitializeAndOpen("sfx.m4a");
   ExpectContainer(container_names::CONTAINER_MOV);
 }
 
-TEST_F(FFmpegGlueContainerTest, MP3) {
-  InitializeAndOpen("sfx.mp3");
-  ExpectContainer(container_names::CONTAINER_MP3);
-}
-
 TEST_F(FFmpegGlueContainerTest, AAC) {
   InitializeAndOpen("sfx.adts");
   ExpectContainer(container_names::CONTAINER_AAC);
diff --git a/media/filters/media_file_checker_unittest.cc b/media/filters/media_file_checker_unittest.cc
index 27d47960..9ee40bf9 100644
--- a/media/filters/media_file_checker_unittest.cc
+++ b/media/filters/media_file_checker_unittest.cc
@@ -38,10 +38,8 @@
   RunMediaFileChecker("sfx.ogg", true);
 }
 
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 TEST(MediaFileCheckerTest, MP3) {
   RunMediaFileChecker("sfx.mp3", true);
 }
-#endif
 
 }  // namespace media
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc
index 927c8b7..f9e9601 100644
--- a/media/filters/stream_parser_factory.cc
+++ b/media/filters/stream_parser_factory.cc
@@ -217,15 +217,9 @@
   return new MPEG1AudioStreamParser();
 }
 
-bool CheckIfMseFlacInIsobmffEnabled(const std::string& codec_id,
-                                    MediaLog* media_log) {
-  return base::FeatureList::IsEnabled(kMseFlacInIsobmff);
-}
-
 static const CodecInfo kMPEG4VP09CodecInfo = {
     "vp09.*", CodecInfo::VIDEO, nullptr, CodecInfo::HISTOGRAM_VP9};
-static const CodecInfo kMPEG4FLACCodecInfo = {"flac", CodecInfo::AUDIO,
-                                              &CheckIfMseFlacInIsobmffEnabled,
+static const CodecInfo kMPEG4FLACCodecInfo = {"flac", CodecInfo::AUDIO, nullptr,
                                               CodecInfo::HISTOGRAM_FLAC};
 
 static const CodecInfo* const kVideoMP4Codecs[] = {&kMPEG4FLACCodecInfo,
diff --git a/media/formats/BUILD.gn b/media/formats/BUILD.gn
index c8d616e..1ed89cb 100644
--- a/media/formats/BUILD.gn
+++ b/media/formats/BUILD.gn
@@ -162,6 +162,8 @@
   visibility = [ "//media:test_support" ]
 
   sources = [
+    "common/stream_parser_test_base.cc",
+    "common/stream_parser_test_base.h",
     "webm/cluster_builder.cc",
     "webm/cluster_builder.h",
     "webm/opus_packet_builder.cc",
@@ -178,22 +180,14 @@
   deps = [
     "//base/test:test_support",
     "//media/base:test_support",
+    "//testing/gtest",
   ]
 
-  if (proprietary_codecs) {
+  if (proprietary_codecs && enable_mse_mpeg2ts_stream_parser) {
     sources += [
-      "common/stream_parser_test_base.cc",
-      "common/stream_parser_test_base.h",
+      "mp2t/es_parser_test_base.cc",
+      "mp2t/es_parser_test_base.h",
     ]
-
-    deps += [ "//testing/gtest" ]
-
-    if (enable_mse_mpeg2ts_stream_parser) {
-      sources += [
-        "mp2t/es_parser_test_base.cc",
-        "mp2t/es_parser_test_base.h",
-      ]
-    }
   }
 }
 
@@ -202,6 +196,7 @@
   sources = [
     "ac3/ac3_util_unittest.cc",
     "common/offset_byte_queue_unittest.cc",
+    "mpeg/mpeg1_audio_stream_parser_unittest.cc",
     "webm/webm_cluster_parser_unittest.cc",
     "webm/webm_content_encodings_client_unittest.cc",
     "webm/webm_crypto_helpers_unittest.cc",
@@ -234,7 +229,6 @@
       "mp4/sample_to_group_iterator_unittest.cc",
       "mp4/track_run_iterator_unittest.cc",
       "mpeg/adts_stream_parser_unittest.cc",
-      "mpeg/mpeg1_audio_stream_parser_unittest.cc",
     ]
 
     deps += [ "//crypto" ]
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index 7dd4198..6def180 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -1040,10 +1040,6 @@
   // Read the FLACSpecificBox, even if CENC is signalled.
   if (format == FOURCC_FLAC ||
       (format == FOURCC_ENCA && sinf.format.format == FOURCC_FLAC)) {
-    RCHECK_MEDIA_LOGGED(base::FeatureList::IsEnabled(kMseFlacInIsobmff),
-                        reader->media_log(),
-                        "MSE support for FLAC in MP4 is not enabled.");
-
     RCHECK_MEDIA_LOGGED(reader->ReadChild(&dfla), reader->media_log(),
                         "Failure parsing FLACSpecificBox (dfLa)");
 
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 6a35ed9..681274b 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -91,7 +91,6 @@
       has_flac_(has_flac),
       num_empty_samples_skipped_(0),
       num_invalid_conversions_(0) {
-  DCHECK(!has_flac || base::FeatureList::IsEnabled(kMseFlacInIsobmff));
 }
 
 MP4StreamParser::~MP4StreamParser() = default;
diff --git a/media/formats/mp4/mp4_stream_parser_unittest.cc b/media/formats/mp4/mp4_stream_parser_unittest.cc
index bc8cf117..dac384d 100644
--- a/media/formats/mp4/mp4_stream_parser_unittest.cc
+++ b/media/formats/mp4/mp4_stream_parser_unittest.cc
@@ -472,10 +472,6 @@
 }
 
 TEST_F(MP4StreamParserTest, Flac) {
-  // The feature is disabled by default. Enable it.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(kMseFlacInIsobmff);
-
   parser_.reset(new MP4StreamParser(std::set<int>(), false, true));
 
   auto params = GetDefaultInitParametersExpectations();
@@ -487,10 +483,6 @@
 }
 
 TEST_F(MP4StreamParserTest, Flac192kHz) {
-  // The feature is disabled by default. Enable it.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(kMseFlacInIsobmff);
-
   parser_.reset(new MP4StreamParser(std::set<int>(), false, true));
 
   auto params = GetDefaultInitParametersExpectations();
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index ef031a4a..2e6bdabd 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -161,6 +161,8 @@
   "WEBM_VP8",
   "WEBM_VP9",
   "WEBM_OPUS_VP9",
+  "MP4_FLAC",
+  "MP3",
 
   # See below for additional variants depending on build configuration.
 ]
@@ -168,7 +170,6 @@
 if (proprietary_codecs) {
   pipeline_integration_fuzzer_variants += [
     "ADTS",
-    "MP3",
     "MP4_AACLC",
     "MP4_AACSBR",
 
@@ -176,7 +177,6 @@
     # SourceBufferState::Init differentiate kinds of AVC, we use "AVC1" here to
     # retain corpus associated with this fuzzer target name.
     "MP4_AVC1",
-    "MP4_FLAC",
     "MP4_AACLC_AVC",
   ]
   if (enable_mse_mpeg2ts_stream_parser) {
diff --git a/media/test/pipeline_integration_fuzzertest.cc b/media/test/pipeline_integration_fuzzertest.cc
index b954ef0..7148e4b 100644
--- a/media/test/pipeline_integration_fuzzertest.cc
+++ b/media/test/pipeline_integration_fuzzertest.cc
@@ -31,13 +31,13 @@
   WEBM_VP8,
   WEBM_VP9,
   WEBM_OPUS_VP9,
+  MP4_FLAC,
+  MP3,
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
   ADTS,
-  MP3,
   MP4_AACLC,
   MP4_AACSBR,
   MP4_AVC1,
-  MP4_FLAC,
   MP4_AACLC_AVC,
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
   MP2T_AACLC,
@@ -61,19 +61,19 @@
       return "video/webm; codecs=\"vp9\"";
     case WEBM_OPUS_VP9:
       return "video/webm; codecs=\"opus,vp9\"";
+    case MP4_FLAC:
+      return "audio/mp4; codecs=\"flac\"";
+    case MP3:
+      return "audio/mpeg";
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
     case ADTS:
       return "audio/aac";
-    case MP3:
-      return "audio/mpeg";
     case MP4_AACLC:
       return "audio/mp4; codecs=\"mp4a.40.2\"";
     case MP4_AACSBR:
       return "audio/mp4; codecs=\"mp4a.40.5\"";
     case MP4_AVC1:
       return "video/mp4; codecs=\"avc1.42E01E\"";
-    case MP4_FLAC:
-      return "audio/mp4; codecs=\"flac\"";
     case MP4_AACLC_AVC:
       return "video/mp4; codecs=\"mp4a.40.2,avc1.42E01E\"";
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
@@ -147,7 +147,6 @@
   }
 
   ~ProgressivePipelineIntegrationFuzzerTest() override = default;
-  ;
 
   void RunTest(const uint8_t* data, size_t size) {
     if (PIPELINE_OK != Start(data, size, kUnreliableDuration))
@@ -172,7 +171,6 @@
   }
 
   ~MediaSourcePipelineIntegrationFuzzerTest() override = default;
-  ;
 
   void RunTest(const uint8_t* data, size_t size, const std::string& mimetype) {
     if (size == 0)
@@ -226,9 +224,6 @@
 
   media::InitializeMediaLibrary();
 
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(media::kMseFlacInIsobmff);
-
   FuzzerVariant variant = PIPELINE_FUZZER_VARIANT;
 
   if (variant == SRC) {
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 6d82002..f1a5128f 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1588,10 +1588,6 @@
 #endif
 
 TEST_P(MSEPipelineIntegrationTest, FlacInMp4_Hashed) {
-  // The feature is disabled by default. Enable it.
-  base::test::ScopedFeatureList features;
-  features.InitAndEnableFeature(kMseFlacInIsobmff);
-
   MockMediaSource source("sfx-flac_frag.mp4", kMP4AudioFlac, kAppendWholeFile);
   EXPECT_EQ(PIPELINE_OK,
             StartPipelineWithMediaSource(&source, kHashed, nullptr));
@@ -2012,6 +2008,7 @@
   EXPECT_EQ(CHUNK_DEMUXER_ERROR_APPEND_FAILED, WaitUntilEndedOrError());
   source.Shutdown();
 }
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 // Verify files which change configuration midstream fail gracefully.
 TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) {
@@ -2019,7 +2016,6 @@
   Play();
   ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE);
 }
-#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {
   ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-16x9-aspect.webm"));
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 68a688fe..66f0913 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -358,7 +358,7 @@
 
   pipeline_->Seek(seek_time, base::Bind(&PipelineIntegrationTestBase::OnSeeked,
                                         base::Unretained(this), seek_time));
-  RunUntilQuit(&run_loop);
+  RunUntilQuitOrError(&run_loop);
   return (pipeline_status_ == PIPELINE_OK);
 }
 
@@ -367,7 +367,7 @@
   pipeline_->Suspend(base::Bind(&PipelineIntegrationTestBase::OnStatusCallback,
                                 base::Unretained(this),
                                 run_loop.QuitWhenIdleClosure()));
-  RunUntilQuit(&run_loop);
+  RunUntilQuitOrError(&run_loop);
   return (pipeline_status_ == PIPELINE_OK);
 }
 
@@ -382,7 +382,7 @@
                     seek_time,
                     base::Bind(&PipelineIntegrationTestBase::OnSeeked,
                                base::Unretained(this), seek_time));
-  RunUntilQuit(&run_loop);
+  RunUntilQuitOrError(&run_loop);
   return (pipeline_status_ == PIPELINE_OK);
 }
 
@@ -655,7 +655,10 @@
   return pipeline_status_;
 }
 
-void PipelineIntegrationTestBase::RunUntilQuit(base::RunLoop* run_loop) {
+void PipelineIntegrationTestBase::RunUntilQuitOrError(base::RunLoop* run_loop) {
+  // We always install an error handler to avoid test hangs.
+  on_error_closure_ = run_loop->QuitWhenIdleClosure();
+
   run_loop->Run();
   on_ended_closure_ = base::OnceClosure();
   on_error_closure_ = base::OnceClosure();
@@ -668,8 +671,7 @@
   DCHECK(on_error_closure_.is_null());
 
   on_ended_closure_ = run_loop->QuitWhenIdleClosure();
-  on_error_closure_ = run_loop->QuitWhenIdleClosure();
-  RunUntilQuit(run_loop);
+  RunUntilQuitOrError(run_loop);
 }
 
 base::TimeTicks DummyTickClock::NowTicks() const {
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index aa27784..9fb3815 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -253,11 +253,13 @@
 
  private:
   // Runs |run_loop| until it is explicitly Quit() by some part of the calling
-  // test fixture. The |scoped_task_environment_| is RunUntilIdle() after the
-  // RunLoop finishes running, before returning to the caller.
-  void RunUntilQuit(base::RunLoop* run_loop);
-  // Configures |on_ended_closure_| and |on_error_closure_| to quit |run_loop|
-  // and then calls RunUntilQuit() on it.
+  // test fixture or when an error occurs (by setting |on_error_closure_|). The
+  // |scoped_task_environment_| is RunUntilIdle() after the RunLoop finishes
+  // running, before returning to the caller.
+  void RunUntilQuitOrError(base::RunLoop* run_loop);
+
+  // Configures |on_ended_closure_| to quit |run_loop| and then calls
+  // RunUntilQuitOrError() on it.
   void RunUntilQuitOrEndedOrError(base::RunLoop* run_loop);
 
   base::OnceClosure on_ended_closure_;
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc
index ecbdbd7..a3aa205 100644
--- a/net/quic/core/congestion_control/bbr_sender.cc
+++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -93,8 +93,6 @@
       max_ack_height_(kBandwidthWindowSize, 0, 0),
       aggregation_epoch_start_time_(QuicTime::Zero()),
       aggregation_epoch_bytes_(0),
-      bytes_acked_since_queue_drained_(0),
-      max_aggregation_bytes_multiplier_(0),
       min_rtt_(QuicTime::Delta::Zero()),
       min_rtt_timestamp_(QuicTime::Zero()),
       congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS),
@@ -225,12 +223,6 @@
       config.HasClientRequestedIndependentOption(kBBRR, perspective)) {
     rate_based_recovery_ = true;
   }
-  if (config.HasClientRequestedIndependentOption(kBBR1, perspective)) {
-    max_aggregation_bytes_multiplier_ = 1.5;
-  }
-  if (config.HasClientRequestedIndependentOption(kBBR2, perspective)) {
-    max_aggregation_bytes_multiplier_ = 2;
-  }
   if (config.HasClientRequestedIndependentOption(kBBRS, perspective)) {
     slower_startup_ = true;
   }
@@ -308,14 +300,6 @@
         sampler_->total_bytes_acked() - total_bytes_acked_before;
 
     UpdateAckAggregationBytes(event_time, bytes_acked);
-    if (max_aggregation_bytes_multiplier_ > 0) {
-      if (unacked_packets_->bytes_in_flight() <=
-          1.25 * GetTargetCongestionWindow(pacing_gain_)) {
-        bytes_acked_since_queue_drained_ = 0;
-      } else {
-        bytes_acked_since_queue_drained_ += bytes_acked;
-      }
-    }
   }
 
   // Handle logic specific to PROBE_BW mode.
@@ -488,6 +472,11 @@
 void BbrSender::UpdateGainCyclePhase(QuicTime now,
                                      QuicByteCount prior_in_flight,
                                      bool has_losses) {
+  QuicByteCount bytes_in_flight = prior_in_flight;
+  if (GetQuicReloadableFlag(quic_bbr_fix_probe_bw)) {
+    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_bbr_fix_probe_bw);
+    bytes_in_flight = unacked_packets_->bytes_in_flight();
+  }
   // In most cases, the cycle is advanced after an RTT passes.
   bool should_advance_gain_cycling = now - last_cycle_start_ > GetMinRtt();
 
@@ -505,7 +494,7 @@
   // queue which could have been incurred by probing prior to it.  If the number
   // of bytes in flight falls down to the estimated BDP value earlier, conclude
   // that the queue has been successfully drained and exit this cycle early.
-  if (pacing_gain_ < 1.0 && prior_in_flight <= GetTargetCongestionWindow(1)) {
+  if (pacing_gain_ < 1.0 && bytes_in_flight <= GetTargetCongestionWindow(1)) {
     should_advance_gain_cycling = true;
   }
 
@@ -516,7 +505,7 @@
     // Low gain mode will be exited immediately when the target BDP is achieved.
     if (fully_drain_queue_ && pacing_gain_ < 1 &&
         kPacingGain[cycle_current_offset_] == 1 &&
-        prior_in_flight > GetTargetCongestionWindow(1)) {
+        bytes_in_flight > GetTargetCongestionWindow(1)) {
       return;
     }
     pacing_gain_ = kPacingGain[cycle_current_offset_];
@@ -705,36 +694,10 @@
   if (rtt_variance_weight_ > 0.f && !BandwidthEstimate().IsZero()) {
     target_window += rtt_variance_weight_ * rtt_stats_->mean_deviation() *
                      BandwidthEstimate();
-  } else if (max_aggregation_bytes_multiplier_ > 0 && is_at_full_bandwidth_) {
-    // Subtracting only half the bytes_acked_since_queue_drained ensures sending
-    // doesn't completely stop for a long period of time if the queue hasn't
-    // been drained recently.
-    if (max_aggregation_bytes_multiplier_ * max_ack_height_.GetBest() >
-        bytes_acked_since_queue_drained_ / 2) {
-      target_window +=
-          max_aggregation_bytes_multiplier_ * max_ack_height_.GetBest() -
-          bytes_acked_since_queue_drained_ / 2;
-    }
   } else if (is_at_full_bandwidth_) {
     target_window += max_ack_height_.GetBest();
   }
 
-  if (GetQuicReloadableFlag(quic_bbr_add_tso_cwnd)) {
-    // QUIC doesn't have TSO, but it does have similarly quantized pacing, so
-    // allow extra CWND to make QUIC's BBR CWND identical to TCP's.
-    QuicByteCount tso_segs_goal = 0;
-    if (pacing_rate_ < QuicBandwidth::FromKBitsPerSecond(1200)) {
-      tso_segs_goal = kDefaultTCPMSS;
-    } else if (pacing_rate_ < QuicBandwidth::FromKBitsPerSecond(24000)) {
-      tso_segs_goal = 2 * kDefaultTCPMSS;
-    } else {
-      tso_segs_goal =
-          std::min(pacing_rate_ * QuicTime::Delta::FromMilliseconds(1),
-                   /* 64k */ static_cast<QuicByteCount>(1 << 16));
-    }
-    target_window += 3 * tso_segs_goal;
-  }
-
   // Instead of immediately setting the target CWND as the new one, BBR grows
   // the CWND towards |target_window| by only increasing it |bytes_acked| at a
   // time.
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h
index 46993fc2..cb3f0fbe 100644
--- a/net/quic/core/congestion_control/bbr_sender.h
+++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -248,14 +248,6 @@
   QuicTime aggregation_epoch_start_time_;
   QuicByteCount aggregation_epoch_bytes_;
 
-  // The number of bytes acknowledged since the last time bytes in flight
-  // dropped below the target window.
-  QuicByteCount bytes_acked_since_queue_drained_;
-
-  // The muliplier for calculating the max amount of extra CWND to add to
-  // compensate for ack aggregation.
-  float max_aggregation_bytes_multiplier_;
-
   // Minimum RTT estimate.  Automatically expires within 10 seconds (and
   // triggers PROBE_RTT mode) if no new value is sampled during that period.
   QuicTime::Delta min_rtt_;
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc
index 6c12d58..6c3302b95 100644
--- a/net/quic/core/congestion_control/bbr_sender_test.cc
+++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -92,9 +92,6 @@
                             /*connection_id=*/43),
         receiver_multiplexer_("Receiver multiplexer",
                               {&receiver_, &competing_receiver_}) {
-    // These will be changed by the appropriate tests as necessary.
-    SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
-
     rtt_stats_ = bbr_sender_.connection()->sent_packet_manager().GetRttStats();
     sender_ = SetupBbrSender(&bbr_sender_);
 
@@ -258,8 +255,6 @@
 
 // Test a simple long data transfer in the default setup.
 TEST_F(BbrSenderTest, SimpleTransfer) {
-  // Adding TSO CWND causes packet loss before exiting startup.
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   // Disable Ack Decimation on the receiver, because it can increase srtt.
   QuicConnectionPeer::SetAckMode(receiver_.connection(),
                                  QuicConnection::AckMode::TCP_ACKING);
@@ -309,7 +304,6 @@
 
 // Test a simple long data transfer with 2 rtts of aggregation.
 TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) {
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   CreateDefaultSetup();
   // 2 RTTs of aggregation, with a max of 10kb.
   EnableAggregation(10 * 1024, 2 * kTestRtt);
@@ -368,76 +362,7 @@
 }
 
 // Test a simple long data transfer with 2 rtts of aggregation.
-TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes4) {
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
-  // Disable Ack Decimation on the receiver, because it can increase srtt.
-  QuicConnectionPeer::SetAckMode(receiver_.connection(),
-                                 QuicConnection::AckMode::TCP_ACKING);
-  CreateDefaultSetup();
-  // Enable ack aggregation that forces the queue to be drained.
-  SetConnectionOption(kBBR1);
-
-  // 2 RTTs of aggregation, with a max of 10kb.
-  EnableAggregation(10 * 1024, 2 * kTestRtt);
-
-  // Transfer 12MB.
-  DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
-  EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
-  // It's possible to read a bandwidth as much as 50% too high with aggregation.
-  EXPECT_LE(kTestLinkBandwidth * 0.99f,
-            sender_->ExportDebugState().max_bandwidth);
-  // TODO(ianswett): Tighten this bound once we understand why BBR is
-  // overestimating bandwidth with aggregation. b/36022633
-  EXPECT_GE(kTestLinkBandwidth * 1.5f,
-            sender_->ExportDebugState().max_bandwidth);
-  // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
-  // bandwidth higher than the link rate.
-  // The margin here is high, because the aggregation greatly increases
-  // smoothed rtt.
-  EXPECT_GE(kTestRtt * 3.5, rtt_stats_->smoothed_rtt());
-  ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.12f);
-}
-
-// Test a simple long data transfer with 2 rtts of aggregation.
-TEST_F(BbrSenderTest, SimpleTransferAckDecimation4) {
-  // Decrease the CWND gain so extra CWND is required with stretch acks.
-  FLAGS_quic_bbr_cwnd_gain = 1.0;
-  sender_ = new BbrSender(
-      rtt_stats_,
-      QuicSentPacketManagerPeer::GetUnackedPacketMap(
-          QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection())),
-      kInitialCongestionWindowPackets, kDefaultMaxCongestionWindowPackets,
-      &random_);
-  QuicConnectionPeer::SetSendAlgorithm(bbr_sender_.connection(), sender_);
-  // Enable Ack Decimation on the receiver.
-  QuicConnectionPeer::SetAckMode(receiver_.connection(),
-                                 QuicConnection::AckMode::ACK_DECIMATION);
-  CreateDefaultSetup();
-  // Enable ack aggregation that forces the queue to be drained.
-  SetConnectionOption(kBBR1);
-
-  // Transfer 12MB.
-  DoSimpleTransfer(12 * 1024 * 1024, QuicTime::Delta::FromSeconds(35));
-  EXPECT_EQ(BbrSender::PROBE_BW, sender_->ExportDebugState().mode);
-  // It's possible to read a bandwidth as much as 50% too high with aggregation.
-  EXPECT_LE(kTestLinkBandwidth * 0.99f,
-            sender_->ExportDebugState().max_bandwidth);
-  // TODO(ianswett): Tighten this bound once we understand why BBR is
-  // overestimating bandwidth with aggregation. b/36022633
-  EXPECT_GE(kTestLinkBandwidth * 1.5f,
-            sender_->ExportDebugState().max_bandwidth);
-  // TODO(ianswett): Expect 0 packets are lost once BBR no longer measures
-  // bandwidth higher than the link rate.
-  EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
-  // The margin here is high, because the aggregation greatly increases
-  // smoothed rtt.
-  EXPECT_GE(kTestRtt * 2, rtt_stats_->smoothed_rtt());
-  ExpectApproxEq(kTestRtt, rtt_stats_->min_rtt(), 0.1f);
-}
-
-// Test a simple long data transfer with 2 rtts of aggregation.
 TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) {
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   // Disable Ack Decimation on the receiver, because it can increase srtt.
   QuicConnectionPeer::SetAckMode(receiver_.connection(),
                                  QuicConnection::AckMode::TCP_ACKING);
@@ -466,7 +391,6 @@
 
 // Test a simple long data transfer with 2 rtts of aggregation.
 TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) {
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   // Disable Ack Decimation on the receiver, because it can increase srtt.
   QuicConnectionPeer::SetAckMode(receiver_.connection(),
                                  QuicConnection::AckMode::TCP_ACKING);
@@ -936,8 +860,6 @@
 
 // Test exiting STARTUP earlier due to the 2RTT connection option.
 TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) {
-  // Adding TSO CWND causes packet loss before exiting startup.
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   CreateDefaultSetup();
 
   SetConnectionOption(k2RTT);
@@ -1022,8 +944,6 @@
 
 // Test slower pacing after loss in STARTUP due to the BBRS connection option.
 TEST_F(BbrSenderTest, SimpleTransferSlowerStartup) {
-  // Adding TSO CWND causes packet loss before exiting startup.
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   CreateSmallBufferSetup();
 
   SetConnectionOption(kBBRS);
@@ -1058,8 +978,6 @@
 
 // Ensures no change in congestion window in STARTUP after loss.
 TEST_F(BbrSenderTest, SimpleTransferNoConservationInStartup) {
-  // Adding TSO CWND causes packet loss before exiting startup.
-  SetQuicReloadableFlag(quic_bbr_add_tso_cwnd, false);
   CreateSmallBufferSetup();
 
   SetConnectionOption(kBBS1);
diff --git a/net/quic/core/crypto/crypto_handshake_message.cc b/net/quic/core/crypto/crypto_handshake_message.cc
index c2b052e6..06e93eb 100644
--- a/net/quic/core/crypto/crypto_handshake_message.cc
+++ b/net/quic/core/crypto/crypto_handshake_message.cc
@@ -73,19 +73,18 @@
 
 void CryptoHandshakeMessage::SetVersionVector(
     QuicTag tag,
-    QuicTransportVersionVector versions) {
+    ParsedQuicVersionVector versions) {
   QuicVersionLabelVector version_labels;
-  for (QuicTransportVersion version : versions) {
+  for (ParsedQuicVersion version : versions) {
     version_labels.push_back(
-        QuicEndian::HostToNet32(QuicVersionToQuicVersionLabel(version)));
+        QuicEndian::HostToNet32(CreateQuicVersionLabel(version)));
   }
   SetVector(tag, version_labels);
 }
 
 void CryptoHandshakeMessage::SetVersion(QuicTag tag,
-                                        QuicTransportVersion version) {
-  SetValue(tag,
-           QuicEndian::HostToNet32(QuicVersionToQuicVersionLabel(version)));
+                                        ParsedQuicVersion version) {
+  SetValue(tag, QuicEndian::HostToNet32(CreateQuicVersionLabel(version)));
 }
 
 void CryptoHandshakeMessage::SetStringPiece(QuicTag tag,
diff --git a/net/quic/core/crypto/crypto_handshake_message.h b/net/quic/core/crypto/crypto_handshake_message.h
index 772c036..6b57c56 100644
--- a/net/quic/core/crypto/crypto_handshake_message.h
+++ b/net/quic/core/crypto/crypto_handshake_message.h
@@ -62,11 +62,11 @@
 
   // Sets an element with the given tag to the on-the-wire representation of
   // |version|.
-  void SetVersion(QuicTag tag, QuicTransportVersion version);
+  void SetVersion(QuicTag tag, ParsedQuicVersion version);
 
   // Sets an element with the given tag to the on-the-wire representation of
   // the elements in |versions|.
-  void SetVersionVector(QuicTag tag, QuicTransportVersionVector versions);
+  void SetVersionVector(QuicTag tag, ParsedQuicVersionVector versions);
 
   // Returns the message tag.
   QuicTag tag() const { return tag_; }
diff --git a/net/quic/core/crypto/crypto_protocol.h b/net/quic/core/crypto/crypto_protocol.h
index 1b2d647..3fe1bfb6 100644
--- a/net/quic/core/crypto/crypto_protocol.h
+++ b/net/quic/core/crypto/crypto_protocol.h
@@ -87,8 +87,8 @@
 const QuicTag kBBS3 = TAG('B', 'B', 'S', '3');   // Slowstart packet
                                                  // conservation in BBR STARTUP
 const QuicTag kBBRR = TAG('B', 'B', 'R', 'R');   // Rate-based recovery in BBR
-const QuicTag kBBR1 = TAG('B', 'B', 'R', '1');   // Ack aggregation v1
-const QuicTag kBBR2 = TAG('B', 'B', 'R', '2');   // Ack aggregation v2
+const QuicTag kBBR1 = TAG('B', 'B', 'R', '1');   // DEPRECATED
+const QuicTag kBBR2 = TAG('B', 'B', 'R', '2');   // DEPRECATED
 const QuicTag kBBR3 = TAG('B', 'B', 'R', '3');   // Fully drain the queue once
                                                  // per cycle
 const QuicTag kBBR4 = TAG('B', 'B', 'R', '4');   // 20 RTT ack aggregation
@@ -111,6 +111,7 @@
 const QuicTag k1CON = TAG('1', 'C', 'O', 'N');   // Emulate a single connection
 const QuicTag kNTLP = TAG('N', 'T', 'L', 'P');   // No tail loss probe
 const QuicTag k1TLP = TAG('1', 'T', 'L', 'P');   // 1 tail loss probe
+const QuicTag k1RTO = TAG('1', 'R', 'T', 'O');   // Send 1 packet upon RTO
 const QuicTag kNCON = TAG('N', 'C', 'O', 'N');   // N Connection Congestion Ctrl
 const QuicTag kNRTO = TAG('N', 'R', 'T', 'O');   // CWND reduction on loss
 const QuicTag kTIME = TAG('T', 'I', 'M', 'E');   // Time based loss detection
@@ -136,6 +137,8 @@
                                                  // tolerating out of order.
 const QuicTag kAKDU = TAG('A', 'K', 'D', 'U');   // Unlimited number of packets
                                                  // received before acking
+const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q');   // Send an immediate ack after
+                                                 // 1 RTT of not sending acks.
 const QuicTag kSSLR = TAG('S', 'S', 'L', 'R');   // Slow Start Large Reduction.
 const QuicTag kNPRR = TAG('N', 'P', 'R', 'R');   // Pace at unity instead of PRR
 const QuicTag k5RTO = TAG('5', 'R', 'T', 'O');   // Close connection on 5 RTOs
@@ -150,6 +153,7 @@
 const QuicTag kSMHL = TAG('S', 'M', 'H', 'L');   // Support MAX_HEADER_LIST_SIZE
                                                  // settings frame.
 const QuicTag kNSTP = TAG('N', 'S', 'T', 'P');   // No stop waiting frames.
+const QuicTag kNRTT = TAG('N', 'R', 'T', 'T');   // Ignore initial RTT
 
 // Optional support of truncated Connection IDs.  If sent by a peer, the value
 // is the minimum number of bytes allowed for the connection ID sent to the
diff --git a/net/quic/core/crypto/crypto_server_test.cc b/net/quic/core/crypto/crypto_server_test.cc
index 8012d75..3566c8a 100644
--- a/net/quic/core/crypto/crypto_server_test.cc
+++ b/net/quic/core/crypto/crypto_server_test.cc
@@ -61,7 +61,7 @@
 struct TestParams {
   TestParams(bool enable_stateless_rejects,
              bool use_stateless_rejects,
-             QuicTransportVersionVector supported_versions)
+             ParsedQuicVersionVector supported_versions)
       : enable_stateless_rejects(enable_stateless_rejects),
         use_stateless_rejects(use_stateless_rejects),
         supported_versions(std::move(supported_versions)) {}
@@ -71,7 +71,7 @@
        << std::endl;
     os << "  use_stateless_rejects: " << p.use_stateless_rejects << std::endl;
     os << "  versions: "
-       << QuicTransportVersionVectorToString(p.supported_versions) << " }";
+       << ParsedQuicVersionVectorToString(p.supported_versions) << " }";
     return os;
   }
 
@@ -83,7 +83,7 @@
   // enable_stateless_rejects is false.
   bool use_stateless_rejects;
   // Versions supported by client and server.
-  QuicTransportVersionVector supported_versions;
+  ParsedQuicVersionVector supported_versions;
 };
 
 // Constructs various test permutations.
@@ -93,8 +93,7 @@
   for (bool enable_stateless_rejects : kTrueFalse) {
     for (bool use_stateless_rejects : kTrueFalse) {
       // Start with all versions, remove highest on each iteration.
-      QuicTransportVersionVector supported_versions =
-          AllSupportedTransportVersions();
+      ParsedQuicVersionVector supported_versions = AllSupportedVersions();
       while (!supported_versions.empty()) {
         params.push_back(TestParams(enable_stateless_rejects,
                                     use_stateless_rejects, supported_versions));
@@ -110,6 +109,7 @@
   CryptoServerTest()
       : rand_(QuicRandom::GetInstance()),
         client_address_(QuicIpAddress::Loopback4(), 1234),
+        client_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
         config_(QuicCryptoServerConfig::TESTING,
                 rand_,
                 crypto_test_utils::ProofSourceForTesting(),
@@ -124,8 +124,7 @@
     config_.set_enable_serving_sct(true);
 
     client_version_ = supported_versions_.front();
-    client_version_string_ = QuicVersionLabelToString(
-        QuicVersionToQuicVersionLabel(client_version_));
+    client_version_string_ = ParsedQuicVersionToString(client_version_);
 
     SetQuicReloadableFlag(enable_quic_stateless_reject_support,
                           GetParam().enable_stateless_rejects);
@@ -225,8 +224,7 @@
     server_hello.GetVersionLabelList(kVER, &versions);
     ASSERT_EQ(supported_versions_.size(), versions.size());
     for (size_t i = 0; i < versions.size(); ++i) {
-      EXPECT_EQ(QuicVersionToQuicVersionLabel(supported_versions_[i]),
-                versions[i]);
+      EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[i]), versions[i]);
     }
 
     QuicStringPiece address;
@@ -242,7 +240,7 @@
     QuicSocketAddress server_address;
     config_.ValidateClientHello(
         message, client_address_.host(), server_address,
-        supported_versions_.front(), &clock_, signed_config_,
+        supported_versions_.front().transport_version, &clock_, signed_config_,
         QuicMakeUnique<ValidateCallback>(this, true, "", &called));
     EXPECT_TRUE(called);
   }
@@ -260,7 +258,7 @@
     QuicSocketAddress server_address;
     config_.ValidateClientHello(
         message, client_address_.host(), server_address,
-        supported_versions_.front(), &clock_, signed_config_,
+        supported_versions_.front().transport_version, &clock_, signed_config_,
         QuicMakeUnique<ValidateCallback>(this, false, error_substr, called));
   }
 
@@ -398,8 +396,8 @@
   MockRandom rand_for_id_generation_;
   MockClock clock_;
   QuicSocketAddress client_address_;
-  QuicTransportVersionVector supported_versions_;
-  QuicTransportVersion client_version_;
+  ParsedQuicVersionVector supported_versions_;
+  ParsedQuicVersion client_version_;
   QuicString client_version_string_;
   QuicCryptoServerConfig config_;
   QuicCryptoServerConfigPeer peer_;
@@ -673,8 +671,8 @@
   }
   // Set the client's preferred version to a supported version that
   // is not the "current" version (supported_versions_.front()).
-  QuicString bad_version = QuicVersionLabelToString(
-      QuicVersionToQuicVersionLabel(supported_versions_.back()));
+  QuicString bad_version =
+      ParsedQuicVersionToString(supported_versions_.back());
 
   CryptoHandshakeMessage msg = crypto_test_utils::CreateCHLO(
       {{"PDMD", "X509"}, {"VER\0", bad_version}}, kClientHelloMinimumSize);
@@ -848,11 +846,11 @@
       new DummyProofVerifierCallback());
   QuicString chlo_hash;
   CryptoUtils::HashHandshakeMessage(msg, &chlo_hash, Perspective::IS_SERVER);
-  EXPECT_EQ(QUIC_SUCCESS,
-            proof_verifier->VerifyProof(
-                "test.example.com", 443, (string(scfg_str)), client_version_,
-                chlo_hash, certs, "", (string(proof)), verify_context.get(),
-                &error_details, &details, std::move(callback)));
+  EXPECT_EQ(QUIC_SUCCESS, proof_verifier->VerifyProof(
+                              "test.example.com", 443, (string(scfg_str)),
+                              client_version_.transport_version, chlo_hash,
+                              certs, "", (string(proof)), verify_context.get(),
+                              &error_details, &details, std::move(callback)));
 }
 
 TEST_P(CryptoServerTest, RejectInvalidXlct) {
@@ -1101,8 +1099,7 @@
  public:
   void SetUp() override {
     client_version_ = supported_versions_.back();
-    client_version_string_ = QuicVersionLabelToString(
-        QuicVersionToQuicVersionLabel(client_version_));
+    client_version_string_ = ParsedQuicVersionToString(client_version_);
     CryptoServerTest::SetUp();
   }
 };
diff --git a/net/quic/core/crypto/crypto_utils.cc b/net/quic/core/crypto/crypto_utils.cc
index edb7287..f9bb63c 100644
--- a/net/quic/core/crypto/crypto_utils.cc
+++ b/net/quic/core/crypto/crypto_utils.cc
@@ -281,7 +281,7 @@
 
 QuicErrorCode CryptoUtils::ValidateServerHello(
     const CryptoHandshakeMessage& server_hello,
-    const QuicTransportVersionVector& negotiated_versions,
+    const ParsedQuicVersionVector& negotiated_versions,
     QuicString* error_details) {
   DCHECK(error_details != nullptr);
 
@@ -296,12 +296,20 @@
     *error_details = "server hello missing version list";
     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
   }
+
+  return ValidateServerHelloVersions(supported_version_labels,
+                                     negotiated_versions, error_details);
+}
+
+QuicErrorCode CryptoUtils::ValidateServerHelloVersions(
+    const QuicVersionLabelVector& server_versions,
+    const ParsedQuicVersionVector& negotiated_versions,
+    QuicString* error_details) {
   if (!negotiated_versions.empty()) {
-    bool mismatch =
-        supported_version_labels.size() != negotiated_versions.size();
-    for (size_t i = 0; i < supported_version_labels.size() && !mismatch; ++i) {
-      mismatch = QuicVersionLabelToQuicVersion(supported_version_labels[i]) !=
-                 negotiated_versions[i];
+    bool mismatch = server_versions.size() != negotiated_versions.size();
+    for (size_t i = 0; i < server_versions.size() && !mismatch; ++i) {
+      mismatch =
+          server_versions[i] != CreateQuicVersionLabel(negotiated_versions[i]);
     }
     // The server sent a list of supported versions, and the connection
     // reports that there was a version negotiation during the handshake.
@@ -316,8 +324,8 @@
 
 QuicErrorCode CryptoUtils::ValidateClientHello(
     const CryptoHandshakeMessage& client_hello,
-    QuicTransportVersion version,
-    const QuicTransportVersionVector& supported_versions,
+    ParsedQuicVersion version,
+    const ParsedQuicVersionVector& supported_versions,
     QuicString* error_details) {
   if (client_hello.tag() != kCHLO) {
     *error_details = "Bad tag";
@@ -334,14 +342,21 @@
     *error_details = "client hello missing version list";
     return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
   }
-  QuicTransportVersion client_version =
-      QuicVersionLabelToQuicVersion(client_version_label);
-  if (client_version != version) {
-    // Just because client_version is a valid version enum doesn't mean that
-    // this server actually supports that version, so we check to see if
-    // it's actually in the supported versions list.
+  return ValidateClientHelloVersion(client_version_label, version,
+                                    supported_versions, error_details);
+}
+
+QuicErrorCode CryptoUtils::ValidateClientHelloVersion(
+    QuicVersionLabel client_version,
+    ParsedQuicVersion connection_version,
+    const ParsedQuicVersionVector& supported_versions,
+    QuicString* error_details) {
+  if (client_version != CreateQuicVersionLabel(connection_version)) {
+    // Check to see if |client_version| is actually on the supported versions
+    // list. If not, the server doesn't support that version and it's not a
+    // downgrade attack.
     for (size_t i = 0; i < supported_versions.size(); ++i) {
-      if (client_version == supported_versions[i]) {
+      if (client_version == CreateQuicVersionLabel(supported_versions[i])) {
         *error_details = "Downgrade attack detected";
         return QUIC_VERSION_NEGOTIATION_MISMATCH;
       }
diff --git a/net/quic/core/crypto/crypto_utils.h b/net/quic/core/crypto/crypto_utils.h
index 8315bae..9a7f60e2 100644
--- a/net/quic/core/crypto/crypto_utils.h
+++ b/net/quic/core/crypto/crypto_utils.h
@@ -166,7 +166,19 @@
   // code and sets |error_details|.
   static QuicErrorCode ValidateServerHello(
       const CryptoHandshakeMessage& server_hello,
-      const QuicTransportVersionVector& negotiated_versions,
+      const ParsedQuicVersionVector& negotiated_versions,
+      QuicString* error_details);
+
+  // Validates that the |server_versions| received do not indicate that the
+  // ServerHello is part of a downgrade attack. |negotiated_versions| must
+  // contain the list of versions received in the server's version negotiation
+  // packet (or be empty if no such packet was received).
+  //
+  // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
+  // code and sets |error_details|.
+  static QuicErrorCode ValidateServerHelloVersions(
+      const QuicVersionLabelVector& server_versions,
+      const ParsedQuicVersionVector& negotiated_versions,
       QuicString* error_details);
 
   // Validates that |client_hello| is actually a CHLO and that this is not part
@@ -177,8 +189,21 @@
   // code and sets |error_details|.
   static QuicErrorCode ValidateClientHello(
       const CryptoHandshakeMessage& client_hello,
-      QuicTransportVersion version,
-      const QuicTransportVersionVector& supported_versions,
+      ParsedQuicVersion version,
+      const ParsedQuicVersionVector& supported_versions,
+      QuicString* error_details);
+
+  // Validates that the |client_version| received does not indicate that a
+  // downgrade attack has occurred. |connection_version| is the version of the
+  // QuicConnection, and |supported_versions| is all versions that that
+  // QuicConnection supports.
+  //
+  // Returns QUIC_NO_ERROR if this is the case or returns the appropriate error
+  // code and sets |error_details|.
+  static QuicErrorCode ValidateClientHelloVersion(
+      QuicVersionLabel client_version,
+      ParsedQuicVersion connection_version,
+      const ParsedQuicVersionVector& supported_versions,
       QuicString* error_details);
 
   // Returns the name of the HandshakeFailureReason as a char*
diff --git a/net/quic/core/crypto/quic_crypto_client_config.cc b/net/quic/core/crypto/quic_crypto_client_config.cc
index 1ce64244..7bc2862 100644
--- a/net/quic/core/crypto/quic_crypto_client_config.cc
+++ b/net/quic/core/crypto/quic_crypto_client_config.cc
@@ -426,7 +426,7 @@
 
 void QuicCryptoClientConfig::FillInchoateClientHello(
     const QuicServerId& server_id,
-    const QuicTransportVersion preferred_version,
+    const ParsedQuicVersion preferred_version,
     const CachedState* cached,
     QuicRandom* rand,
     bool demand_x509_proof,
@@ -503,7 +503,7 @@
 QuicErrorCode QuicCryptoClientConfig::FillClientHello(
     const QuicServerId& server_id,
     QuicConnectionId connection_id,
-    const QuicTransportVersion preferred_version,
+    const ParsedQuicVersion preferred_version,
     const CachedState* cached,
     QuicWallTime now,
     QuicRandom* rand,
@@ -671,7 +671,7 @@
     std::unique_ptr<char[]> output(new char[encrypted_len]);
     size_t output_size = 0;
     if (!crypters.encrypter->EncryptPacket(
-            preferred_version, 0 /* packet number */,
+            preferred_version.transport_version, 0 /* packet number */,
             QuicStringPiece() /* associated data */,
             cetv_plaintext.AsStringPiece(), output.get(), &output_size,
             encrypted_len)) {
@@ -842,8 +842,8 @@
 QuicErrorCode QuicCryptoClientConfig::ProcessServerHello(
     const CryptoHandshakeMessage& server_hello,
     QuicConnectionId connection_id,
-    QuicTransportVersion version,
-    const QuicTransportVersionVector& negotiated_versions,
+    ParsedQuicVersion version,
+    const ParsedQuicVersionVector& negotiated_versions,
     CachedState* cached,
     QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
     QuicString* error_details) {
diff --git a/net/quic/core/crypto/quic_crypto_client_config.h b/net/quic/core/crypto/quic_crypto_client_config.h
index b38584a..2ef884f 100644
--- a/net/quic/core/crypto/quic_crypto_client_config.h
+++ b/net/quic/core/crypto/quic_crypto_client_config.h
@@ -228,7 +228,7 @@
   // certificate related fields.
   void FillInchoateClientHello(
       const QuicServerId& server_id,
-      const QuicTransportVersion preferred_version,
+      const ParsedQuicVersion preferred_version,
       const CachedState* cached,
       QuicRandom* rand,
       bool demand_x509_proof,
@@ -252,7 +252,7 @@
   QuicErrorCode FillClientHello(
       const QuicServerId& server_id,
       QuicConnectionId connection_id,
-      const QuicTransportVersion preferred_version,
+      const ParsedQuicVersion preferred_version,
       const CachedState* cached,
       QuicWallTime now,
       QuicRandom* rand,
@@ -288,8 +288,8 @@
   QuicErrorCode ProcessServerHello(
       const CryptoHandshakeMessage& server_hello,
       QuicConnectionId connection_id,
-      QuicTransportVersion version,
-      const QuicTransportVersionVector& negotiated_versions,
+      ParsedQuicVersion version,
+      const ParsedQuicVersionVector& negotiated_versions,
       CachedState* cached,
       QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params,
       QuicString* error_details);
diff --git a/net/quic/core/crypto/quic_crypto_client_config_test.cc b/net/quic/core/crypto/quic_crypto_client_config_test.cc
index 4bdb2ea..1f2433de6 100644
--- a/net/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -182,13 +182,12 @@
   CryptoHandshakeMessage msg;
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
-  config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state,
-                                 &rand,
+  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
                                  /* demand_x509_proof= */ true, params, &msg);
 
   QuicVersionLabel cver;
   EXPECT_EQ(QUIC_NO_ERROR, msg.GetVersionLabel(kVER, &cver));
-  EXPECT_EQ(QuicVersionToQuicVersionLabel(QuicTransportVersionMax()), cver);
+  EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver);
   QuicStringPiece proof_nonce;
   EXPECT_TRUE(msg.GetStringPiece(kNONP, &proof_nonce));
   EXPECT_EQ(QuicString(32, 'r'), proof_nonce);
@@ -218,8 +217,7 @@
   CryptoHandshakeMessage msg;
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
-  config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state,
-                                 &rand,
+  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
                                  /* demand_x509_proof= */ true, params, &msg);
 
   QuicTag pdmd;
@@ -250,8 +248,7 @@
   CryptoHandshakeMessage msg;
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
-  config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state,
-                                 &rand,
+  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
                                  /* demand_x509_proof= */ true, params, &msg);
 
   QuicStringPiece scid;
@@ -279,8 +276,7 @@
   CryptoHandshakeMessage msg;
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
   MockRandom rand;
-  config.FillInchoateClientHello(server_id, QuicTransportVersionMax(), &state,
-                                 &rand,
+  config.FillInchoateClientHello(server_id, QuicVersionMax(), &state, &rand,
                                  /* demand_x509_proof= */ true, params, &msg);
 
   QuicStringPiece scid;
@@ -299,26 +295,25 @@
   MockRandom rand;
   CryptoHandshakeMessage chlo;
   QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
-  config.FillClientHello(server_id, kConnectionId, QuicTransportVersionMax(),
-                         &state, QuicWallTime::Zero(), &rand,
+  config.FillClientHello(server_id, kConnectionId, QuicVersionMax(), &state,
+                         QuicWallTime::Zero(), &rand,
                          nullptr,  // channel_id_key
                          params, &chlo, &error_details);
 
   // Verify that the version label has been set correctly in the CHLO.
   QuicVersionLabel cver;
   EXPECT_EQ(QUIC_NO_ERROR, chlo.GetVersionLabel(kVER, &cver));
-  EXPECT_EQ(QuicVersionToQuicVersionLabel(QuicTransportVersionMax()), cver);
+  EXPECT_EQ(CreateQuicVersionLabel(QuicVersionMax()), cver);
 }
 
 TEST_F(QuicCryptoClientConfigTest, ProcessServerDowngradeAttack) {
-  QuicTransportVersionVector supported_versions =
-      AllSupportedTransportVersions();
+  ParsedQuicVersionVector supported_versions = AllSupportedVersions();
   if (supported_versions.size() == 1) {
     // No downgrade attack is possible if the client only supports one version.
     return;
   }
 
-  QuicTransportVersionVector supported_version_vector;
+  ParsedQuicVersionVector supported_version_vector;
   for (size_t i = supported_versions.size(); i > 0; --i) {
     supported_version_vector.push_back(supported_versions[i - 1]);
   }
@@ -589,8 +584,8 @@
   CryptoHandshakeMessage msg;
   msg.set_tag(kSHLO);
   // Choose the latest version.
-  QuicTransportVersionVector supported_versions;
-  QuicTransportVersion version = AllSupportedTransportVersions().front();
+  ParsedQuicVersionVector supported_versions;
+  ParsedQuicVersion version = AllSupportedVersions().front();
   supported_versions.push_back(version);
   msg.SetVersionVector(kVER, supported_versions);
 
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc
index a376ea9..31462de 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.cc
+++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -534,8 +534,8 @@
       bool reject_only,
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
-      QuicTransportVersion version,
-      const QuicTransportVersionVector& supported_versions,
+      ParsedQuicVersion version,
+      const ParsedQuicVersionVector& supported_versions,
       bool use_stateless_rejects,
       QuicConnectionId server_designated_connection_id,
       const QuicClock* clock,
@@ -594,8 +594,8 @@
   const bool reject_only_;
   const QuicConnectionId connection_id_;
   const QuicSocketAddress client_address_;
-  const QuicTransportVersion version_;
-  const QuicTransportVersionVector supported_versions_;
+  const ParsedQuicVersion version_;
+  const ParsedQuicVersionVector supported_versions_;
   const bool use_stateless_rejects_;
   const QuicConnectionId server_designated_connection_id_;
   const QuicClock* const clock_;
@@ -619,8 +619,8 @@
     QuicConnectionId connection_id,
     const QuicSocketAddress& server_address,
     const QuicSocketAddress& client_address,
-    QuicTransportVersion version,
-    const QuicTransportVersionVector& supported_versions,
+    ParsedQuicVersion version,
+    const ParsedQuicVersionVector& supported_versions,
     bool use_stateless_rejects,
     QuicConnectionId server_designated_connection_id,
     const QuicClock* clock,
@@ -708,9 +708,9 @@
             compressed_certs_cache, params, signed_config,
             total_framing_overhead, chlo_packet_size, requested_config,
             primary_config, std::move(done_cb)));
-    proof_source_->GetProof(server_address, string(info.sni),
-                            primary_config->serialized, version, chlo_hash,
-                            std::move(cb));
+    proof_source_->GetProof(
+        server_address, string(info.sni), primary_config->serialized,
+        version.transport_version, chlo_hash, std::move(cb));
     helper.DetachCallback();
     return;
   }
@@ -732,8 +732,8 @@
     bool reject_only,
     QuicConnectionId connection_id,
     const QuicSocketAddress& client_address,
-    QuicTransportVersion version,
-    const QuicTransportVersionVector& supported_versions,
+    ParsedQuicVersion version,
+    const ParsedQuicVersionVector& supported_versions,
     bool use_stateless_rejects,
     QuicConnectionId server_designated_connection_id,
     const QuicClock* clock,
@@ -769,8 +769,9 @@
 
   std::unique_ptr<CryptoHandshakeMessage> out(new CryptoHandshakeMessage);
   if (!info.reject_reasons.empty() || !requested_config.get()) {
-    BuildRejection(version, clock->WallNow(), *primary_config, client_hello,
-                   info, validate_chlo_result.cached_network_params,
+    BuildRejection(version.transport_version, clock->WallNow(), *primary_config,
+                   client_hello, info,
+                   validate_chlo_result.cached_network_params,
                    use_stateless_rejects, server_designated_connection_id, rand,
                    compressed_certs_cache, params, *signed_config,
                    total_framing_overhead, chlo_packet_size, out.get());
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h
index 312f1377..9400a6d 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.h
+++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -317,8 +317,8 @@
       QuicConnectionId connection_id,
       const QuicSocketAddress& server_address,
       const QuicSocketAddress& client_address,
-      QuicTransportVersion version,
-      const QuicTransportVersionVector& supported_versions,
+      ParsedQuicVersion version,
+      const ParsedQuicVersionVector& supported_versions,
       bool use_stateless_rejects,
       QuicConnectionId server_designated_connection_id,
       const QuicClock* clock,
@@ -534,8 +534,8 @@
       bool reject_only,
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
-      QuicTransportVersion version,
-      const QuicTransportVersionVector& supported_versions,
+      ParsedQuicVersion version,
+      const ParsedQuicVersionVector& supported_versions,
       bool use_stateless_rejects,
       QuicConnectionId server_designated_connection_id,
       const QuicClock* clock,
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index e6b032f..93d892f5 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -316,10 +316,6 @@
       received_stateless_reset_token_(0),
       last_control_frame_id_(kInvalidControlFrameId),
       is_path_degrading_(false),
-      negotiate_version_early_(
-          GetQuicReloadableFlag(quic_server_early_version_negotiation)),
-      always_discard_packets_after_close_(
-          GetQuicReloadableFlag(quic_always_discard_packets_after_close)),
       handle_write_results_for_connectivity_probe_(GetQuicReloadableFlag(
           quic_handle_write_results_for_connectivity_probe)),
       use_path_degrading_alarm_(
@@ -693,10 +689,8 @@
     return false;
   }
 
-  if (negotiate_version_early_ &&
-      version_negotiation_state_ != NEGOTIATED_VERSION &&
+  if (version_negotiation_state_ != NEGOTIATED_VERSION &&
       perspective_ == Perspective::IS_SERVER) {
-    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_server_early_version_negotiation);
     if (!header.version_flag) {
       // Packets should have the version flag till version negotiation is
       // done.
@@ -1805,25 +1799,6 @@
       if (debug_visitor_ != nullptr) {
         debug_visitor_->OnSuccessfulVersionNegotiation(version());
       }
-    } else if (!negotiate_version_early_) {
-      if (!header.version_flag) {
-        // Packets should have the version flag till version negotiation is
-        // done.
-        QuicString error_details =
-            QuicStrCat(ENDPOINT, "Packet ", header.packet_number,
-                       " without version flag before version negotiated.");
-        QUIC_DLOG(WARNING) << error_details;
-        CloseConnection(QUIC_INVALID_VERSION, error_details,
-                        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-        return false;
-      } else {
-        DCHECK_EQ(header.version, version());
-        version_negotiation_state_ = NEGOTIATED_VERSION;
-        visitor_->OnSuccessfulVersionNegotiation(version());
-        if (debug_visitor_ != nullptr) {
-          debug_visitor_->OnSuccessfulVersionNegotiation(version());
-        }
-      }
     }
   }
 
@@ -1990,9 +1965,7 @@
 }
 
 bool QuicConnection::WritePacket(SerializedPacket* packet) {
-  if (always_discard_packets_after_close_ && ShouldDiscardPacket(*packet)) {
-    QUIC_FLAG_COUNT_N(
-        quic_reloadable_flag_quic_always_discard_packets_after_close, 1, 2);
+  if (ShouldDiscardPacket(*packet)) {
     ++stats_.packets_discarded;
     return true;
   }
@@ -2006,10 +1979,6 @@
     RecordInternalErrorLocation(QUIC_CONNECTION_WRITE_PACKET);
     return true;
   }
-  if (!always_discard_packets_after_close_ && ShouldDiscardPacket(*packet)) {
-    ++stats_.packets_discarded;
-    return true;
-  }
   // Termination packets are encrypted and saved, so don't exit early.
   const bool is_termination_packet = IsTerminationPacket(*packet);
   if (writer_->IsWriteBlocked() && !is_termination_packet) {
@@ -2863,9 +2832,7 @@
     QuicPacketWriter* probing_writer,
     const QuicSocketAddress& peer_address) {
   DCHECK(peer_address.IsInitialized());
-  if (always_discard_packets_after_close_ && !connected_) {
-    QUIC_FLAG_COUNT_N(
-        quic_reloadable_flag_quic_always_discard_packets_after_close, 2, 2);
+  if (!connected_) {
     QUIC_BUG << "Not sending connectivity probing packet as connection is "
              << "disconnected.";
     return false;
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h
index b670be5..e01aa5d3 100644
--- a/net/quic/core/quic_connection.h
+++ b/net/quic/core/quic_connection.h
@@ -1309,13 +1309,6 @@
   // True if the peer is unreachable on the current path.
   bool is_path_degrading_;
 
-  // Latched value of
-  // quic_reloadable_flag_quic_server_early_version_negotiation.
-  const bool negotiate_version_early_;
-
-  // Latched value of
-  // quic_reloadable_flag_quic_always_discard_packets_after_close.
-  const bool always_discard_packets_after_close_;
   // Latched valure of
   // quic_reloadable_flag_quic_handle_write_results_for_connectivity_probe.
   const bool handle_write_results_for_connectivity_probe_;
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc
index 568a3bb..a77c925e 100644
--- a/net/quic/core/quic_connection_test.cc
+++ b/net/quic/core/quic_connection_test.cc
@@ -1573,14 +1573,9 @@
   EXPECT_FALSE(connection_.connected());
   EXPECT_EQ(1u, connection_.NumQueuedPackets());
 
-  if (GetQuicReloadableFlag(quic_always_discard_packets_after_close)) {
-    EXPECT_EQ(0u, connection_.GetStats().packets_discarded);
-    connection_.OnCanWrite();
-    EXPECT_EQ(1u, connection_.GetStats().packets_discarded);
-  } else {
-    EXPECT_QUIC_BUG(connection_.OnCanWrite(),
-                    "Attempt to write packet:1 after:2");
-  }
+  EXPECT_EQ(0u, connection_.GetStats().packets_discarded);
+  connection_.OnCanWrite();
+  EXPECT_EQ(1u, connection_.GetStats().packets_discarded);
 }
 
 TEST_P(QuicConnectionTest, ReceiveConnectivityProbingAtServer) {
@@ -5414,20 +5409,12 @@
   EXPECT_FALSE(connection_.connected());
   EXPECT_FALSE(connection_.CanWriteStreamData());
 
-  int num_packets_sent =
-      GetQuicReloadableFlag(quic_always_discard_packets_after_close) ? 0 : 1;
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _))
-      .Times(num_packets_sent);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0);
 
-  if (GetQuicReloadableFlag(quic_always_discard_packets_after_close)) {
-    EXPECT_QUIC_BUG(connection_.SendConnectivityProbingPacket(
-                        writer_.get(), connection_.peer_address()),
-                    "Not sending connectivity probing packet as connection is "
-                    "disconnected.");
-  } else {
-    connection_.SendConnectivityProbingPacket(writer_.get(),
-                                              connection_.peer_address());
-  }
+  EXPECT_QUIC_BUG(connection_.SendConnectivityProbingPacket(
+                      writer_.get(), connection_.peer_address()),
+                  "Not sending connectivity probing packet as connection is "
+                  "disconnected.");
 }
 
 TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) {
diff --git a/net/quic/core/quic_crypto_client_handshaker.cc b/net/quic/core/quic_crypto_client_handshaker.cc
index 32a17d7..5737a7c61 100644
--- a/net/quic/core/quic_crypto_client_handshaker.cc
+++ b/net/quic/core/quic_crypto_client_handshaker.cc
@@ -318,8 +318,7 @@
 
   if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
     crypto_config_->FillInchoateClientHello(
-        server_id_,
-        session()->connection()->supported_versions().front().transport_version,
+        server_id_, session()->connection()->supported_versions().front(),
         cached, session()->connection()->random_generator(),
         /* demand_x509_proof= */ true, crypto_negotiated_params_, &out);
     // Pad the inchoate client hello to fill up a packet.
@@ -363,8 +362,8 @@
   QuicString error_details;
   QuicErrorCode error = crypto_config_->FillClientHello(
       server_id_, session()->connection()->connection_id(),
-      session()->connection()->supported_versions().front().transport_version,
-      cached, session()->connection()->clock()->WallNow(),
+      session()->connection()->supported_versions().front(), cached,
+      session()->connection()->clock()->WallNow(),
       session()->connection()->random_generator(), channel_id_key_.get(),
       crypto_negotiated_params_, &out, &error_details);
   if (error != QUIC_NO_ERROR) {
@@ -621,10 +620,9 @@
   QuicString error_details;
   QuicErrorCode error = crypto_config_->ProcessServerHello(
       *in, session()->connection()->connection_id(),
-      session()->connection()->transport_version(),
-      ParsedVersionsToTransportVersions(
-          session()->connection()->server_supported_versions()),
-      cached, crypto_negotiated_params_, &error_details);
+      session()->connection()->version(),
+      session()->connection()->server_supported_versions(), cached,
+      crypto_negotiated_params_, &error_details);
 
   if (error != QUIC_NO_ERROR) {
     stream_->CloseConnectionWithDetails(
diff --git a/net/quic/core/quic_crypto_client_stream_test.cc b/net/quic/core/quic_crypto_client_stream_test.cc
index 7ef81c5..0ec9ba3 100644
--- a/net/quic/core/quic_crypto_client_stream_test.cc
+++ b/net/quic/core/quic_crypto_client_stream_test.cc
@@ -409,7 +409,7 @@
 
   void AdvanceHandshakeWithFakeServer() {
     client_session_->GetMutableCryptoStream()->CryptoConnect();
-    EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
+    EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
         .Times(testing::AnyNumber());
     EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_))
         .Times(testing::AnyNumber());
diff --git a/net/quic/core/quic_crypto_server_handshaker.cc b/net/quic/core/quic_crypto_server_handshaker.cc
index febd64b..e1827f7c 100644
--- a/net/quic/core/quic_crypto_server_handshaker.cc
+++ b/net/quic/core/quic_crypto_server_handshaker.cc
@@ -398,7 +398,8 @@
   const CryptoHandshakeMessage& message = result->client_hello;
   QuicString error_details;
   if (!helper_->CanAcceptClientHello(
-          message, session()->connection()->self_address(), &error_details)) {
+          message, GetClientAddress(), session()->connection()->peer_address(),
+          session()->connection()->self_address(), &error_details)) {
     done_cb->Run(QUIC_HANDSHAKE_FAILED, error_details, nullptr, nullptr,
                  nullptr);
     return;
@@ -428,11 +429,11 @@
       GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config);
   crypto_config_->ProcessClientHello(
       result, /*reject_only=*/false, connection->connection_id(),
-      connection->self_address(), GetClientAddress(), transport_version(),
-      ParsedVersionsToTransportVersions(connection->supported_versions()),
-      use_stateless_rejects_in_crypto_config, server_designated_connection_id,
-      connection->clock(), connection->random_generator(),
-      compressed_certs_cache_, crypto_negotiated_params_, signed_config_,
+      connection->self_address(), GetClientAddress(), connection->version(),
+      connection->supported_versions(), use_stateless_rejects_in_crypto_config,
+      server_designated_connection_id, connection->clock(),
+      connection->random_generator(), compressed_certs_cache_,
+      crypto_negotiated_params_, signed_config_,
       QuicCryptoStream::CryptoMessageFramingOverhead(transport_version()),
       chlo_packet_size_, std::move(done_cb));
 }
diff --git a/net/quic/core/quic_crypto_server_stream.h b/net/quic/core/quic_crypto_server_stream.h
index 98d7d34..6b9ec15 100644
--- a/net/quic/core/quic_crypto_server_stream.h
+++ b/net/quic/core/quic_crypto_server_stream.h
@@ -147,6 +147,8 @@
     // acceptable according to the visitor's policy. Otherwise, returns false
     // and populates |error_details|.
     virtual bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+                                      const QuicSocketAddress& client_address,
+                                      const QuicSocketAddress& peer_address,
                                       const QuicSocketAddress& self_address,
                                       QuicString* error_details) const = 0;
   };
diff --git a/net/quic/core/quic_crypto_server_stream_test.cc b/net/quic/core/quic_crypto_server_stream_test.cc
index c1a1f45..22e9d66 100644
--- a/net/quic/core/quic_crypto_server_stream_test.cc
+++ b/net/quic/core/quic_crypto_server_stream_test.cc
@@ -103,7 +103,7 @@
         &server_connection_, &server_session);
     CHECK(server_session);
     server_session_.reset(server_session);
-    EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
+    EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
         .Times(testing::AnyNumber());
     EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_))
         .Times(testing::AnyNumber());
@@ -390,7 +390,7 @@
   Initialize();
   InitializeFakeClient(/* supports_stateless_rejects= */ false);
 
-  EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
+  EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
       .WillOnce(testing::Return(false));
   EXPECT_CALL(*server_connection_,
               CloseConnection(QUIC_HANDSHAKE_FAILED, _, _));
@@ -534,7 +534,7 @@
   Initialize();
   InitializeFakeClient(/* supports_stateless_rejects= */ false);
 
-  EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
+  EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
       .WillOnce(testing::Return(true));
   EXPECT_CALL(*server_connection_,
               CloseConnection(QUIC_HANDSHAKE_FAILED, "Failed to get proof", _));
@@ -570,7 +570,7 @@
 TEST_P(QuicCryptoServerStreamTestWithFakeProofSource, MultipleChlo) {
   Initialize();
   GetFakeProofSource()->Activate();
-  EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _))
+  EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
       .WillOnce(testing::Return(true));
 
   // Create a minimal CHLO
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index 3da4a0c0..8098745 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -60,9 +60,6 @@
 // Congestion window gain for QUIC BBR during PROBE_BW phase.
 QUIC_FLAG(double, FLAGS_quic_bbr_cwnd_gain, 2.0f)
 
-// Add the equivalent number of bytes as 3 TCP TSO segments to QUIC's BBR CWND.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd, false)
-
 // Simplify QUIC\'s adaptive time loss detection to measure the necessary
 // reordering window for every spurious retransmit.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_adaptive_time_loss, false)
@@ -141,10 +138,6 @@
           FLAGS_quic_reloadable_flag_quic_fast_path_on_stream_data_acked,
           true)
 
-// If true, QUIC streams are registered in the QuicStream constructor instead
-// of in the QuicSpdyStream constructor.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_register_streams_early2, true)
-
 // If this flag and
 // FLAGS_quic_reloadable_flag_quic_fix_write_out_of_order_queued_packet_crash
 // are both ture, QUIC will clear queued packets before sending connectivity
@@ -154,19 +147,6 @@
     FLAGS_quic_reloadable_flag_quic_clear_queued_packets_before_sending_connectivity_probing,
     false)
 
-// When true, this flag has QuicConnection call
-// QuicConnectionVisitorInterface::OnSuccessfulVersionNegotiation earlier when
-// processing the packet header.
-QUIC_FLAG(bool,
-          FLAGS_quic_reloadable_flag_quic_server_early_version_negotiation,
-          true)
-
-// If true, QUIC will always discard outgoing packets after connection close.
-// Currently out-of-order outgoing packets are not discarded
-QUIC_FLAG(bool,
-          FLAGS_quic_reloadable_flag_quic_always_discard_packets_after_close,
-          true)
-
 // If true, when a stream is reset by peer with error, it should not be added to
 // zombie streams.
 QUIC_FLAG(bool,
@@ -189,11 +169,6 @@
 // replace it with a static streams map.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_register_static_streams, true)
 
-// Base the QUIC crypto retransmission timer on the last sent crypto packet.
-QUIC_FLAG(bool,
-          FLAGS_quic_reloadable_flag_quic_better_crypto_retransmission,
-          true)
-
 // If true, enable server proxy support in QUIC.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_server_proxy2, false)
 
@@ -250,3 +225,24 @@
     bool,
     FLAGS_quic_reloadable_flag_quic_early_retransmit_detects_in_flight_packet_lost,
     false)
+
+// Enables the 1RTO connection option which only sends one packet on QUIC
+// retransmission timeout, instead of 2.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_one_rto, false)
+
+// Modify QuicVersionManager so that the QuicTransportVersionVector returned by
+// GetSupportedTransportVersions contains a unique list of entries.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_version_manager_dedupe_transport_versions,
+          false)
+
+// When true, the NRTT QUIC connection option causes receivers to ignore
+// incoming initial RTT values.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_no_irtt, false)
+
+// Fixed QUIC's PROBE_BW logic to exit low gain mode based on bytes_in_flight,
+// not prior_in_flight.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_fix_probe_bw, false)
+
+// If true, changes when the dispatcher changes internal state.
+QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_enable_l1_munge, false)
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc
index 5539f37e..9fb7a2263 100644
--- a/net/quic/core/quic_sent_packet_manager.cc
+++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -75,6 +75,7 @@
       consecutive_crypto_retransmission_count_(0),
       pending_timer_transmission_count_(0),
       max_tail_loss_probes_(kDefaultMaxTailLossProbes),
+      max_rto_packets_(kMaxRetransmissionsOnTimeout),
       enable_half_rtt_tail_loss_probe_(false),
       using_pacing_(false),
       use_new_rto_(false),
@@ -94,10 +95,7 @@
       rtt_updated_(false),
       acked_packets_iter_(last_ack_frame_.packets.rbegin()),
       use_path_degrading_alarm_(
-          GetQuicReloadableFlag(quic_path_degrading_alarm2)),
-      use_better_crypto_retransmission_(
-          GetQuicReloadableFlag(quic_better_crypto_retransmission)) {
-  QUIC_FLAG_COUNT(quic_reloadable_flag_quic_better_crypto_retransmission);
+          GetQuicReloadableFlag(quic_path_degrading_alarm2)) {
   SetSendAlgorithm(congestion_control_type);
 }
 
@@ -106,8 +104,13 @@
 void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
   if (config.HasReceivedInitialRoundTripTimeUs() &&
       config.ReceivedInitialRoundTripTimeUs() > 0) {
-    SetInitialRtt(QuicTime::Delta::FromMicroseconds(
-        config.ReceivedInitialRoundTripTimeUs()));
+    if (GetQuicReloadableFlag(quic_no_irtt) &&
+        config.HasClientSentConnectionOption(kNRTT, perspective_)) {
+      QUIC_FLAG_COUNT(quic_reloadable_flag_quic_no_irtt);
+    } else {
+      SetInitialRtt(QuicTime::Delta::FromMicroseconds(
+          config.ReceivedInitialRoundTripTimeUs()));
+    }
   } else if (config.HasInitialRoundTripTimeUsToSend() &&
              config.GetInitialRoundTripTimeUsToSend() > 0) {
     SetInitialRtt(QuicTime::Delta::FromMicroseconds(
@@ -195,6 +198,11 @@
     QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_one_tlp, 1, 2);
     max_tail_loss_probes_ = 1;
   }
+  if (GetQuicReloadableFlag(quic_one_rto) &&
+      config.HasClientSentConnectionOption(k1RTO, perspective_)) {
+    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_one_rto);
+    max_rto_packets_ = 1;
+  }
   if (config.HasClientSentConnectionOption(kTLPR, perspective_)) {
     enable_half_rtt_tail_loss_probe_ = true;
   }
@@ -768,7 +776,7 @@
        it != unacked_packets_.end(); ++it, ++packet_number) {
     if ((!session_decides_what_to_write() || it->state == OUTSTANDING) &&
         unacked_packets_.HasRetransmittableFrames(*it) &&
-        pending_timer_transmission_count_ < kMaxRetransmissionsOnTimeout) {
+        pending_timer_transmission_count_ < max_rto_packets_) {
       if (session_decides_what_to_write()) {
         retransmissions.push_back(packet_number);
       } else {
@@ -913,11 +921,8 @@
   }
   switch (GetRetransmissionMode()) {
     case HANDSHAKE_MODE:
-      if (use_better_crypto_retransmission_) {
-        return unacked_packets_.GetLastCryptoPacketSentTime() +
-               GetCryptoRetransmissionDelay();
-      }
-      return clock_->ApproximateNow() + GetCryptoRetransmissionDelay();
+      return unacked_packets_.GetLastCryptoPacketSentTime() +
+             GetCryptoRetransmissionDelay();
     case LOSS_MODE:
       return loss_algorithm_->GetLossTimeout();
     case TLP_MODE: {
diff --git a/net/quic/core/quic_sent_packet_manager.h b/net/quic/core/quic_sent_packet_manager.h
index 6c44610..d1b8b2ac 100644
--- a/net/quic/core/quic_sent_packet_manager.h
+++ b/net/quic/core/quic_sent_packet_manager.h
@@ -449,6 +449,8 @@
   size_t pending_timer_transmission_count_;
   // Maximum number of tail loss probes to send before firing an RTO.
   size_t max_tail_loss_probes_;
+  // Maximum number of packets to send upon RTO.
+  QuicPacketCount max_rto_packets_;
   // If true, send the TLP at 0.5 RTT.
   bool enable_half_rtt_tail_loss_probe_;
   bool using_pacing_;
@@ -517,10 +519,6 @@
   // quic_reloadable_flag_quic_path_degrading_alarm
   const bool use_path_degrading_alarm_;
 
-  // Latched value of
-  // quic_reloadable_flag_quic_better_crypto_retransmission
-  const bool use_better_crypto_retransmission_;
-
   DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager);
 };
 
diff --git a/net/quic/core/quic_sent_packet_manager_test.cc b/net/quic/core/quic_sent_packet_manager_test.cc
index 04330445..a19e434 100644
--- a/net/quic/core/quic_sent_packet_manager_test.cc
+++ b/net/quic/core/quic_sent_packet_manager_test.cc
@@ -1445,10 +1445,11 @@
     EXPECT_EQ(102 * kDefaultLength,
               QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
   } else {
-    EXPECT_TRUE(manager_.HasPendingRetransmissions());
+    ASSERT_TRUE(manager_.HasPendingRetransmissions());
     EXPECT_EQ(100 * kDefaultLength,
               QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
     RetransmitNextPacket(101);
+    ASSERT_TRUE(manager_.HasPendingRetransmissions());
     RetransmitNextPacket(102);
     EXPECT_FALSE(manager_.HasPendingRetransmissions());
   }
@@ -1490,6 +1491,53 @@
   }
 }
 
+TEST_P(QuicSentPacketManagerTest, RetransmissionTimeoutOnePacket) {
+  SetQuicReloadableFlag(quic_one_rto, true);
+  // Set the 1RTO connection option.
+  QuicConfig client_config;
+  QuicTagVector options;
+  options.push_back(k1RTO);
+  QuicSentPacketManagerPeer::SetPerspective(&manager_, Perspective::IS_CLIENT);
+  client_config.SetConnectionOptionsToSend(options);
+  EXPECT_CALL(*network_change_visitor_, OnCongestionChange());
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, PacingRate(_))
+      .WillRepeatedly(Return(QuicBandwidth::Zero()));
+  EXPECT_CALL(*send_algorithm_, GetCongestionWindow())
+      .WillRepeatedly(Return(10 * kDefaultTCPMSS));
+  manager_.SetFromConfig(client_config);
+  EXPECT_CALL(*send_algorithm_, CanSend(_)).WillRepeatedly(Return(true));
+
+  StrictMock<MockDebugDelegate> debug_delegate;
+  manager_.SetDebugDelegate(&debug_delegate);
+
+  // Send 100 packets.
+  const size_t kNumSentPackets = 100;
+  for (size_t i = 1; i <= kNumSentPackets; ++i) {
+    SendDataPacket(i);
+  }
+
+  EXPECT_FALSE(manager_.MaybeRetransmitTailLossProbe());
+  if (manager_.session_decides_what_to_write()) {
+    EXPECT_CALL(notifier_, RetransmitFrames(_, _))
+        .Times(1)
+        .WillOnce(WithArgs<1>(Invoke([this](TransmissionType type) {
+          RetransmitDataPacket(101, type);
+        })));
+  }
+  manager_.OnRetransmissionTimeout();
+  if (manager_.session_decides_what_to_write()) {
+    EXPECT_EQ(101 * kDefaultLength,
+              QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+  } else {
+    ASSERT_TRUE(manager_.HasPendingRetransmissions());
+    EXPECT_EQ(100 * kDefaultLength,
+              QuicSentPacketManagerPeer::GetBytesInFlight(&manager_));
+    RetransmitNextPacket(101);
+    EXPECT_FALSE(manager_.HasPendingRetransmissions());
+  }
+}
+
 TEST_P(QuicSentPacketManagerTest, NewRetransmissionTimeout) {
   QuicConfig client_config;
   QuicTagVector options;
@@ -1748,11 +1796,7 @@
   }
 
   // The retransmission time should now be twice as far in the future.
-  if (GetQuicReloadableFlag(quic_better_crypto_retransmission)) {
-    expected_time = crypto_packet_send_time + srtt * 2 * 1.5;
-  } else {
-    expected_time = clock_.Now() + srtt * 2 * 1.5;
-  }
+  expected_time = crypto_packet_send_time + srtt * 2 * 1.5;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 }
 
@@ -1800,11 +1844,7 @@
   }
 
   // The retransmission time should now be twice as far in the future.
-  if (GetQuicReloadableFlag(quic_better_crypto_retransmission)) {
-    expected_time = crypto_packet_send_time + srtt * 2 * 2;
-  } else {
-    expected_time = clock_.Now() + srtt * 2 * 2;
-  }
+  expected_time = crypto_packet_send_time + srtt * 2 * 2;
   EXPECT_EQ(expected_time, manager_.GetRetransmissionTime());
 }
 
diff --git a/net/quic/core/quic_server_session_base_test.cc b/net/quic/core/quic_server_session_base_test.cc
index 3b3e309..2bd1a42 100644
--- a/net/quic/core/quic_server_session_base_test.cc
+++ b/net/quic/core/quic_server_session_base_test.cc
@@ -405,8 +405,7 @@
   const QuicString serving_region = "not a real region";
   session_->set_serving_region(serving_region);
 
-  if (GetQuicReloadableFlag(quic_register_streams_early2) &&
-      GetQuicReloadableFlag(quic_register_static_streams)) {
+  if (GetQuicReloadableFlag(quic_register_static_streams)) {
     session_->UnregisterStreamPriority(kHeadersStreamId, /*is_static=*/true);
   }
   QuicServerSessionBasePeer::SetCryptoStream(session_.get(), nullptr);
@@ -414,8 +413,7 @@
       new MockQuicCryptoServerStream(&crypto_config_, &compressed_certs_cache_,
                                      session_.get(), &stream_helper_);
   QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream);
-  if (GetQuicReloadableFlag(quic_register_streams_early2) &&
-      GetQuicReloadableFlag(quic_register_static_streams)) {
+  if (GetQuicReloadableFlag(quic_register_static_streams)) {
     session_->RegisterStreamPriority(kHeadersStreamId, /*is_static=*/true,
                                      QuicStream::kDefaultPriority);
   }
@@ -497,6 +495,12 @@
 }
 
 TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) {
+  if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+    // This test relies on resumption, which is not currently supported by the
+    // TLS handshake.
+    // TODO(nharper): Add support for resumption to the TLS handshake.
+    return;
+  }
   // Test that if a client provides a CachedNetworkParameters with the same
   // serving region as the current server, and which was made within an hour of
   // now, that this data is passed down to the send algorithm.
@@ -592,6 +596,12 @@
 // ProofSource::GetProof.  Delay the completion of the operation until after the
 // stream has been destroyed, and verify that there are no memory bugs.
 TEST_P(StreamMemberLifetimeTest, Basic) {
+  if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+    // This test depends on the QUIC crypto protocol, so it is disabled for the
+    // TLS handshake.
+    // TODO(nharper): Fix this test so it doesn't rely on QUIC crypto.
+    return;
+  }
   SetQuicReloadableFlag(enable_quic_stateless_reject_support, true);
   SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true);
 
@@ -609,7 +619,7 @@
       PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
       &packet_version_list));
 
-  EXPECT_CALL(stream_helper_, CanAcceptClientHello(_, _, _))
+  EXPECT_CALL(stream_helper_, CanAcceptClientHello(_, _, _, _, _))
       .WillOnce(testing::Return(true));
   EXPECT_CALL(stream_helper_, GenerateConnectionIdForReject(_))
       .WillOnce(testing::Return(12345));
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc
index 694f415..a38e1185 100644
--- a/net/quic/core/quic_session.cc
+++ b/net/quic/core/quic_session.cc
@@ -37,11 +37,8 @@
                          const QuicConfig& config)
     : connection_(connection),
       visitor_(owner),
-      register_streams_early_(
-          GetQuicReloadableFlag(quic_register_streams_early2)),
       write_blocked_streams_(
-          GetQuicReloadableFlag(quic_register_static_streams) &&
-          register_streams_early_),
+          GetQuicReloadableFlag(quic_register_static_streams)),
       config_(config),
       max_open_outgoing_streams_(kDefaultMaxStreamsPerConnection),
       max_open_incoming_streams_(config_.GetMaxIncomingDynamicStreamsToSend()),
@@ -63,11 +60,7 @@
       currently_writing_stream_id_(0),
       goaway_sent_(false),
       goaway_received_(false),
-      control_frame_manager_(this) {
-  if (register_streams_early()) {
-    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_register_streams_early2);
-  }
-}
+      control_frame_manager_(this) {}
 
 void QuicSession::Initialize() {
   connection_->set_visitor(this);
@@ -749,13 +742,9 @@
 void QuicSession::RegisterStreamPriority(QuicStreamId id,
                                          bool is_static,
                                          SpdyPriority priority) {
-  // Static streams should not be registered unless register_streams_early
-  // is true.
-  DCHECK(register_streams_early() || !is_static);
   // Static streams do not need to be registered with the write blocked list,
   // since it has special handling for them.
-  if (!write_blocked_streams()->register_static_streams() &&
-      register_streams_early() && is_static) {
+  if (!write_blocked_streams()->register_static_streams() && is_static) {
     return;
   }
 
@@ -763,13 +752,9 @@
 }
 
 void QuicSession::UnregisterStreamPriority(QuicStreamId id, bool is_static) {
-  // Static streams should not be registered unless register_streams_early
-  // is true.
-  DCHECK(register_streams_early() || !is_static);
   // Static streams do not need to be registered with the write blocked list,
   // since it has special handling for them.
-  if (!write_blocked_streams()->register_static_streams() &&
-      register_streams_early() && is_static) {
+  if (!write_blocked_streams()->register_static_streams() && is_static) {
     return;
   }
   write_blocked_streams()->UnregisterStream(id, is_static);
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h
index c853834d..35d9194 100644
--- a/net/quic/core/quic_session.h
+++ b/net/quic/core/quic_session.h
@@ -308,8 +308,6 @@
   // Set transmission type of next sending packets.
   void SetTransmissionType(TransmissionType type);
 
-  bool register_streams_early() const { return register_streams_early_; }
-
   bool session_decides_what_to_write() const;
 
  protected:
@@ -478,9 +476,6 @@
   // May be null.
   Visitor* visitor_;
 
-  // Latched value of quic_reloadable_flag_quic_register_streams_early2.
-  const bool register_streams_early_;
-
   // A list of streams which need to write more data.  Stream register
   // themselves in their constructor, and unregisterm themselves in their
   // destructors, so the write blocked list must outlive all streams.
diff --git a/net/quic/core/quic_session_test.cc b/net/quic/core/quic_session_test.cc
index 719b10e6..19ed1f31 100644
--- a/net/quic/core/quic_session_test.cc
+++ b/net/quic/core/quic_session_test.cc
@@ -108,17 +108,7 @@
 class TestStream : public QuicStream {
  public:
   TestStream(QuicStreamId id, QuicSession* session)
-      : QuicStream(id, session, /*is_static=*/false) {
-    if (!session->register_streams_early()) {
-      session->RegisterStreamPriority(id, false, QuicStream::kDefaultPriority);
-    }
-  }
-
-  ~TestStream() override {
-    if (!session()->register_streams_early()) {
-      session()->UnregisterStreamPriority(id(), false);
-    }
-  }
+      : QuicStream(id, session, /*is_static=*/false) {}
 
   using QuicStream::CloseWriteSide;
 
diff --git a/net/quic/core/quic_spdy_stream.cc b/net/quic/core/quic_spdy_stream.cc
index 4fa1d8b0..aba21f7a 100644
--- a/net/quic/core/quic_spdy_stream.cc
+++ b/net/quic/core/quic_spdy_stream.cc
@@ -36,17 +36,9 @@
   // Don't receive any callbacks from the sequencer until headers
   // are complete.
   sequencer()->SetBlockedUntilFlush();
-  if (!session()->register_streams_early()) {
-    spdy_session_->RegisterStreamPriority(id, /*is_static=*/false, priority());
-  }
 }
 
-QuicSpdyStream::~QuicSpdyStream() {
-  if (spdy_session_ != nullptr && !session()->register_streams_early()) {
-    spdy_session_->UnregisterStreamPriority(id(),
-                                            /*is_static=*/false);
-  }
-}
+QuicSpdyStream::~QuicSpdyStream() {}
 
 size_t QuicSpdyStream::WriteHeaders(
     SpdyHeaderBlock header_block,
diff --git a/net/quic/core/quic_stream.cc b/net/quic/core/quic_stream.cc
index 72e1567..0cefab11 100644
--- a/net/quic/core/quic_stream.cc
+++ b/net/quic/core/quic_stream.cc
@@ -81,9 +81,7 @@
       buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)),
       is_static_(is_static) {
   SetFromConfig();
-  if (session_->register_streams_early()) {
-    session_->RegisterStreamPriority(id, is_static_, priority_);
-  }
+  session_->RegisterStreamPriority(id, is_static_, priority_);
 }
 
 QuicStream::~QuicStream() {
@@ -94,7 +92,7 @@
         << send_buffer_.stream_bytes_outstanding()
         << ", fin_outstanding: " << fin_outstanding_;
   }
-  if (session_ != nullptr && session_->register_streams_early()) {
+  if (session_ != nullptr) {
     session_->UnregisterStreamPriority(id(), is_static_);
   }
 }
diff --git a/net/quic/core/quic_stream_test.cc b/net/quic/core/quic_stream_test.cc
index 7b7d1a5..58098dd 100644
--- a/net/quic/core/quic_stream_test.cc
+++ b/net/quic/core/quic_stream_test.cc
@@ -123,11 +123,6 @@
         .Times(AnyNumber());
     write_blocked_list_ =
         QuicSessionPeer::GetWriteBlockedStreams(session_.get());
-    if (!session_->register_streams_early()) {
-      write_blocked_list_->RegisterStream(kTestStreamId,
-                                          /*is_static_stream=*/false,
-                                          kV3HighestPriority);
-    }
   }
 
   bool fin_sent() { return QuicStreamPeer::FinSent(stream_); }
diff --git a/net/quic/core/quic_version_manager.cc b/net/quic/core/quic_version_manager.cc
index e38aad5..b69b15b 100644
--- a/net/quic/core/quic_version_manager.cc
+++ b/net/quic/core/quic_version_manager.cc
@@ -5,8 +5,11 @@
 #include "net/quic/core/quic_version_manager.h"
 
 #include "net/quic/core/quic_versions.h"
+#include "net/quic/platform/api/quic_flag_utils.h"
 #include "net/quic/platform/api/quic_flags.h"
 
+#include <algorithm>
+
 namespace net {
 
 QuicVersionManager::QuicVersionManager(
@@ -56,8 +59,17 @@
       FilterSupportedVersions(allowed_supported_versions_);
   filtered_transport_versions_.clear();
   for (ParsedQuicVersion version : filtered_supported_versions_) {
-    filtered_transport_versions_.push_back(version.transport_version);
+    auto transport_version = version.transport_version;
+    if (!GetQuicReloadableFlag(
+            quic_version_manager_dedupe_transport_versions) ||
+        std::find(filtered_transport_versions_.begin(),
+                  filtered_transport_versions_.end(),
+                  transport_version) == filtered_transport_versions_.end()) {
+      filtered_transport_versions_.push_back(transport_version);
+    }
   }
+  QUIC_FLAG_COUNT(
+      quic_reloadable_flag_quic_version_manager_dedupe_transport_versions);
 }
 
 }  // namespace net
diff --git a/net/quic/quartc/quartc_factory.cc b/net/quic/quartc/quartc_factory.cc
index 41063ec9a..c33d108f 100644
--- a/net/quic/quartc/quartc_factory.cc
+++ b/net/quic/quartc/quartc_factory.cc
@@ -106,7 +106,6 @@
 std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession(
     const QuartcSessionConfig& quartc_session_config) {
   DCHECK(quartc_session_config.packet_transport);
-  SetQuicReloadableFlag(quic_better_crypto_retransmission, true);
   SetQuicReloadableFlag(quic_is_write_blocked, true);
 
   Perspective perspective = quartc_session_config.is_server
diff --git a/net/quic/quartc/quartc_session.cc b/net/quic/quartc/quartc_session.cc
index 7d12b46f..a2c0da4 100644
--- a/net/quic/quartc/quartc_session.cc
+++ b/net/quic/quartc/quartc_session.cc
@@ -107,6 +107,8 @@
 
 bool QuartcCryptoServerStreamHelper::CanAcceptClientHello(
     const CryptoHandshakeMessage& message,
+    const QuicSocketAddress& client_address,
+    const QuicSocketAddress& peer_address,
     const QuicSocketAddress& self_address,
     string* error_details) const {
   return true;
@@ -237,9 +239,6 @@
     // QuicStream::OnClose), the stream is already closed so return.
     return;
   }
-  if (!register_streams_early()) {
-    write_blocked_streams()->UnregisterStream(stream_id, /*is_static=*/false);
-  }
   QuicSession::CloseStream(stream_id);
 }
 
@@ -423,12 +422,7 @@
     // Register the stream to the QuicWriteBlockedList. |priority| is clamped
     // between 0 and 7, with 0 being the highest priority and 7 the lowest
     // priority.
-    if (!register_streams_early()) {
-      write_blocked_streams()->RegisterStream(
-          stream->id(), /* is_static_stream= */ false, priority);
-    } else {
-      write_blocked_streams()->UpdateStreamPriority(stream->id(), priority);
-    }
+    write_blocked_streams()->UpdateStreamPriority(stream->id(), priority);
 
     if (IsIncomingStream(id)) {
       DCHECK(session_delegate_);
diff --git a/net/quic/quartc/quartc_session.h b/net/quic/quartc/quartc_session.h
index fdfa7b75..16d8b57 100644
--- a/net/quic/quartc/quartc_session.h
+++ b/net/quic/quartc/quartc_session.h
@@ -24,6 +24,8 @@
       QuicConnectionId connection_id) const override;
 
   bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+                            const QuicSocketAddress& client_address,
+                            const QuicSocketAddress& peer_address,
                             const QuicSocketAddress& self_address,
                             std::string* error_details) const override;
 };
diff --git a/net/quic/quartc/quartc_stream_test.cc b/net/quic/quartc/quartc_stream_test.cc
index d5e7d93..37806e08 100644
--- a/net/quic/quartc/quartc_stream_test.cc
+++ b/net/quic/quartc/quartc_stream_test.cc
@@ -180,10 +180,6 @@
         QuicMakeUnique<MockQuartcStreamDelegate>(kStreamId, &read_buffer_);
     stream_ = new QuartcStream(kStreamId, session_.get());
     stream_->SetDelegate(mock_stream_delegate_.get());
-    if (!session_->register_streams_early()) {
-      session_->RegisterReliableStream(stream_->stream_id(),
-                                       QuicStream::kDefaultPriority);
-    }
     session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_));
   }
 
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index e451532f..34d0931 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -311,8 +311,7 @@
     result_ = result;
     crypto_config_->ProcessClientHello(
         result_, /*reject_only=*/false, /*connection_id=*/1, server_addr_,
-        client_addr_, AllSupportedTransportVersions().front(),
-        AllSupportedTransportVersions(),
+        client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
         /*use_stateless_rejects=*/true, /*server_designated_connection_id=*/0,
         clock_, QuicRandom::GetInstance(), compressed_certs_cache_, params_,
         signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
@@ -406,7 +405,8 @@
   server_session.OnSuccessfulVersionNegotiation(
       client_conn->supported_versions().front());
   EXPECT_CALL(*server_session.helper(),
-              CanAcceptClientHello(testing::_, testing::_, testing::_))
+              CanAcceptClientHello(testing::_, testing::_, testing::_,
+                                   testing::_, testing::_))
       .Times(testing::AnyNumber());
   EXPECT_CALL(*server_session.helper(),
               GenerateConnectionIdForReject(testing::_))
diff --git a/net/quic/test_tools/crypto_test_utils_test.cc b/net/quic/test_tools/crypto_test_utils_test.cc
index 315b7b66..8ddaf432 100644
--- a/net/quic/test_tools/crypto_test_utils_test.cc
+++ b/net/quic/test_tools/crypto_test_utils_test.cc
@@ -61,8 +61,7 @@
     result_ = result;
     crypto_config_->ProcessClientHello(
         result_, /*reject_only=*/false, /*connection_id=*/1, server_addr_,
-        client_addr_, AllSupportedTransportVersions().front(),
-        AllSupportedTransportVersions(),
+        client_addr_, AllSupportedVersions().front(), AllSupportedVersions(),
         /*use_stateless_rejects=*/true, /*server_designated_connection_id=*/0,
         clock_, QuicRandom::GetInstance(), compressed_certs_cache_, params_,
         signed_config_, /*total_framing_overhead=*/50, kDefaultMaxPacketSize,
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 4a7a0dd..07fa8e58 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -505,7 +505,7 @@
   ON_CALL(helper_, GenerateConnectionIdForReject(_))
       .WillByDefault(
           testing::Return(connection->random_generator()->RandUint64()));
-  ON_CALL(helper_, CanAcceptClientHello(_, _, _))
+  ON_CALL(helper_, CanAcceptClientHello(_, _, _, _, _))
       .WillByDefault(testing::Return(true));
 }
 
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index a6f7ab9..1095fb1 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -610,12 +610,7 @@
   bool support_server_push_;
 };
 
-class EndToEndTestWithTls : public EndToEndTest {
- protected:
-  EndToEndTestWithTls() : EndToEndTest() {
-    SetQuicReloadableFlag(quic_server_early_version_negotiation, true);
-  }
-};
+class EndToEndTestWithTls : public EndToEndTest {};
 
 // Run all end to end tests with all supported versions.
 INSTANTIATE_TEST_CASE_P(EndToEndTests,
@@ -1391,6 +1386,36 @@
   server_thread_->Resume();
 }
 
+TEST_P(EndToEndTest, ClientSuggestsIgnoredRTT) {
+  SetQuicReloadableFlag(quic_no_irtt, true);
+  // Client suggests initial RTT, but also specifies NRTT, so it's not used.
+  const QuicTime::Delta kInitialRTT = QuicTime::Delta::FromMicroseconds(20000);
+  client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT.ToMicroseconds());
+  QuicTagVector options;
+  options.push_back(kNRTT);
+  client_config_.SetConnectionOptionsToSend(options);
+
+  ASSERT_TRUE(Initialize());
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+  server_thread_->WaitForCryptoHandshakeConfirmed();
+
+  // Pause the server so we can access the server's internals without races.
+  server_thread_->Pause();
+  QuicDispatcher* dispatcher =
+      QuicServerPeer::GetDispatcher(server_thread_->server());
+  ASSERT_EQ(1u, dispatcher->session_map().size());
+  const QuicSentPacketManager& client_sent_packet_manager =
+      client_->client()->client_session()->connection()->sent_packet_manager();
+  const QuicSentPacketManager* server_sent_packet_manager =
+      GetSentPacketManagerFromFirstServerSession();
+
+  EXPECT_EQ(kInitialRTT,
+            client_sent_packet_manager.GetRttStats()->initial_rtt());
+  EXPECT_EQ(kInitialRTT,
+            server_sent_packet_manager->GetRttStats()->initial_rtt());
+  server_thread_->Resume();
+}
+
 TEST_P(EndToEndTest, MaxInitialRTT) {
   // Client tries to suggest twice the server's max initial rtt and the server
   // uses the max.
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 5e167368..ce846427f 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -203,9 +203,13 @@
 class ChloValidator : public ChloAlpnExtractor {
  public:
   ChloValidator(QuicCryptoServerStream::Helper* helper,
-                QuicSocketAddress self_address,
+                const QuicSocketAddress& client_address,
+                const QuicSocketAddress& peer_address,
+                const QuicSocketAddress& self_address,
                 StatelessRejector* rejector)
       : helper_(helper),
+        client_address_(client_address),
+        peer_address_(peer_address),
         self_address_(self_address),
         rejector_(rejector),
         can_accept_(false),
@@ -217,7 +221,8 @@
               const CryptoHandshakeMessage& chlo) override {
     // Extract the ALPN
     ChloAlpnExtractor::OnChlo(version, connection_id, chlo);
-    if (helper_->CanAcceptClientHello(chlo, self_address_, &error_details_)) {
+    if (helper_->CanAcceptClientHello(chlo, client_address_, peer_address_,
+                                      self_address_, &error_details_)) {
       can_accept_ = true;
       rejector_->OnChlo(version, connection_id,
                         helper_->GenerateConnectionIdForReject(connection_id),
@@ -231,6 +236,10 @@
 
  private:
   QuicCryptoServerStream::Helper* helper_;  // Unowned.
+  // client_address_ and peer_address_ could be different values for proxy
+  // connections.
+  QuicSocketAddress client_address_;
+  QuicSocketAddress peer_address_;
   QuicSocketAddress self_address_;
   StatelessRejector* rejector_;  // Unowned.
   bool can_accept_;
@@ -971,11 +980,12 @@
   }
 
   std::unique_ptr<StatelessRejector> rejector(new StatelessRejector(
-      version.transport_version, GetSupportedTransportVersions(),
-      crypto_config_, &compressed_certs_cache_, helper()->GetClock(),
-      helper()->GetRandomGenerator(), current_packet_->length(),
-      current_client_address_, current_self_address_));
-  ChloValidator validator(session_helper_.get(), current_self_address_,
+      version, GetSupportedVersions(), crypto_config_, &compressed_certs_cache_,
+      helper()->GetClock(), helper()->GetRandomGenerator(),
+      current_packet_->length(), current_client_address_,
+      current_self_address_));
+  ChloValidator validator(session_helper_.get(), current_client_address_,
+                          current_peer_address_, current_self_address_,
                           rejector.get());
   if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
                               config_.create_session_tag_indicators(),
@@ -1024,6 +1034,18 @@
     const QuicSocketAddress& current_self_address,
     std::unique_ptr<QuicReceivedPacket> current_packet,
     ParsedQuicVersion first_version) {
+  const bool enable_l1_munge = GetQuicRestartFlag(quic_enable_l1_munge);
+  if (enable_l1_munge) {
+    // Reset current_* to correspond to the packet which initiated the stateless
+    // reject logic.
+    current_client_address_ = current_client_address;
+    current_peer_address_ = current_peer_address;
+    current_self_address_ = current_self_address;
+    current_packet_ = current_packet.get();
+    current_connection_id_ = rejector->connection_id();
+    framer_.set_version(first_version);
+  }
+
   // Stop buffering packets on this connection
   const auto num_erased =
       temporarily_buffered_connections_.erase(rejector->connection_id());
@@ -1040,14 +1062,16 @@
     return;
   }
 
-  // Reset current_* to correspond to the packet which initiated the stateless
-  // reject logic.
-  current_client_address_ = current_client_address;
-  current_peer_address_ = current_peer_address;
-  current_self_address_ = current_self_address;
-  current_packet_ = current_packet.get();
-  current_connection_id_ = rejector->connection_id();
-  framer_.set_version(first_version);
+  if (!enable_l1_munge) {
+    // Reset current_* to correspond to the packet which initiated the stateless
+    // reject logic.
+    current_client_address_ = current_client_address;
+    current_peer_address_ = current_peer_address;
+    current_self_address_ = current_self_address;
+    current_packet_ = current_packet.get();
+    current_connection_id_ = rejector->connection_id();
+    framer_.set_version(first_version);
+  }
 
   ProcessStatelessRejectorState(std::move(rejector),
                                 first_version.transport_version);
diff --git a/net/tools/quic/quic_simple_crypto_server_stream_helper.cc b/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
index 56afbf82..d75a675 100644
--- a/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
+++ b/net/tools/quic/quic_simple_crypto_server_stream_helper.cc
@@ -21,6 +21,8 @@
 
 bool QuicSimpleCryptoServerStreamHelper::CanAcceptClientHello(
     const CryptoHandshakeMessage& message,
+    const QuicSocketAddress& client_address,
+    const QuicSocketAddress& peer_address,
     const QuicSocketAddress& self_address,
     std::string* error_details) const {
   return true;
diff --git a/net/tools/quic/quic_simple_crypto_server_stream_helper.h b/net/tools/quic/quic_simple_crypto_server_stream_helper.h
index 31c257df..585a232 100644
--- a/net/tools/quic/quic_simple_crypto_server_stream_helper.h
+++ b/net/tools/quic/quic_simple_crypto_server_stream_helper.h
@@ -23,6 +23,8 @@
       QuicConnectionId /*connection_id*/) const override;
 
   bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+                            const QuicSocketAddress& client_address,
+                            const QuicSocketAddress& peer_address,
                             const QuicSocketAddress& self_address,
                             std::string* error_details) const override;
 
diff --git a/net/tools/quic/quic_simple_server_session_helper.cc b/net/tools/quic/quic_simple_server_session_helper.cc
index 819553a..21a7977 100644
--- a/net/tools/quic/quic_simple_server_session_helper.cc
+++ b/net/tools/quic/quic_simple_server_session_helper.cc
@@ -18,6 +18,8 @@
 
 bool QuicSimpleServerSessionHelper::CanAcceptClientHello(
     const CryptoHandshakeMessage& message,
+    const QuicSocketAddress& client_address,
+    const QuicSocketAddress& peer_address,
     const QuicSocketAddress& self_address,
     std::string* error_details) const {
   return true;
diff --git a/net/tools/quic/quic_simple_server_session_helper.h b/net/tools/quic/quic_simple_server_session_helper.h
index 00a3bf9c..f2b3f3b 100644
--- a/net/tools/quic/quic_simple_server_session_helper.h
+++ b/net/tools/quic/quic_simple_server_session_helper.h
@@ -22,6 +22,8 @@
       QuicConnectionId /*connection_id*/) const override;
 
   bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
+                            const QuicSocketAddress& client_address,
+                            const QuicSocketAddress& peer_address,
                             const QuicSocketAddress& self_address,
                             std::string* error_details) const override;
 
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc
index 124ff389..7973f56 100644
--- a/net/tools/quic/quic_simple_server_session_test.cc
+++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -384,8 +384,7 @@
   EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams());
   EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams());
 
-  if (GetQuicReloadableFlag(quic_register_streams_early2) &&
-      GetQuicReloadableFlag(quic_register_static_streams)) {
+  if (GetQuicReloadableFlag(quic_register_static_streams)) {
     session_->UnregisterStreamPriority(kHeadersStreamId, /*is_static=*/true);
   }
   // Assume encryption already established.
@@ -395,8 +394,7 @@
                                      session_.get(), &stream_helper_);
   crypto_stream->set_encryption_established(true);
   QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
-  if (GetQuicReloadableFlag(quic_register_streams_early2) &&
-      GetQuicReloadableFlag(quic_register_static_streams)) {
+  if (GetQuicReloadableFlag(quic_register_static_streams)) {
     session_->RegisterStreamPriority(kHeadersStreamId, /*is_static=*/true,
                                      QuicStream::kDefaultPriority);
   }
@@ -482,8 +480,7 @@
 
     visitor_ = QuicConnectionPeer::GetVisitor(connection_);
 
-    if (GetQuicReloadableFlag(quic_register_streams_early2) &&
-        GetQuicReloadableFlag(quic_register_static_streams)) {
+    if (GetQuicReloadableFlag(quic_register_static_streams)) {
       session_->UnregisterStreamPriority(kHeadersStreamId, /*is_static=*/true);
     }
     QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), nullptr);
@@ -494,8 +491,7 @@
 
     crypto_stream->set_encryption_established(true);
     QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
-    if (GetQuicReloadableFlag(quic_register_streams_early2) &&
-        GetQuicReloadableFlag(quic_register_static_streams)) {
+    if (GetQuicReloadableFlag(quic_register_static_streams)) {
       session_->RegisterStreamPriority(kHeadersStreamId, /*is_static=*/true,
                                        QuicStream::kDefaultPriority);
     }
diff --git a/net/tools/quic/quic_spdy_client_session_test.cc b/net/tools/quic/quic_spdy_client_session_test.cc
index eb16b3f..32fe5d8 100644
--- a/net/tools/quic/quic_spdy_client_session_test.cc
+++ b/net/tools/quic/quic_spdy_client_session_test.cc
@@ -140,6 +140,13 @@
 }
 
 TEST_P(QuicSpdyClientSessionTest, NoEncryptionAfterInitialEncryption) {
+  if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+    // This test relies on resumption and is QUIC crypto specific, so it is
+    // disabled for TLS.
+    // TODO(nharper): Add support for resumption to the TLS handshake, and fix
+    // this test to not rely on QUIC crypto.
+    return;
+  }
   // Complete a handshake in order to prime the crypto config for 0-RTT.
   CompleteCryptoHandshake();
 
@@ -178,6 +185,12 @@
 }
 
 TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithNoFinOrRst) {
+  if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+    // This test relies on the MIDS transport parameter, which is not yet
+    // supported in TLS 1.3.
+    // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
+    return;
+  }
   EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AnyNumber());
   EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(AnyNumber());
 
@@ -198,6 +211,12 @@
 }
 
 TEST_P(QuicSpdyClientSessionTest, MaxNumStreamsWithRst) {
+  if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+    // This test relies on the MIDS transport parameter, which is not yet
+    // supported in TLS 1.3.
+    // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
+    return;
+  }
   EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AnyNumber());
   EXPECT_CALL(*connection_, OnStreamReset(_, _)).Times(AnyNumber());
 
@@ -219,6 +238,12 @@
 }
 
 TEST_P(QuicSpdyClientSessionTest, ResetAndTrailers) {
+  if (GetParam().handshake_protocol == PROTOCOL_TLS1_3) {
+    // This test relies on the MIDS transport parameter, which is not yet
+    // supported in TLS 1.3.
+    // TODO(nharper): Add support for Transport Parameters in the TLS handshake.
+    return;
+  }
   // Tests the situation in which the client sends a RST at the same time that
   // the server sends trailing headers (trailers). Receipt of the trailers by
   // the client should result in all outstanding stream state being tidied up
diff --git a/net/tools/quic/stateless_rejector.cc b/net/tools/quic/stateless_rejector.cc
index 8ae3e851..3497c41 100644
--- a/net/tools/quic/stateless_rejector.cc
+++ b/net/tools/quic/stateless_rejector.cc
@@ -35,8 +35,8 @@
 };
 
 StatelessRejector::StatelessRejector(
-    QuicTransportVersion version,
-    const QuicTransportVersionVector& versions,
+    ParsedQuicVersion version,
+    const ParsedQuicVersionVector& versions,
     const QuicCryptoServerConfig* crypto_config,
     QuicCompressedCertsCache* compressed_certs_cache,
     const QuicClock* clock,
@@ -89,7 +89,7 @@
   StatelessRejector* rejector_ptr = rejector.get();
   rejector_ptr->crypto_config_->ValidateClientHello(
       rejector_ptr->chlo_, rejector_ptr->client_address_.host(),
-      rejector_ptr->server_address_, rejector_ptr->version_,
+      rejector_ptr->server_address_, rejector_ptr->version_.transport_version,
       rejector_ptr->clock_, rejector_ptr->signed_config_,
       std::unique_ptr<ValidateCallback>(
           new ValidateCallback(std::move(rejector), std::move(done_cb))));
@@ -133,7 +133,8 @@
       version_, versions_,
       /*use_stateless_rejects=*/true, server_designated_connection_id_, clock_,
       random_, compressed_certs_cache_, params_, signed_config_,
-      QuicCryptoStream::CryptoMessageFramingOverhead(version_),
+      QuicCryptoStream::CryptoMessageFramingOverhead(
+          version_.transport_version),
       chlo_packet_size_, std::move(cb));
 }
 
diff --git a/net/tools/quic/stateless_rejector.h b/net/tools/quic/stateless_rejector.h
index ac04e402..d678cf8 100644
--- a/net/tools/quic/stateless_rejector.h
+++ b/net/tools/quic/stateless_rejector.h
@@ -24,8 +24,8 @@
     REJECTED,     // The CHLO was rejected.
   };
 
-  StatelessRejector(QuicTransportVersion version,
-                    const QuicTransportVersionVector& versions,
+  StatelessRejector(ParsedQuicVersion version,
+                    const ParsedQuicVersionVector& versions,
                     const QuicCryptoServerConfig* crypto_config,
                     QuicCompressedCertsCache* compressed_certs_cache,
                     const QuicClock* clock,
@@ -94,8 +94,8 @@
   State state_;
   QuicErrorCode error_;
   QuicString error_details_;
-  QuicTransportVersion version_;
-  QuicTransportVersionVector versions_;
+  ParsedQuicVersion version_;
+  ParsedQuicVersionVector versions_;
   QuicConnectionId connection_id_;
   QuicConnectionId server_designated_connection_id_;
   QuicByteCount chlo_packet_size_;
diff --git a/net/tools/quic/stateless_rejector_test.cc b/net/tools/quic/stateless_rejector_test.cc
index 62e741b..4eb3bae 100644
--- a/net/tools/quic/stateless_rejector_test.cc
+++ b/net/tools/quic/stateless_rejector_test.cc
@@ -52,12 +52,13 @@
 
 // Test various combinations of QUIC version and flag state.
 struct TestParams {
-  QuicTransportVersion version;
+  ParsedQuicVersion version =
+      ParsedQuicVersion{PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED};
   FlagsMode flags;
 };
 
 QuicString TestParamToString(const testing::TestParamInfo<TestParams>& params) {
-  return QuicStrCat("v", params.param.version, "_",
+  return QuicStrCat("v", ParsedQuicVersionToString(params.param.version), "_",
                     FlagsModeToString(params.param.flags));
 }
 
@@ -65,7 +66,7 @@
   std::vector<TestParams> params;
   for (FlagsMode flags :
        {ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED}) {
-    for (QuicTransportVersion version : AllSupportedTransportVersions()) {
+    for (ParsedQuicVersion version : AllSupportedVersions()) {
       TestParams param;
       param.version = version;
       param.flags = flags;
@@ -88,7 +89,7 @@
             QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
         rejector_(QuicMakeUnique<StatelessRejector>(
             GetParam().version,
-            AllSupportedTransportVersions(),
+            AllSupportedVersions(),
             &config_,
             &compressed_certs_cache_,
             &clock_,
@@ -112,8 +113,7 @@
         "#" + QuicTextUtils::HexEncode(config_peer_.GetPrimaryConfig()->id);
 
     // Encode the QUIC version.
-    ver_hex_ = QuicVersionLabelToString(
-        QuicVersionToQuicVersionLabel(GetParam().version));
+    ver_hex_ = ParsedQuicVersionToString(GetParam().version);
 
     // Generate a public value.
     char public_value[32];
@@ -180,7 +180,7 @@
       {{"PDMD", "X509"},
        {"COPT", "SREJ"}});
   // clang-format on
-  rejector_->OnChlo(GetParam().version, kConnectionId,
+  rejector_->OnChlo(GetParam().version.transport_version, kConnectionId,
                     kServerDesignateConnectionId, client_hello);
 
   if (GetParam().flags != ENABLED) {
@@ -209,7 +209,7 @@
       kClientHelloMinimumSize);
   // clang-format on
 
-  rejector_->OnChlo(GetParam().version, kConnectionId,
+  rejector_->OnChlo(GetParam().version.transport_version, kConnectionId,
                     kServerDesignateConnectionId, client_hello);
   EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
 }
@@ -229,7 +229,7 @@
       kClientHelloMinimumSize);
   // clang-format on
 
-  rejector_->OnChlo(GetParam().version, kConnectionId,
+  rejector_->OnChlo(GetParam().version.transport_version, kConnectionId,
                     kServerDesignateConnectionId, client_hello);
   if (GetParam().flags != ENABLED) {
     EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
@@ -271,7 +271,7 @@
       kClientHelloMinimumSize);
   // clang-format on
 
-  rejector_->OnChlo(GetParam().version, kConnectionId,
+  rejector_->OnChlo(GetParam().version.transport_version, kConnectionId,
                     kServerDesignateConnectionId, client_hello);
   if (GetParam().flags != ENABLED) {
     EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
diff --git a/net/tools/quic/test_tools/mock_quic_session_visitor.h b/net/tools/quic/test_tools/mock_quic_session_visitor.h
index 793be8d4..80cf2ba 100644
--- a/net/tools/quic/test_tools/mock_quic_session_visitor.h
+++ b/net/tools/quic/test_tools/mock_quic_session_visitor.h
@@ -37,8 +37,10 @@
   ~MockQuicCryptoServerStreamHelper() override;
   MOCK_CONST_METHOD1(GenerateConnectionIdForReject,
                      QuicConnectionId(QuicConnectionId connection_id));
-  MOCK_CONST_METHOD3(CanAcceptClientHello,
+  MOCK_CONST_METHOD5(CanAcceptClientHello,
                      bool(const CryptoHandshakeMessage& message,
+                          const QuicSocketAddress& client_address,
+                          const QuicSocketAddress& peer_address,
                           const QuicSocketAddress& self_address,
                           std::string* error_details));
 
diff --git a/printing/common/pdf_metafile_utils.cc b/printing/common/pdf_metafile_utils.cc
index c3c073e8..fe3fd49 100644
--- a/printing/common/pdf_metafile_utils.cc
+++ b/printing/common/pdf_metafile_utils.cc
@@ -51,6 +51,7 @@
   metadata.fCreator = creator.empty()
                           ? SkString("Chromium")
                           : SkString(creator.c_str(), creator.size());
+  metadata.fRasterDPI = 300.0f;
   return SkDocument::MakePDF(stream, metadata);
 }
 
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 83045cbd..b7651d3 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -32,6 +32,8 @@
   sources = [
     "debug_recording.cc",
     "debug_recording.h",
+    "delay_buffer.cc",
+    "delay_buffer.h",
     "group_coordinator.cc",
     "group_coordinator.h",
     "group_member.h",
@@ -74,6 +76,7 @@
 
   sources = [
     "debug_recording_unittest.cc",
+    "delay_buffer_unittest.cc",
     "group_coordinator_unittest.cc",
     "input_stream_unittest.cc",
     "local_muter_unittest.cc",
@@ -83,6 +86,8 @@
     "sync_reader_unittest.cc",
     "test/audio_system_to_service_adapter_test.cc",
     "test/debug_recording_session_unittest.cc",
+    "test/fake_consumer.cc",
+    "test/fake_consumer.h",
     "test/fake_group_member.cc",
     "test/fake_group_member.h",
     "test/in_process_service_test.cc",
diff --git a/services/audio/delay_buffer.cc b/services/audio/delay_buffer.cc
new file mode 100644
index 0000000..17d2a04b
--- /dev/null
+++ b/services/audio/delay_buffer.cc
@@ -0,0 +1,126 @@
+// 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 "services/audio/delay_buffer.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/numerics/safe_conversions.h"
+#include "media/base/audio_bus.h"
+#include "media/base/vector_math.h"
+
+namespace audio {
+
+DelayBuffer::DelayBuffer(int history_size) : history_size_(history_size) {}
+
+DelayBuffer::~DelayBuffer() = default;
+
+void DelayBuffer::Write(FrameTicks position,
+                        const media::AudioBus& input_bus,
+                        double volume) {
+  DCHECK(chunks_.empty() || chunks_.back().GetEndPosition() <= position);
+
+  // Prune-out the oldest InputChunks, but ensure that this DelayBuffer is
+  // maintaining at least |history_size_| frames in total when this method
+  // returns (i.e., after the current chunk is inserted).
+  const FrameTicks prune_position =
+      position + input_bus.frames() - history_size_;
+  while (!chunks_.empty() &&
+         chunks_.front().GetEndPosition() <= prune_position) {
+    chunks_.pop_front();
+  }
+
+  // Make a copy of the AudioBus for later consumption. Apply the volume setting
+  // by scaling the audio signal during the copy.
+  auto copy = media::AudioBus::Create(input_bus.channels(), input_bus.frames());
+  for (int ch = 0; ch < input_bus.channels(); ++ch) {
+    media::vector_math::FMUL(input_bus.channel(ch), volume, input_bus.frames(),
+                             copy->channel(ch));
+  }
+
+  chunks_.emplace_back(position, std::move(copy));
+}
+
+void DelayBuffer::Read(FrameTicks from,
+                       int frames_to_read,
+                       media::AudioBus* output_bus) {
+  DCHECK_LE(frames_to_read, output_bus->frames());
+
+  // Remove all of the oldest chunks until the one in front contains the |from|
+  // position (or is the first chunk after it).
+  while (!chunks_.empty() && chunks_.front().GetEndPosition() <= from) {
+    chunks_.pop_front();
+  }
+
+  // Loop, transferring data from each InputChunk to the output AudioBus until
+  // the requested number of frames have been read.
+  for (int frames_remaining = frames_to_read; frames_remaining > 0;) {
+    const int dest_offset = frames_to_read - frames_remaining;
+
+    // If attempting to read past the end of the recorded signal, zero-pad the
+    // rest of the output and return.
+    if (chunks_.empty()) {
+      output_bus->ZeroFramesPartial(dest_offset, frames_remaining);
+      return;
+    }
+    const InputChunk& chunk = chunks_.front();
+
+    // This is the offset to the frame within the chunk's AudioBus that
+    // corresponds to the offset in the output AudioBus. If this calculated
+    // value is out-of-range, there is a gap (i.e., a missing piece of audio
+    // signal) in the recording.
+    const int source_offset =
+        base::saturated_cast<int>(from + dest_offset - chunk.position);
+
+    if (source_offset < 0) {
+      // There is a gap in the recording. Fill zeroes in the corresponding part
+      // of the output.
+      const int frames_to_zero_fill = (source_offset + frames_remaining <= 0)
+                                          ? frames_remaining
+                                          : -source_offset;
+      output_bus->ZeroFramesPartial(dest_offset, frames_to_zero_fill);
+      frames_remaining -= frames_to_zero_fill;
+      continue;
+    }
+    DCHECK_LE(source_offset, chunk.bus->frames());
+
+    // Copy some or all of the frames in the current chunk to the output; the
+    // lesser of: a) the frames available in the chunk, or b) the frames
+    // remaining to output.
+    const int frames_to_copy_from_chunk = chunk.bus->frames() - source_offset;
+    if (frames_to_copy_from_chunk <= frames_remaining) {
+      chunk.bus->CopyPartialFramesTo(source_offset, frames_to_copy_from_chunk,
+                                     dest_offset, output_bus);
+      frames_remaining -= frames_to_copy_from_chunk;
+      chunks_.pop_front();  // All frames from this chunk have been consumed.
+    } else {
+      chunk.bus->CopyPartialFramesTo(source_offset, frames_remaining,
+                                     dest_offset, output_bus);
+      return;  // The |output_bus| has been fully populated.
+    }
+  }
+}
+
+DelayBuffer::FrameTicks DelayBuffer::GetBeginPosition() const {
+  return chunks_.empty() ? 0 : chunks_.front().position;
+}
+
+DelayBuffer::FrameTicks DelayBuffer::GetEndPosition() const {
+  return chunks_.empty() ? 0 : chunks_.back().GetEndPosition();
+}
+
+DelayBuffer::InputChunk::InputChunk(FrameTicks p,
+                                    std::unique_ptr<media::AudioBus> b)
+    : position(p), bus(std::move(b)) {}
+DelayBuffer::InputChunk::InputChunk(DelayBuffer::InputChunk&&) = default;
+DelayBuffer::InputChunk& DelayBuffer::InputChunk::operator=(
+    DelayBuffer::InputChunk&&) = default;
+DelayBuffer::InputChunk::~InputChunk() = default;
+
+DelayBuffer::FrameTicks DelayBuffer::InputChunk::GetEndPosition() const {
+  return position + bus->frames();
+}
+
+}  // namespace audio
diff --git a/services/audio/delay_buffer.h b/services/audio/delay_buffer.h
new file mode 100644
index 0000000..2d1482c
--- /dev/null
+++ b/services/audio/delay_buffer.h
@@ -0,0 +1,109 @@
+// 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 SERVICES_AUDIO_DELAY_BUFFER_H_
+#define SERVICES_AUDIO_DELAY_BUFFER_H_
+
+#include <memory>
+
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+
+namespace media {
+class AudioBus;
+}  // namespace media
+
+namespace audio {
+
+// Records and maintains a recent history of an audio signal, then allows
+// read-back starting from part of the recording. While this looks a lot like a
+// FIFO, it is not because Read() will typically not be reading from one end of
+// a queue.
+//
+// The audio format is the same throughout all operations, as this DelayBuffer
+// does not resample or remix the audio. Also, for absolute precision, it uses
+// frame counts to track the timing of the audio recorded and read.
+//
+// The typical use case is the loopback audio system: In this scenario, the
+// service has an audio output stream running for local playback, and the
+// stream's audio is timed to play back in the near future (usually, 1 ms to 20
+// ms, depending on the platform). When loopback is active, that audio will be
+// copied into this DelayBuffer via calls to Write(). Then, the loopback audio
+// stream implementation will Read() the audio at a time in the recent past
+// (approximately 20 ms before "now," but this will vary slightly). Because of
+// clock drift concerns, the loopback implementation will slightly compress/
+// stretch the audio signal it pulls out of this buffer, to maintain
+// synchronization, and this will cause it to vary the number of frames read for
+// each successive Read() call.
+class DelayBuffer {
+ public:
+  // Use sample counts as a measure of audio signal position.
+  using FrameTicks = int64_t;
+
+  // Construct a DelayBuffer that keeps at least |history_size| un-read frames
+  // recorded.
+  explicit DelayBuffer(int history_size);
+
+  ~DelayBuffer();
+
+  // Inserts a copy of the given audio into the buffer. |position| must be
+  // monotonically increasing, and the audio must not overlap any
+  // previously-written audio. The length of the |input_bus| may vary, but the
+  // channel layout may not. The given |volume| will be used to scale the audio
+  // during the copy to the internal buffer.
+  void Write(FrameTicks position,
+             const media::AudioBus& input_bus,
+             double volume);
+
+  // Reads audio from the buffer, starting at the given |from| position, which
+  // must not overlap any previously-read audio. |frames_to_read| is the number
+  // of frames to read, which may be any amount less than or equal to the size
+  // of the |output_bus|. No part of the |output_bus| beyond the first
+  // |frames_to_read| will be modified. If there are gaps (i.e., missing pieces)
+  // of the recording, zeros will be filled in the output.
+  void Read(FrameTicks from, int frames_to_read, media::AudioBus* output_bus);
+
+  // Returns the current buffered range of the recording, ala the usual C++
+  // [begin,end)  semantics.
+  FrameTicks GetBeginPosition() const;
+  FrameTicks GetEndPosition() const;
+
+ private:
+  struct InputChunk {
+    // The position of the first frame in this chunk.
+    FrameTicks position;
+
+    // The storage for the audio frames.
+    std::unique_ptr<media::AudioBus> bus;
+
+    // Constructor for an InputChunk with data.
+    InputChunk(FrameTicks p, std::unique_ptr<media::AudioBus> b);
+
+    // Move constructor/assignment.
+    InputChunk(InputChunk&& other);
+    InputChunk& operator=(InputChunk&& other);
+
+    ~InputChunk();
+
+    // Returns the position just after the last frame's position.
+    FrameTicks GetEndPosition() const;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(InputChunk);
+  };
+
+  // The minimum number of un-read frames that must be kept.
+  const int history_size_;
+
+  // A queue storing each chunk of recorded audio. The elements in the queue are
+  // always in-order, chronologically increasing by InputChunk::position, and do
+  // not overlap.
+  base::circular_deque<InputChunk> chunks_;
+
+  DISALLOW_COPY_AND_ASSIGN(DelayBuffer);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_DELAY_BUFFER_H_
diff --git a/services/audio/delay_buffer_unittest.cc b/services/audio/delay_buffer_unittest.cc
new file mode 100644
index 0000000..5fcaad7
--- /dev/null
+++ b/services/audio/delay_buffer_unittest.cc
@@ -0,0 +1,167 @@
+// 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 "services/audio/delay_buffer.h"
+
+#include <algorithm>
+
+#include "media/base/audio_bus.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace audio {
+namespace {
+
+constexpr int kChannels = 1;
+constexpr int kMaxFrames = 32;
+
+#define EXPECT_BUS_VALUES_EQ(bus, begin, end, value)                        \
+  {                                                                         \
+    const auto IsValue = [](float x) { return x == (value); };              \
+    EXPECT_TRUE(std::all_of((bus)->channel(0) + (begin),                    \
+                            (bus)->channel(0) + (end) - (begin), IsValue)); \
+  }
+
+TEST(DelayBufferTest, RecordsAMaximumNumberOfFrames) {
+  DelayBuffer buffer(kMaxFrames);
+  ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition());
+
+  constexpr int frames_per_bus = kMaxFrames / 4;
+  const auto bus = media::AudioBus::Create(kChannels, frames_per_bus);
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0);
+
+  // Fill the buffer.
+  DelayBuffer::FrameTicks position = 0;
+  for (int i = 0; i < 4; ++i) {
+    buffer.Write(position, *bus, 1.0);
+    position += frames_per_bus;
+    EXPECT_EQ(0, buffer.GetBeginPosition());
+    EXPECT_EQ(position, buffer.GetEndPosition());
+  }
+
+  // Writing just one more bus should cause the leading frames to be dropped.
+  buffer.Write(position, *bus, 1.0);
+  position += frames_per_bus;
+  EXPECT_EQ(position - kMaxFrames, buffer.GetBeginPosition());
+  EXPECT_EQ(position, buffer.GetEndPosition());
+
+  // Now, simulate a gap in the recording by recording the next bus late.
+  position += frames_per_bus * 2;
+  buffer.Write(position, *bus, 1.0);
+  position += frames_per_bus;
+  EXPECT_EQ(position - kMaxFrames, buffer.GetBeginPosition());
+  EXPECT_EQ(position, buffer.GetEndPosition());
+}
+
+TEST(DelayBufferTest, ReadsSilenceIfNothingWasRecorded) {
+  DelayBuffer buffer(kMaxFrames);
+  ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition());
+
+  DelayBuffer::FrameTicks position = 0;
+  constexpr int frames_per_bus = kMaxFrames / 4;
+  const auto bus = media::AudioBus::Create(kChannels, frames_per_bus);
+
+  for (int i = 0; i < 10; ++i) {
+    // Set data in the bus to confirm it is all going to be overwritten.
+    std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0);
+
+    buffer.Read(position, frames_per_bus, bus.get());
+    EXPECT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition());
+    EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 0.0);
+
+    position += frames_per_bus;
+  }
+}
+
+TEST(DelayBufferTest, ReadsSilenceIfOutsideRecordedRange) {
+  DelayBuffer buffer(kMaxFrames);
+  ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition());
+
+  constexpr int frames_per_bus = kMaxFrames / 4;
+  const auto bus = media::AudioBus::Create(kChannels, frames_per_bus);
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0);
+
+  // Fill the buffer.
+  DelayBuffer::FrameTicks position = 0;
+  for (int i = 0; i < 4; ++i) {
+    buffer.Write(position, *bus, 1.0);
+    position += frames_per_bus;
+  }
+  EXPECT_EQ(0, buffer.GetBeginPosition());
+  EXPECT_EQ(position, buffer.GetEndPosition());
+
+  // Read before the begin position and expect to get silence.
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(-kMaxFrames, frames_per_bus, bus.get());
+  EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 0.0);
+
+  // Read at a position one before the begin position. Expect the first sample
+  // to be 0.0, and the rest 1.0.
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(buffer.GetBeginPosition() - 1, frames_per_bus, bus.get());
+  EXPECT_EQ(0.0, bus->channel(0)[0]);
+  EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 1.0);
+
+  // Read at a position where the last sample should be 0.0 and the rest 1.0.
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(buffer.GetEndPosition() - frames_per_bus + 1, frames_per_bus,
+              bus.get());
+  EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus - 1, 1.0);
+  EXPECT_EQ(0.0, bus->channel(0)[frames_per_bus - 1]);
+
+  // Read after the end position and expect to get silence.
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(kMaxFrames, frames_per_bus, bus.get());
+  EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 0.0);
+}
+
+TEST(DelayBufferTest, ReadsGapsInRecording) {
+  DelayBuffer buffer(kMaxFrames);
+  ASSERT_EQ(buffer.GetBeginPosition(), buffer.GetEndPosition());
+
+  constexpr int frames_per_bus = kMaxFrames / 4;
+  const auto bus = media::AudioBus::Create(kChannels, frames_per_bus);
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 1.0);
+
+  // Fill the buffer, but with a gap in the third quarter of it.
+  DelayBuffer::FrameTicks record_position = 0;
+  for (int i = 0; i < 4; ++i) {
+    if (i != 2) {
+      buffer.Write(record_position, *bus, 1.0);
+    }
+    record_position += frames_per_bus;
+  }
+  EXPECT_EQ(0, buffer.GetBeginPosition());
+  EXPECT_EQ(record_position, buffer.GetEndPosition());
+
+  // Read through the whole range, but offset by one frame early. Confirm the
+  // silence gap appears in the right place.
+  DelayBuffer::FrameTicks read_position = -1;
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(read_position, frames_per_bus, bus.get());
+  read_position += frames_per_bus;
+  EXPECT_EQ(0.0, bus->channel(0)[0]);
+  EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 1.0);
+
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(read_position, frames_per_bus, bus.get());
+  read_position += frames_per_bus;
+  EXPECT_BUS_VALUES_EQ(bus, 0, frames_per_bus, 1.0);
+
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(read_position, frames_per_bus, bus.get());
+  read_position += frames_per_bus;
+  EXPECT_EQ(1.0, bus->channel(0)[0]);
+  // The gap begins.
+  EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 0.0);
+
+  std::fill(bus->channel(0), bus->channel(0) + frames_per_bus, 0.5);
+  buffer.Read(read_position, frames_per_bus, bus.get());
+  read_position += frames_per_bus;
+  EXPECT_EQ(0.0, bus->channel(0)[0]);
+  // The gap ends.
+  EXPECT_BUS_VALUES_EQ(bus, 1, frames_per_bus - 1, 1.0);
+}
+
+}  // namespace
+}  // namespace audio
diff --git a/services/audio/test/fake_consumer.cc b/services/audio/test/fake_consumer.cc
new file mode 100644
index 0000000..4d3241b
--- /dev/null
+++ b/services/audio/test/fake_consumer.cc
@@ -0,0 +1,114 @@
+// 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 "services/audio/test/fake_consumer.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/numerics/math_constants.h"
+#include "media/base/audio_bus.h"
+
+namespace audio {
+
+FakeConsumer::FakeConsumer(int channels, int sample_rate)
+    : sample_rate_(sample_rate) {
+  recorded_channel_data_.resize(channels);
+}
+
+FakeConsumer::~FakeConsumer() = default;
+
+int FakeConsumer::GetRecordedFrameCount() const {
+  return static_cast<int>(recorded_channel_data_[0].size());
+}
+
+void FakeConsumer::Clear() {
+  for (auto& data : recorded_channel_data_) {
+    data.clear();
+  }
+}
+
+void FakeConsumer::Consume(const media::AudioBus& bus) {
+  CHECK_EQ(static_cast<int>(recorded_channel_data_.size()), bus.channels());
+  for (int ch = 0; ch < static_cast<int>(recorded_channel_data_.size()); ++ch) {
+    const float* const src = bus.channel(ch);
+    std::vector<float>& samples = recorded_channel_data_[ch];
+    samples.insert(samples.end(), src, src + bus.frames());
+  }
+}
+
+bool FakeConsumer::IsSilent(int channel) const {
+  return IsSilentInRange(channel, 0, GetRecordedFrameCount());
+}
+
+bool FakeConsumer::IsSilentInRange(int channel,
+                                   int begin_frame,
+                                   int end_frame) const {
+  CHECK_LT(channel, static_cast<int>(recorded_channel_data_.size()));
+  const std::vector<float>& samples = recorded_channel_data_[channel];
+
+  CHECK_GE(begin_frame, 0);
+  CHECK_LE(begin_frame, end_frame);
+  CHECK_LE(end_frame, static_cast<int>(samples.size()));
+
+  if (begin_frame == end_frame) {
+    return true;
+  }
+  const float value = samples[begin_frame];
+  return std::all_of(samples.data() + begin_frame + 1,
+                     samples.data() + end_frame,
+                     [&value](float f) { return f == value; });
+}
+
+int FakeConsumer::FindEndOfSilence(int channel, int begin_frame) const {
+  CHECK_LT(channel, static_cast<int>(recorded_channel_data_.size()));
+  CHECK_GE(begin_frame, 0);
+  const std::vector<float>& samples = recorded_channel_data_[channel];
+
+  if (static_cast<int>(samples.size()) <= begin_frame) {
+    return begin_frame;
+  }
+  const float value = samples[begin_frame];
+  const float* at = std::find_if(samples.data() + begin_frame + 1,
+                                 samples.data() + GetRecordedFrameCount(),
+                                 [&value](float f) { return f != value; });
+  return at - samples.data();
+}
+
+double FakeConsumer::ComputeAmplitudeAt(int channel,
+                                        double frequency,
+                                        int end_frame) const {
+  CHECK_LT(channel, static_cast<int>(recorded_channel_data_.size()));
+  CHECK_GT(frequency, 0.0);
+  const std::vector<float>& samples = recorded_channel_data_[channel];
+  CHECK_LE(end_frame, static_cast<int>(samples.size()));
+
+  // Attempt to analyze the last three cycles of waveform, or less if the
+  // recording is shorter than that. Three is chosen here because this will
+  // allow the algorithm below to reliably compute an amplitude value that is
+  // very close to that which was used to generate the pure source signal, even
+  // if the implementation under test has slightly stretched/compressed the
+  // signal (e.g., +/- 1 Hz).
+  const int analysis_length =
+      std::min(end_frame, static_cast<int>(3 * sample_rate_ / frequency));
+  if (analysis_length == 0) {
+    return 0.0;
+  }
+
+  // Compute the amplitude for just the |frequency| of interest, as opposed to
+  // doing a full Discrete Fourier Transform.
+  const double step = 2.0 * base::kPiDouble * frequency / sample_rate_;
+  double real_part = 0.0;
+  double img_part = 0.0;
+  for (int i = end_frame - analysis_length; i < end_frame; ++i) {
+    real_part += samples[i] * std::cos(i * step);
+    img_part -= samples[i] * std::sin(i * step);
+  }
+  const double normalization_factor = 2.0 / analysis_length;
+  return std::sqrt(real_part * real_part + img_part * img_part) *
+         normalization_factor;
+}
+
+}  // namespace audio
diff --git a/services/audio/test/fake_consumer.h b/services/audio/test/fake_consumer.h
new file mode 100644
index 0000000..28b3b33
--- /dev/null
+++ b/services/audio/test/fake_consumer.h
@@ -0,0 +1,59 @@
+// 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 SERVICES_AUDIO_TEST_FAKE_CONSUMER_H_
+#define SERVICES_AUDIO_TEST_FAKE_CONSUMER_H_
+
+#include <vector>
+
+#include "base/macros.h"
+
+namespace media {
+class AudioBus;
+}
+
+namespace audio {
+
+// Consumes and records the audio signal. Then, test procedures may use the
+// utility methods to analyze the recording.
+class FakeConsumer {
+ public:
+  FakeConsumer(int channels, int sample_rate);
+
+  ~FakeConsumer();
+
+  // Returns the total number of frames recorded (the end position of the
+  // recording).
+  int GetRecordedFrameCount() const;
+
+  // Throws away all samples recorded so far.
+  void Clear();
+
+  // Appends the audio signal in |bus| to the recording.
+  void Consume(const media::AudioBus& bus);
+
+  // Returns true if all (or a part) of the recording in |channel| is flat
+  // (i.e., not oscillating, and effectively silent).
+  bool IsSilent(int channel) const;
+  bool IsSilentInRange(int channel, int begin_frame, int end_frame) const;
+
+  // Returns the position at which silence in the recording ends, at or after
+  // |begin_frame|. If the entire recording after the given position is silent,
+  // this will return GetRecordedFrameCount().
+  int FindEndOfSilence(int channel, int begin_frame) const;
+
+  // Returns the amplitude of the given |frequency| in the given |channel| just
+  // before the given |end_frame| position.
+  double ComputeAmplitudeAt(int channel, double frequency, int end_frame) const;
+
+ private:
+  const int sample_rate_;
+  std::vector<std::vector<float>> recorded_channel_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeConsumer);
+};
+
+}  // namespace audio
+
+#endif  // SERVICES_AUDIO_TEST_FAKE_CONSUMER_H_
diff --git a/services/network/cross_origin_read_blocking_unittest.cc b/services/network/cross_origin_read_blocking_unittest.cc
index 7722ca2..68a1e39 100644
--- a/services/network/cross_origin_read_blocking_unittest.cc
+++ b/services/network/cross_origin_read_blocking_unittest.cc
@@ -140,7 +140,6 @@
   StringPiece json_data2("{ \"key   \\\"  \"          \t\t\r\n:");
   StringPiece non_json_data0("\t\t\r\n   { name : \"chrome\", ");
   StringPiece non_json_data1("\t\t\r\n   foo({ \"name\" : \"chrome\", ");
-  StringPiece empty_data("");
 
   EXPECT_EQ(SniffingResult::kYes,
             CrossOriginReadBlocking::SniffForJSON(json_data));
diff --git a/services/service_manager/runner/init.cc b/services/service_manager/runner/init.cc
index 0162ea6d..f598822 100644
--- a/services/service_manager/runner/init.cc
+++ b/services/service_manager/runner/init.cc
@@ -67,6 +67,7 @@
   }
 }
 
+NO_SANITIZE("cfi-icall")
 void CallLibraryEarlyInitialization(base::NativeLibrary app_library) {
   // Do whatever warming that the service wants.
 
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc
index 202982f..69e56ce 100644
--- a/services/tracing/perfetto/json_trace_exporter.cc
+++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -16,6 +16,8 @@
 #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h"
 #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_packet.pb.h"
 
+using TraceEvent = base::trace_event::TraceEvent;
+
 namespace {
 
 void OutputJSONFromTraceEventProto(
@@ -111,9 +113,58 @@
     base::StringAppendF(out, ",\"s\":\"%c\"", scope);
   }
 
-  *out += ",\"args\":\"__stripped__\"";
+  *out += ",\"args\":{";
+  for (int i = 0; i < event.args_size(); ++i) {
+    auto& arg = event.args(i);
 
-  *out += "}";
+    if (i > 0) {
+      *out += ",";
+    }
+
+    *out += "\"";
+    *out += arg.name();
+    *out += "\":";
+
+    TraceEvent::TraceValue value;
+    if (arg.has_bool_value()) {
+      value.as_bool = arg.bool_value();
+      TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_BOOL, value, out);
+      continue;
+    }
+
+    if (arg.has_uint_value()) {
+      value.as_uint = arg.uint_value();
+      TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_UINT, value, out);
+      continue;
+    }
+
+    if (arg.has_int_value()) {
+      value.as_int = arg.int_value();
+      TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_INT, value, out);
+      continue;
+    }
+
+    if (arg.has_double_value()) {
+      value.as_double = arg.double_value();
+      TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_DOUBLE, value, out);
+      continue;
+    }
+
+    if (arg.has_pointer_value()) {
+      value.as_pointer = reinterpret_cast<void*>(arg.pointer_value());
+      TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_POINTER, value, out);
+      continue;
+    }
+
+    if (arg.has_string_value()) {
+      std::string str = arg.string_value();
+      value.as_string = &str[0];
+      TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_STRING, value, out);
+      continue;
+    }
+  }
+
+  *out += "}}";
 }
 
 }  // namespace
diff --git a/services/tracing/perfetto/json_trace_exporter_unittest.cc b/services/tracing/perfetto/json_trace_exporter_unittest.cc
index 0bb40352..bd5e14a4 100644
--- a/services/tracing/perfetto/json_trace_exporter_unittest.cc
+++ b/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -8,8 +8,10 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/json/json_reader.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/trace_event_analyzer.h"
 #include "base/trace_event/trace_event.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -140,24 +142,29 @@
   }
 
   void OnTraceEventJSON(const std::string& json, bool has_more) {
-    last_received_json_ = json;
+    // The TraceAnalyzer expects the raw trace output, without the
+    // wrapping root-node.
+    static const size_t kTracingPreambleLength = strlen("\"{traceEvents\":");
+    static const size_t kTracingEpilogueLength = strlen("}");
+    std::string raw_events = json.substr(
+        kTracingPreambleLength,
+        json.length() - kTracingPreambleLength - kTracingEpilogueLength);
+
+    trace_analyzer_.reset(trace_analyzer::TraceAnalyzer::Create(raw_events));
+    EXPECT_TRUE(trace_analyzer_);
   }
 
-  void EmitTestPacket() {
-    perfetto::protos::TracePacket trace_packet_proto;
-
-    auto* event_bundle = trace_packet_proto.mutable_chrome_events();
-    auto* new_trace_event = event_bundle->add_trace_events();
-
-    new_trace_event->set_name("name");
+  void SetTestPacketBasicData(
+      perfetto::protos::ChromeTraceEvent* new_trace_event) {
+    new_trace_event->set_name("foo_name");
     new_trace_event->set_timestamp(42);
     new_trace_event->set_flags(TRACE_EVENT_FLAG_HAS_GLOBAL_ID |
                                TRACE_EVENT_FLAG_FLOW_OUT);
 
     new_trace_event->set_process_id(2);
     new_trace_event->set_thread_id(3);
-    new_trace_event->set_category_group_name("cat");
-    new_trace_event->set_phase(TRACE_EVENT_PHASE_INSTANT);
+    new_trace_event->set_category_group_name("cat_name");
+    new_trace_event->set_phase(TRACE_EVENT_PHASE_COMPLETE);
     new_trace_event->set_duration(4);
     new_trace_event->set_thread_duration(5);
     new_trace_event->set_thread_timestamp(6);
@@ -167,7 +174,9 @@
     std::string scope;
     scope += TRACE_EVENT_SCOPE_NAME_GLOBAL;
     new_trace_event->set_scope(scope);
+  }
 
+  void FinalizePacket(const perfetto::protos::TracePacket& trace_packet_proto) {
     perfetto::TracePacket trace_packet;
     std::string ser_buf = trace_packet_proto.SerializeAsString();
     trace_packet.AddSlice(&ser_buf[0], ser_buf.size());
@@ -178,39 +187,248 @@
     json_trace_exporter_->OnTraceData(std::move(packets), false);
   }
 
-  void ValidateTestPacket() {
-    EXPECT_EQ(
-        "{\"traceEvents\":[{\"pid\":2,\"tid\":3,\"ts\":42,\"ph\":\"I\",\"cat\":"
-        "\"cat\",\"name\":\"name\",\"dur\":4,\"tdur\":5,\"tts\":6,\"scope\":"
-        "\"g\",\"id2\":{\"global\":\"0x7\"},\"bind_id\":\"0x8\",\"flow_out\":"
-        "true,\"s\":\"g\",\"args\":\"__stripped__\"}]}",
-        last_received_json_);
+  const trace_analyzer::TraceEvent* ValidateAndGetBasicTestPacket() {
+    const trace_analyzer::TraceEvent* trace_event =
+        trace_analyzer_->FindFirstOf(
+            trace_analyzer::Query(trace_analyzer::Query::EVENT_NAME) ==
+            trace_analyzer::Query::String("foo_name"));
+    EXPECT_TRUE(trace_event);
+
+    EXPECT_EQ(2, trace_event->thread.process_id);
+    EXPECT_EQ(3, trace_event->thread.thread_id);
+    EXPECT_EQ(42, trace_event->timestamp);
+    EXPECT_EQ('X', trace_event->phase);
+    EXPECT_EQ("foo_name", trace_event->name);
+    EXPECT_EQ("cat_name", trace_event->category);
+    EXPECT_EQ(4, trace_event->duration);
+    EXPECT_EQ(5, trace_event->thread_duration);
+    EXPECT_EQ(6, trace_event->thread_timestamp);
+    EXPECT_EQ("g", trace_event->scope);
+    EXPECT_EQ("0x7", trace_event->global_id2);
+    EXPECT_EQ("0x8", trace_event->bind_id);
+    EXPECT_TRUE(trace_event->flow_out);
+
+    return trace_event;
   }
 
-  std::unique_ptr<MockService> service_;
+  const trace_analyzer::TraceAnalyzer* trace_analyzer() const {
+    return trace_analyzer_.get();
+  }
+  MockService* service() { return service_.get(); }
 
  private:
+  std::unique_ptr<MockService> service_;
   std::unique_ptr<JSONTraceExporter> json_trace_exporter_;
   std::unique_ptr<base::MessageLoop> message_loop_;
-  std::string last_received_json_;
+  std::unique_ptr<trace_analyzer::TraceAnalyzer> trace_analyzer_;
 };
 
 TEST_F(JSONTraceExporterTest, EnableTracingWithGivenConfig) {
   const char kDummyTraceConfig[] = "trace_all_the_things";
   CreateJSONTraceExporter(kDummyTraceConfig);
-  service_->WaitForTracingEnabled();
-  EXPECT_EQ(kDummyTraceConfig, service_->tracing_enabled_with_config());
+  service()->WaitForTracingEnabled();
+  EXPECT_EQ(kDummyTraceConfig, service()->tracing_enabled_with_config());
 }
 
-TEST_F(JSONTraceExporterTest, TestEvent) {
+TEST_F(JSONTraceExporterTest, TestBasicEvent) {
   CreateJSONTraceExporter("foo");
-  service_->WaitForTracingEnabled();
-
+  service()->WaitForTracingEnabled();
   StopAndFlush();
-  EmitTestPacket();
 
-  service_->WaitForTracingDisabled();
-  ValidateTestPacket();
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  ValidateAndGetBasicTestPacket();
+}
+
+TEST_F(JSONTraceExporterTest, TestEventWithBoolArgs) {
+  CreateJSONTraceExporter("foo");
+  service()->WaitForTracingEnabled();
+  StopAndFlush();
+
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo1");
+    new_arg->set_bool_value(true);
+  }
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo2");
+    new_arg->set_bool_value(false);
+  }
+
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  auto* trace_event = ValidateAndGetBasicTestPacket();
+
+  EXPECT_TRUE(trace_event->GetKnownArgAsBool("foo1"));
+  EXPECT_FALSE(trace_event->GetKnownArgAsBool("foo2"));
+}
+
+TEST_F(JSONTraceExporterTest, TestEventWithUintArgs) {
+  CreateJSONTraceExporter("foo");
+  service()->WaitForTracingEnabled();
+  StopAndFlush();
+
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo1");
+    new_arg->set_uint_value(1);
+  }
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo2");
+    new_arg->set_uint_value(2);
+  }
+
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  auto* trace_event = ValidateAndGetBasicTestPacket();
+
+  EXPECT_EQ(1, trace_event->GetKnownArgAsDouble("foo1"));
+  EXPECT_EQ(2, trace_event->GetKnownArgAsDouble("foo2"));
+}
+
+TEST_F(JSONTraceExporterTest, TestEventWithIntArgs) {
+  CreateJSONTraceExporter("foo");
+  service()->WaitForTracingEnabled();
+  StopAndFlush();
+
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo1");
+    new_arg->set_int_value(1);
+  }
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo2");
+    new_arg->set_int_value(2);
+  }
+
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  auto* trace_event = ValidateAndGetBasicTestPacket();
+
+  EXPECT_EQ(1, trace_event->GetKnownArgAsDouble("foo1"));
+  EXPECT_EQ(2, trace_event->GetKnownArgAsDouble("foo2"));
+}
+
+TEST_F(JSONTraceExporterTest, TestEventWithDoubleArgs) {
+  CreateJSONTraceExporter("foo");
+  service()->WaitForTracingEnabled();
+  StopAndFlush();
+
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo1");
+    new_arg->set_double_value(1.0);
+  }
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo2");
+    new_arg->set_double_value(2.0);
+  }
+
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  auto* trace_event = ValidateAndGetBasicTestPacket();
+
+  EXPECT_EQ(1.0, trace_event->GetKnownArgAsDouble("foo1"));
+  EXPECT_EQ(2.0, trace_event->GetKnownArgAsDouble("foo2"));
+}
+
+TEST_F(JSONTraceExporterTest, TestEventWithStringArgs) {
+  CreateJSONTraceExporter("foo");
+  service()->WaitForTracingEnabled();
+  StopAndFlush();
+
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo1");
+    new_arg->set_string_value("bar1");
+  }
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo2");
+    new_arg->set_string_value("bar2");
+  }
+
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  auto* trace_event = ValidateAndGetBasicTestPacket();
+
+  EXPECT_EQ("bar1", trace_event->GetKnownArgAsString("foo1"));
+  EXPECT_EQ("bar2", trace_event->GetKnownArgAsString("foo2"));
+}
+
+TEST_F(JSONTraceExporterTest, TestEventWithPointerArgs) {
+  CreateJSONTraceExporter("foo");
+  service()->WaitForTracingEnabled();
+  StopAndFlush();
+
+  perfetto::protos::TracePacket trace_packet_proto;
+  auto* new_trace_event =
+      trace_packet_proto.mutable_chrome_events()->add_trace_events();
+  SetTestPacketBasicData(new_trace_event);
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo1");
+    new_arg->set_pointer_value(0x1);
+  }
+
+  {
+    auto* new_arg = new_trace_event->add_args();
+    new_arg->set_name("foo2");
+    new_arg->set_pointer_value(0x2);
+  }
+
+  FinalizePacket(trace_packet_proto);
+
+  service()->WaitForTracingDisabled();
+  auto* trace_event = ValidateAndGetBasicTestPacket();
+
+  EXPECT_EQ("0x1", trace_event->GetKnownArgAsString("foo1"));
+  EXPECT_EQ("0x2", trace_event->GetKnownArgAsString("foo2"));
 }
 
 }  // namespace tracing
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index a1f2ce6..9470d9b 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -76,6 +76,48 @@
 
     char phase = trace_event.phase();
     new_trace_event->set_phase(phase);
+
+    for (int i = 0;
+         i < base::trace_event::kTraceMaxNumArgs && trace_event.arg_name(i);
+         ++i) {
+      // TODO(oysteine): Support ConvertableToTraceFormat serialized into a JSON
+      // string.
+      auto type = trace_event.arg_type(i);
+      if (type == TRACE_VALUE_TYPE_CONVERTABLE) {
+        continue;
+      }
+
+      auto* new_arg = new_trace_event->add_args();
+      new_arg->set_name(trace_event.arg_name(i));
+
+      auto& value = trace_event.arg_value(i);
+      switch (type) {
+        case TRACE_VALUE_TYPE_BOOL:
+          new_arg->set_bool_value(value.as_bool);
+          break;
+        case TRACE_VALUE_TYPE_UINT:
+          new_arg->set_uint_value(value.as_uint);
+          break;
+        case TRACE_VALUE_TYPE_INT:
+          new_arg->set_int_value(value.as_int);
+          break;
+        case TRACE_VALUE_TYPE_DOUBLE:
+          new_arg->set_double_value(value.as_double);
+          break;
+        case TRACE_VALUE_TYPE_POINTER:
+          new_arg->set_pointer_value(static_cast<uint64_t>(
+              reinterpret_cast<uintptr_t>(value.as_pointer)));
+          break;
+        case TRACE_VALUE_TYPE_STRING:
+        case TRACE_VALUE_TYPE_COPY_STRING:
+          new_arg->set_string_value(value.as_string ? value.as_string : "NULL");
+          break;
+        default:
+          NOTREACHED() << "Don't know how to print this value";
+          break;
+      }
+    }
+
     if (phase == TRACE_EVENT_PHASE_COMPLETE) {
       int64_t duration = trace_event.duration().InMicroseconds();
       if (duration != -1) {
@@ -121,6 +163,20 @@
   std::unique_ptr<perfetto::TraceWriter> trace_writer_;
 };
 
+namespace {
+
+base::ThreadLocalStorage::Slot* ThreadLocalEventSinkSlot() {
+  static base::NoDestructor<base::ThreadLocalStorage::Slot>
+      thread_local_event_sink_tls([](void* event_sink) {
+        delete static_cast<TraceEventDataSource::ThreadLocalEventSink*>(
+            event_sink);
+      });
+
+  return thread_local_event_sink_tls.get();
+}
+
+}  // namespace
+
 // static
 TraceEventDataSource* TraceEventDataSource::GetInstance() {
   static base::NoDestructor<TraceEventDataSource> instance;
@@ -186,17 +242,12 @@
 
 // static
 void TraceEventDataSource::OnAddTraceEvent(const TraceEvent& trace_event) {
-  static base::NoDestructor<base::ThreadLocalStorage::Slot>
-      thread_local_event_sink_tls([](void* event_sink) {
-        delete static_cast<ThreadLocalEventSink*>(event_sink);
-      });
-
-  auto* thread_local_event_sink = static_cast<ThreadLocalEventSink*>(
-      thread_local_event_sink_tls.get()->Get());
+  auto* thread_local_event_sink =
+      static_cast<ThreadLocalEventSink*>(ThreadLocalEventSinkSlot()->Get());
 
   if (!thread_local_event_sink) {
     thread_local_event_sink = GetInstance()->CreateThreadLocalEventSink();
-    thread_local_event_sink_tls.get()->Set(thread_local_event_sink);
+    ThreadLocalEventSinkSlot()->Set(thread_local_event_sink);
   }
 
   if (thread_local_event_sink) {
@@ -204,4 +255,14 @@
   }
 }
 
+// static
+void TraceEventDataSource::ResetCurrentThreadForTesting() {
+  ThreadLocalEventSink* thread_local_event_sink =
+      static_cast<ThreadLocalEventSink*>(ThreadLocalEventSinkSlot()->Get());
+  if (thread_local_event_sink) {
+    delete thread_local_event_sink;
+    ThreadLocalEventSinkSlot()->Set(nullptr);
+  }
+}
+
 }  // namespace tracing
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.h b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
index 9871eeb3..4e0741a 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.h
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.h
@@ -27,6 +27,9 @@
 
   static TraceEventDataSource* GetInstance();
 
+  // Deletes the TraceWriter for the current thread, if any.
+  static void ResetCurrentThreadForTesting();
+
   // The ProducerClient is responsible for calling RequestStop
   // which will clear the stored pointer to it, before it
   // gets destroyed. ProducerClient::CreateTraceWriter can be
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
index bb1c99e..02de2dc 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -37,11 +37,14 @@
 
   std::unique_ptr<perfetto::protos::TracePacket> GetPreviousPacket() {
     uint32_t message_size = trace_packet_.Finalize();
+    // GetNewBuffer() in ScatteredStreamWriterNullDelegate doesn't
+    // actually return a new buffer, but rather lets us access the buffer
+    // buffer already used by protozero to write the TracePacket into.
     protozero::ContiguousMemoryRange buffer = delegate_.GetNewBuffer();
     EXPECT_GE(buffer.size(), message_size);
 
     auto proto = std::make_unique<perfetto::protos::TracePacket>();
-    proto->ParseFromArray(buffer.begin, buffer.size());
+    EXPECT_TRUE(proto->ParseFromArray(buffer.begin, message_size));
 
     return proto;
   }
@@ -101,13 +104,19 @@
 
     wait_for_tracelog_flush.Run();
 
+    // As MockTraceWriter keeps a pointer to our MockProducerClient,
+    // we need to make sure to clean it up from TLS. This means
+    // these tests can't use a multithreaded task environment that
+    // might add trace events from other threads, as those might
+    // use old TraceWriters writing into invalid memory.
+    TraceEventDataSource::GetInstance()->ResetCurrentThreadForTesting();
     producer_client_.reset();
     message_loop_.reset();
   }
 
   void CreateTraceEventDataSource() {
     auto data_source_config = mojom::DataSourceConfig::New();
-    TraceEventDataSource::GetInstance()->StartTracing(producer_client_.get(),
+    TraceEventDataSource::GetInstance()->StartTracing(producer_client(),
                                                       *data_source_config);
   }
 
@@ -166,6 +175,107 @@
   EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, trace_event.phase());
 }
 
+TEST_F(TraceEventDataSourceTest, EventWithStringArgs) {
+  CreateTraceEventDataSource();
+
+  TRACE_EVENT_INSTANT2("foo", "bar", TRACE_EVENT_SCOPE_THREAD, "arg1_name",
+                       "arg1_val", "arg2_name", "arg2_val");
+
+  auto trace_events = producer_client()->GetChromeTraceEvents();
+  EXPECT_EQ(trace_events.size(), 1);
+
+  auto trace_args = trace_events[0].args();
+  EXPECT_EQ(trace_args.size(), 2);
+
+  EXPECT_EQ("arg1_name", trace_args[0].name());
+  EXPECT_EQ("arg1_val", trace_args[0].string_value());
+  EXPECT_EQ("arg2_name", trace_args[1].name());
+  EXPECT_EQ("arg2_val", trace_args[1].string_value());
+}
+
+TEST_F(TraceEventDataSourceTest, EventWithUIntArgs) {
+  CreateTraceEventDataSource();
+
+  TRACE_EVENT_INSTANT2("foo", "bar", TRACE_EVENT_SCOPE_THREAD, "foo", 42u,
+                       "bar", 4242u);
+
+  auto trace_events = producer_client()->GetChromeTraceEvents();
+  EXPECT_EQ(trace_events.size(), 1);
+
+  auto trace_args = trace_events[0].args();
+  EXPECT_EQ(trace_args.size(), 2);
+
+  EXPECT_EQ(42u, trace_args[0].uint_value());
+  EXPECT_EQ(4242u, trace_args[1].uint_value());
+}
+
+TEST_F(TraceEventDataSourceTest, EventWithIntArgs) {
+  CreateTraceEventDataSource();
+
+  TRACE_EVENT_INSTANT2("foo", "bar", TRACE_EVENT_SCOPE_THREAD, "foo", 42, "bar",
+                       4242);
+
+  auto trace_events = producer_client()->GetChromeTraceEvents();
+  EXPECT_EQ(trace_events.size(), 1);
+
+  auto trace_args = trace_events[0].args();
+  EXPECT_EQ(trace_args.size(), 2);
+
+  EXPECT_EQ(42, trace_args[0].int_value());
+  EXPECT_EQ(4242, trace_args[1].int_value());
+}
+
+TEST_F(TraceEventDataSourceTest, EventWithBoolArgs) {
+  CreateTraceEventDataSource();
+
+  TRACE_EVENT_INSTANT2("foo", "bar", TRACE_EVENT_SCOPE_THREAD, "foo", true,
+                       "bar", false);
+
+  auto trace_events = producer_client()->GetChromeTraceEvents();
+  EXPECT_EQ(trace_events.size(), 1);
+
+  auto trace_args = trace_events[0].args();
+  EXPECT_EQ(trace_args.size(), 2);
+
+  EXPECT_TRUE(trace_args[0].has_bool_value());
+  EXPECT_EQ(true, trace_args[0].bool_value());
+  EXPECT_TRUE(trace_args[1].has_bool_value());
+  EXPECT_EQ(false, trace_args[1].bool_value());
+}
+
+TEST_F(TraceEventDataSourceTest, EventWithDoubleArgs) {
+  CreateTraceEventDataSource();
+
+  TRACE_EVENT_INSTANT2("foo", "bar", TRACE_EVENT_SCOPE_THREAD, "foo", 42.42,
+                       "bar", 4242.42);
+
+  auto trace_events = producer_client()->GetChromeTraceEvents();
+  EXPECT_EQ(trace_events.size(), 1);
+
+  auto trace_args = trace_events[0].args();
+  EXPECT_EQ(trace_args.size(), 2);
+
+  EXPECT_EQ(42.42, trace_args[0].double_value());
+  EXPECT_EQ(4242.42, trace_args[1].double_value());
+}
+
+TEST_F(TraceEventDataSourceTest, EventWithPointerArgs) {
+  CreateTraceEventDataSource();
+
+  TRACE_EVENT_INSTANT2("foo", "bar", TRACE_EVENT_SCOPE_THREAD, "foo",
+                       reinterpret_cast<void*>(0xBEEF), "bar",
+                       reinterpret_cast<void*>(0xF00D));
+
+  auto trace_events = producer_client()->GetChromeTraceEvents();
+  EXPECT_EQ(trace_events.size(), 1);
+
+  auto trace_args = trace_events[0].args();
+  EXPECT_EQ(trace_args.size(), 2);
+
+  EXPECT_EQ(static_cast<uintptr_t>(0xBEEF), trace_args[0].pointer_value());
+  EXPECT_EQ(static_cast<uintptr_t>(0xF00D), trace_args[1].pointer_value());
+}
+
 }  // namespace
 
 }  // namespace tracing
diff --git a/testing/buildbot/filters/fuchsia.net_unittests.filter b/testing/buildbot/filters/fuchsia.net_unittests.filter
index 433c7bd..47c72ba 100644
--- a/testing/buildbot/filters/fuchsia.net_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.net_unittests.filter
@@ -1,9 +1,5 @@
 # TODO(fuchsia): Fix these tests and remove the filter. https://crbug.com/731302 .
 
-# Timeout on the bots exceeding 45s on the bots (apperently due to slow IO).
--DiskCacheTest.BlockFiles_Grow
--DiskCacheBackendTest.SimpleCacheDeleteQuickly
-
 # Exceeds FD limit, ZX-1127.
 -PacFileFetcherImplTest.Priority
 
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 76dadf2..2fdaeb4 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -33,16 +33,16 @@
 crbug.com/636993 external/wpt/fullscreen/api/element-ready-check-not-allowed-cross-origin-manual.sub.html [ Crash ]
 crbug.com/636993 fast/block/child-not-removed-from-parent-lineboxes-crash.html [ Crash ]
 crbug.com/636993 fast/block/float/add-float-back-to-anonymous-block-previous.html [ Crash ]
+crbug.com/636993 fast/css-generated-content/dynamic-apply-after-for-inline.html [ Crash ]
 crbug.com/636993 fast/css/css-property-setter-getter.html [ Crash ]
 crbug.com/636993 fast/css/first-letter-removed-added.html [ Crash ]
-crbug.com/636993 fast/css/relative-position-replaced-in-table-display-crash.html [ Crash ]
 crbug.com/591099 fast/css/getComputedStyle/getComputedStyle-resolved-values.html [ Timeout Crash ]
-crbug.com/636993 fast/css-generated-content/dynamic-apply-after-for-inline.html [ Crash ]
+crbug.com/636993 fast/css/relative-position-replaced-in-table-display-crash.html [ Crash ]
+crbug.com/636993 fast/dynamic/unicode-bidi.html [ Failure ]
 crbug.com/594672 fast/events/updateLayoutForHitTest.html [ Pass Failure Crash ]
 crbug.com/636993 fast/inline/inline-empty-block-continuation-remove.html [ Crash ]
 crbug.com/636993 fast/overflow/scroll-div-hide-show.html [ Crash ]
 crbug.com/594672 virtual/mouseevent_fractional/fast/events/updateLayoutForHitTest.html [ Pass Failure Crash ]
-crbug.com/636993 fast/dynamic/unicode-bidi.html [ Failure ]
 
 # New passes
 crbug.com/626703 external/wpt/css/css-ui/text-overflow-021.html [ Failure ]
@@ -77,7 +77,7 @@
 crbug.com/714962 accessibility/background-color.html [ Failure ]
 crbug.com/714962 accessibility/bounds-calc.html [ Failure ]
 crbug.com/591099 accessibility/canvas-fallback-content-2.html [ Timeout ]
-crbug.com/591099 accessibility/computed-name.html [ Timeout ]
+crbug.com/591099 accessibility/computed-name.html [ Pass Timeout ]
 crbug.com/591099 accessibility/computed-role.html [ Pass Timeout ]
 crbug.com/714962 accessibility/css-first-letter-children.html [ Failure ]
 crbug.com/591099 accessibility/css-generated-content.html [ Failure ]
@@ -118,11 +118,11 @@
 crbug.com/591099 animations/animation-ready-reject-script-forbidden.html [ Timeout ]
 crbug.com/591099 animations/cross-fade-list-style-image.html [ Failure ]
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Timeout ]
-crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Pass Timeout ]
+crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/svg-stroke-dasharray-interpolation.html [ Timeout ]
 crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Pass Timeout ]
 crbug.com/591099 animations/rotate-transform-equivalent.html [ Failure ]
-crbug.com/591099 animations/timing/timing-model.html [ Timeout ]
+crbug.com/591099 animations/timing/timing-model.html [ Pass Timeout ]
 crbug.com/714962 compositing/background-color/view-blending-base-background.html [ Failure ]
 crbug.com/591099 compositing/draws-content/canvas-background-layer.html [ Failure ]
 crbug.com/591099 compositing/draws-content/webgl-background-layer.html [ Failure ]
@@ -230,22 +230,22 @@
 crbug.com/591099 editing/selection/shift-click.html [ Failure ]
 crbug.com/591099 editing/selection/skip-over-contenteditable.html [ Failure ]
 crbug.com/591099 editing/selection/transformed-selection-rects.html [ Failure ]
-crbug.com/591099 editing/text-iterator/findString.html [ Timeout ]
+crbug.com/591099 editing/text-iterator/findString.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Pass ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/hkdf.https.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-KW.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDH.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDSA.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_HMAC.worker.html [ Timeout ]
-crbug.com/714962 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html [ Timeout ]
+crbug.com/714962 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html [ Timeout ]
@@ -256,14 +256,10 @@
 crbug.com/714962 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/acid/acid3/numbered-tests.html [ Crash ]
 crbug.com/591099 external/wpt/acid/acid3/test.html [ Crash ]
-crbug.com/591099 external/wpt/content-security-policy/inside-worker/dedicated-inheritance.html [ Failure Pass ]
-crbug.com/591099 external/wpt/content-security-policy/reporting/report-original-url.sub.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-image-from-script.sub.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Pass ]
 crbug.com/591099 external/wpt/credential-management/passwordcredential-framed-get.sub.https.html [ Pass ]
-crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-top-below-inline-001r.xht [ Failure Pass ]
 crbug.com/635619 external/wpt/css/CSS2/floats/floats-in-table-caption-001.html [ Failure ]
-crbug.com/714962 external/wpt/css/CSS2/linebox/vertical-align-baseline-005a.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/CSS2/linebox/vertical-align-baseline-005a.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001e.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001h.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-002e.xht [ Pass ]
@@ -275,23 +271,15 @@
 crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-color-5.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-image-5.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-backgrounds/box-shadow-syntax-001.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-color/t425-hsla-onscreen-multiple-boxes-c.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-contain/quote-scoping-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-details.html [ Crash ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-inline.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-list-001-none.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-dynamic-table-001-inline.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display/display-contents-list-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-fill-stroke/paint-order-001.tentative.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-flexbox/flex-minimum-width-flex-items-008.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/percentage-heights-003.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-05.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-06.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-16.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/font-variant-ligatures-11.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/fixed-stretch-style-over-weight.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-fonts/matching/stretch-distance-over-weight-distance.html [ Pass ]
@@ -306,17 +294,7 @@
 crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-layout-api/constraints-fixed-inline-size-absolute-left-right.https.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-layout-api/style-map.https.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-multicol/multicol-count-computed-003.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-004.xht [ Pass ]
-crbug.com/591099 external/wpt/css/css-overflow/logical-overflow-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-paint-api/geometry-border-image-001.https.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-paint-api/paint-function-arguments.https.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-paint-api/parse-input-arguments-003.https.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-position/position-relative-table-tr-top-absolute-child.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-position/position-sticky-writing-modes.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-pseudo/first-letter-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-rhythm/ [ Skip ]
 crbug.com/591099 external/wpt/css/css-scroll-anchoring/clipped-scrollers-skipped.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-scroll-anchoring/opt-out.html [ Failure ]
@@ -326,13 +304,13 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-004.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-006.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-006.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-007.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-box/shape-outside-box-008.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-002.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-003.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-004.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-radial-gradient-003.html [ Failure ]
@@ -379,7 +357,7 @@
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-030.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/circle/shape-outside-circle-031.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-013.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-014.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-014.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-016.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/ellipse/shape-outside-ellipse-017.html [ Failure ]
@@ -419,10 +397,10 @@
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-003.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-004.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-005.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-006.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-007.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-007.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-008.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-010.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/spec-examples/shape-outside-011.html [ Failure ]
@@ -437,14 +415,12 @@
 crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/height-distribution/percentage-sizing-of-table-cell-children.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-tables/height-distribution/td-different-subpixel-padding-in-same-row.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-tables/table-model-fixup-2.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-tables/width-distribution/td-with-subpixel-padding-vertical-rl.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-text-decor/text-decoration-serialization.tentative.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-color-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-left-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-right-001.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-right-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-right-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-left-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-below-left-002.xht [ Failure ]
@@ -460,7 +436,7 @@
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-filled-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-open-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-shape-001.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-string-001.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-string-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/i18n/css3-text-line-break-jazh-136.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/i18n/css3-text-line-break-jazh-142.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-255.html [ Pass ]
@@ -484,22 +460,10 @@
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-006.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-transforms/transform-abspos-007.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-transforms/transform-generated-002.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-transforms/transform-origin-name-002.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-transforms/transform-transformed-tr-percent-height-child.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-transforms/transform3d-perspective-008.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-transforms/transform3d-rotatex-transformorigin-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-transforms/transform3d-scale-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-transitions/before-load-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-transitions/transition-timing-function-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/line-break.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-decoration-line.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-typed-om/the-stylepropertymap/properties/text-transform.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-ui/box-sizing-018.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-015.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-ui/text-overflow-023.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-variables/variable-definition.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-003.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-005.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-011.xht [ Pass ]
@@ -580,9 +544,8 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-010.html [ Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes/available-size-011.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/available-size-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-012.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/available-size-015.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-017.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-018.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/baseline-inline-non-replaced-004.xht [ Failure ]
@@ -594,7 +557,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-006.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-008.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/float-contiguous-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vlr-013.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/float-vrl-004.xht [ Failure ]
@@ -634,18 +597,18 @@
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-020.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-021.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-023.xht [ Failure ]
-crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht [ Failure Pass ]
+crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vrl-024.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-003.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-004.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-007.xht [ Failure ]
 crbug.com/714962 external/wpt/css/css-writing-modes/sizing-orthog-prct-htb-in-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-013.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vlr-007.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vlr-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-baseline-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-combine-upright-decorations-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-combine-upright-layout-rules-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/text-orientation-016.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-005.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-005.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vlr-023.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-vlr-025.xht [ Failure ]
@@ -656,19 +619,14 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/wm-propagation-body-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/cssom-view/elementFromPoint-003.html [ Failure ]
-crbug.com/591099 external/wpt/css/cssom/getComputedStyle-detached-subtree.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/cssom/interfaces.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass ]
 crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Pass ]
-crbug.com/591099 external/wpt/css/selectors/selection-image-001.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/descriptor-pad-invalid.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/name-case-sensitivity.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-definite-sizes-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-006v.html [ Pass ]
 crbug.com/714962 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-items-as-stacking-contexts-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-012.html [ Failure ]
@@ -677,10 +635,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/remove-from-split-inline-6.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/split-inner-inline-2.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-004.html [ Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-006a.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-007.html [ Failure ]
-crbug.com/591099 external/wpt/dom/events/Event-returnValue.html [ Failure Pass ]
 crbug.com/591099 external/wpt/dom/nodes/Element-classlist.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Element-matches.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Element-webkitMatchesSelector.html [ Timeout ]
@@ -696,7 +651,6 @@
 crbug.com/591099 external/wpt/dom/ranges/Range-mutations-dataChange.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-set.html [ Timeout ]
 crbug.com/591099 external/wpt/dom/ranges/Range-surroundContents.html [ Timeout ]
-crbug.com/591099 external/wpt/domxpath/002.html [ Failure Pass ]
 crbug.com/591099 external/wpt/domxpath/xml_xpath_runner.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/backcolor.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/bold.html [ Timeout ]
@@ -706,8 +660,8 @@
 crbug.com/591099 external/wpt/editing/run/formatblock.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/forwarddelete.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/hilitecolor.html [ Timeout ]
-crbug.com/591099 external/wpt/editing/run/indent.html [ Failure Timeout ]
-crbug.com/591099 external/wpt/editing/run/inserthorizontalrule.html [ Timeout ]
+crbug.com/591099 external/wpt/editing/run/indent.html [ Timeout ]
+crbug.com/591099 external/wpt/editing/run/inserthorizontalrule.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/editing/run/inserthtml.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/insertlinebreak.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/insertorderedlist.html [ Timeout ]
@@ -725,7 +679,7 @@
 crbug.com/591099 external/wpt/editing/run/strikethrough.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/subscript.html [ Timeout ]
 crbug.com/591099 external/wpt/editing/run/superscript.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/editing/run/underline.html [ Failure Timeout ]
+crbug.com/591099 external/wpt/editing/run/underline.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/api-invalid-label.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-japanese/euc-jp/eucjp-decode-cseucpkdfmtjapanese.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-japanese/euc-jp/eucjp-decode-x-euc-jp.html [ Timeout ]
@@ -819,16 +773,10 @@
 crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href-errors-misc.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ]
-crbug.com/591099 external/wpt/fetch/api/idl.any.html [ Failure Pass ]
-crbug.com/591099 external/wpt/fetch/http-cache/heuristic.html [ Failure Pass ]
 crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 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 ]
-crbug.com/591099 external/wpt/html/browsers/history/the-location-interface/location-stringifier.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_setter.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/browsers/the-window-object/accessing-other-browsing-contexts/indexed-browsing-contexts-03.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/browsers/windows/browsing-context.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/browsers/windows/noreferrer-window-name.html [ Timeout ]
 crbug.com/591099 external/wpt/html/dom/documents/dom-tree-accessors/Document.currentScript.html [ Pass ]
 crbug.com/591099 external/wpt/html/dom/elements/the-innertext-idl-attribute/getter.html [ Failure ]
@@ -841,45 +789,25 @@
 crbug.com/591099 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/windows-1252.html [ Timeout ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/flow-content-0/dialog.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-fieldset-element-0/legend-block-formatting-context.html [ Failure ]
-crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2k.html [ Pass ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html [ Timeout ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/src.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-pointer-control.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-webvtt-non-snap-to-lines.html [ Failure ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/the-img-element/current-pixel-density/basic.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/embedded-content/the-object-element/object-in-object-fallback-2.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/forms/autofocus/first-when-later-but-before.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/forms/the-input-element/image-click-form-data.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/forms/the-label-element/label-attributes.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/forms/the-textarea-element/value-defaultValue-textContent.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-menu.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-list-owner-skip-no-boxes.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/interactive-elements/the-dialog-element/abspos-dialog-layout.html [ Failure ]
 crbug.com/591099 external/wpt/html/semantics/interactive-elements/the-dialog-element/centering.html [ Crash ]
-crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/084.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/semantics/scripting-1/the-template-element/template-element/template-descendant-frameset.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/syntax/parsing/html5lib_innerHTML_foreign-fragment.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/syntax/parsing/html5lib_tests11.html?run_type=write_single [ Failure Pass ]
 crbug.com/591099 external/wpt/html/syntax/parsing/named-character-references.html [ Timeout ]
 crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-1.htm [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-4.htm [ Pass Timeout ]
 crbug.com/591099 external/wpt/html/the-xhtml-syntax/parsing-xhtml-documents/xhtml-mathml-dtd-entity-7.htm [ Pass Timeout ]
-crbug.com/591099 external/wpt/html/webappapis/scripting/processing-model-2/compile-error-same-origin-with-hash.html [ Failure Pass ]
 crbug.com/591099 external/wpt/http/basic-auth-cache-test.html [ Timeout ]
-crbug.com/591099 external/wpt/infrastructure/reftest/reftest_timeout.html [ Pass ]
-crbug.com/591099 external/wpt/infrastructure/testdriver/send_keys.html [ Failure Pass ]
 crbug.com/591099 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Timeout ]
-crbug.com/591099 external/wpt/mediacapture-streams/MediaDevices-IDL-all.html [ Failure Pass ]
 crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.html [ Timeout ]
 crbug.com/591099 external/wpt/mimesniff/mime-types/parsing.any.worker.html [ Timeout ]
-crbug.com/591099 external/wpt/mixed-content/video-tag/no-opt-in/same-host-http/top-level/no-redirect/optionally-blockable/no-opt-in-allows.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ]
 crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.getcontext.worker.html [ Pass ]
-crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/offscreencanvas.resize.html [ Failure Pass ]
-crbug.com/591099 external/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.trailingjunk.html [ Failure Pass ]
 crbug.com/591099 external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
 crbug.com/591099 external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html [ Pass ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html [ Timeout ]
@@ -895,8 +823,6 @@
 crbug.com/591099 external/wpt/requestidlecallback/callback-invoked.html [ Pass ]
 crbug.com/591099 external/wpt/requestidlecallback/cancel-invoked.html [ Pass ]
 crbug.com/591099 external/wpt/requestidlecallback/idlharness.html [ Pass ]
-crbug.com/591099 external/wpt/screen-orientation/orientation-reading.html [ Failure Pass ]
-crbug.com/591099 external/wpt/secure-contexts/basic-dedicated-worker.html [ Failure Pass ]
 crbug.com/591099 external/wpt/selection/addRange-00.html [ Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-04.html [ Timeout ]
 crbug.com/591099 external/wpt/selection/addRange-12.html [ Pass Timeout ]
@@ -914,69 +840,39 @@
 crbug.com/591099 external/wpt/selection/selectAllChildren.html [ Timeout ]
 crbug.com/591099 external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ]
-crbug.com/591099 external/wpt/speech-api/SpeechSynthesis-speak-ownership.html [ Failure Pass ]
-crbug.com/591099 external/wpt/streams/readable-byte-streams/properties.dedicatedworker.html [ Failure Pass ]
-crbug.com/591099 external/wpt/streams/readable-byte-streams/properties.html [ Failure Pass ]
-crbug.com/591099 external/wpt/streams/transform-streams/properties.dedicatedworker.html [ Failure Pass ]
 crbug.com/591099 external/wpt/svg/interfaces.html [ Timeout ]
 crbug.com/591099 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ]
-crbug.com/591099 external/wpt/url/a-element-xhtml.xhtml [ Failure Pass ]
-crbug.com/591099 external/wpt/url/interfaces.any.html [ Failure Pass ]
 crbug.com/591099 external/wpt/url/url-setters.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/wasm/wasm_local_iframe_test.html [ Failure ]
-crbug.com/591099 external/wpt/web-animations/animation-model/animation-types/addition-per-property.html [ Failure Pass ]
 crbug.com/591099 external/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html [ Timeout ]
-crbug.com/591099 external/wpt/web-animations/timing-model/animations/setting-the-timeline-of-an-animation.html [ Failure Pass ]
 crbug.com/591099 external/wpt/webaudio/idlharness.https.html [ Timeout ]
 crbug.com/591099 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Failure ]
-crbug.com/591099 external/wpt/webrtc/RTCConfiguration-iceCandidatePoolSize.html [ Failure Pass ]
-crbug.com/591099 external/wpt/webrtc/RTCPeerConnectionIceEvent-constructor.html [ Failure Pass ]
-crbug.com/591099 external/wpt/webrtc/RTCRtpParameters-encodings.html [ Failure Pass ]
 crbug.com/591099 external/wpt/webrtc/interfaces.html [ Pass Timeout ]
-crbug.com/591099 external/wpt/websockets/unload-a-document/004.html [ Failure Pass ]
+crbug.com/591099 external/wpt/websockets/constructor/014.html?wss [ Pass Timeout ]
+crbug.com/591099 external/wpt/websockets/keeping-connection-open/001.html?wss [ Pass Timeout ]
 crbug.com/591099 external/wpt/webstorage/storage_setitem.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webvr/idlharness.https.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_up.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/align_end.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/align_middle_position_gt_50.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/bidi_ruby.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/dom_override_cue_text_while_paused.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/9_cues_overlapping_completely_all_cues_have_same_timestamp.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/background_shorthand_css_relative_url.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/inherit_values_from_media_element.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_properties.html [ Failure Pass ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_namespace.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_text-shadow.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_white-space_pre-line_wrapped.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_with_class_object_specific_selector.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_white-space_pre_wrapped.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/color_hsla.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/inherit_values_from_media_element.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_transition_with_timestamp.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_color.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_outline_shorthand.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_with_class_object_specific_selector.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_properties.html [ Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_shorthand.html [ Failure ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_namespace.html [ Pass ]
-crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/size_50.html [ Pass ]
 crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Timeout ]
-crbug.com/591099 external/wpt/workers/interfaces.worker.html [ Failure Pass ]
 crbug.com/591099 external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ]
-crbug.com/591099 external/wpt/xhr/send-response-event-order.htm [ Failure Pass ]
 crbug.com/591099 fast/backgrounds/background-clip-text.html [ Failure ]
 crbug.com/591099 fast/backgrounds/background-leakage-transforms.html [ Failure ]
 crbug.com/591099 fast/backgrounds/border-radius-split-background-image.html [ Failure ]
@@ -1042,7 +938,7 @@
 crbug.com/591099 fast/css-grid-layout/flex-and-minmax-content-resolution-columns.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-align-baseline-vertical.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/grid-baseline-margins.html [ Pass ]
-crbug.com/591099 fast/css-grid-layout/grid-columns-rows-get-set-multiple.html [ Timeout ]
+crbug.com/591099 fast/css-grid-layout/grid-columns-rows-get-set-multiple.html [ Pass Timeout ]
 crbug.com/591099 fast/css-grid-layout/grid-columns-rows-get-set.html [ Timeout ]
 crbug.com/591099 fast/css-grid-layout/grid-item-column-row-get-set.html [ Pass Timeout ]
 crbug.com/591099 fast/css-grid-layout/grid-item-overflow.html [ Failure ]
@@ -1113,7 +1009,7 @@
 crbug.com/591099 fast/css/getComputedStyle/getComputedStyle-margin-percentage.html [ Failure ]
 crbug.com/714962 fast/css/hover-pseudo-element-quirks.html [ Failure ]
 crbug.com/591099 fast/css/import_with_baseurl.html [ Failure Pass ]
-crbug.com/591099 fast/css/large-numbers.html [ Timeout ]
+crbug.com/591099 fast/css/large-numbers.html [ Pass Timeout ]
 crbug.com/591099 fast/css/margin-top-bottom-dynamic.html [ Failure ]
 crbug.com/591099 fast/css/negative-text-indent-in-inline-block.html [ Failure ]
 crbug.com/591099 fast/css/outline-narrowLine.html [ Failure ]
@@ -1152,7 +1048,7 @@
 crbug.com/591099 fast/dom/HTMLAreaElement/area-download.html [ Failure ]
 crbug.com/591099 fast/dom/MutationObserver/observe-attributes.html [ Pass Timeout ]
 crbug.com/714962 fast/dom/Range/getBoundingClientRect-linebreak-character.html [ Failure ]
-crbug.com/591099 fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html [ Timeout ]
+crbug.com/591099 fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html [ Pass Timeout ]
 crbug.com/591099 fast/dom/Window/window-lookup-precedence.html [ Timeout ]
 crbug.com/591099 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ]
 crbug.com/591099 fast/dom/domstring-attribute-reflection.html [ Timeout ]
@@ -1181,16 +1077,16 @@
 crbug.com/591099 fast/events/keyboardevent-getModifierState.html [ Timeout ]
 crbug.com/714962 fast/events/middleClickAutoscroll-latching.html [ Pass Timeout ]
 crbug.com/714962 fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure Pass ]
-crbug.com/591099 fast/events/mouse-event-buttons-attribute.html [ Timeout ]
+crbug.com/591099 fast/events/mouse-event-buttons-attribute.html [ Pass Timeout ]
 crbug.com/591099 fast/events/mouse-relative-position.html [ Failure ]
 crbug.com/591099 fast/events/mouseevent-getModifierState.html [ Timeout ]
 crbug.com/591099 fast/events/onclick-list-marker.html [ Failure ]
 crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Timeout ]
-crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture.html [ Timeout ]
+crbug.com/591099 fast/events/pointerevents/mouse-pointer-capture.html [ Pass Timeout ]
 crbug.com/591099 fast/events/pointerevents/mouse-pointer-event-properties.html [ Timeout ]
-crbug.com/591099 fast/events/pointerevents/mouse-pointer-preventdefault.html [ Timeout ]
+crbug.com/591099 fast/events/pointerevents/mouse-pointer-preventdefault.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/events/pointerevents/multi-pointer-preventdefault.html [ Pass Timeout ]
-crbug.com/591099 fast/events/pointerevents/touch-capture-in-iframe.html [ Timeout ]
+crbug.com/591099 fast/events/pointerevents/touch-capture-in-iframe.html [ Pass Timeout ]
 crbug.com/591099 fast/events/pointerevents/touch-capture.html [ Timeout ]
 crbug.com/591099 fast/events/select-element.html [ Timeout ]
 crbug.com/591099 fast/events/sequential-focus-navigation-starting-point.html [ Failure ]
@@ -1199,9 +1095,9 @@
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/591099 fast/forms/calendar-picker/calendar-picker-key-operations.html [ Pass Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/calendar-picker-mouse-operations.html [ Failure ]
-crbug.com/591099 fast/forms/calendar-picker/month-picker-key-operations.html [ Timeout ]
+crbug.com/591099 fast/forms/calendar-picker/month-picker-key-operations.html [ Pass Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/month-picker-mouse-operations.html [ Failure ]
-crbug.com/591099 fast/forms/calendar-picker/week-picker-key-operations.html [ Timeout ]
+crbug.com/591099 fast/forms/calendar-picker/week-picker-key-operations.html [ Pass Timeout ]
 crbug.com/714962 fast/forms/calendar-picker/week-picker-mouse-operations.html [ Failure ]
 crbug.com/591099 fast/forms/control-clip-overflow.html [ Failure ]
 crbug.com/591099 fast/forms/fieldset/fieldset-with-float.html [ Failure ]
@@ -1521,7 +1417,7 @@
 crbug.com/591099 fast/text/emphasis-complex.html [ Failure ]
 crbug.com/591099 fast/text/emphasis-ellipsis-complextext.html [ Failure ]
 crbug.com/591099 fast/text/emphasis-overlap.html [ Failure ]
-crbug.com/591099 fast/text/find-kana.html [ Timeout ]
+crbug.com/591099 fast/text/find-kana.html [ Pass Timeout ]
 crbug.com/591099 fast/text/hide-atomic-inlines-after-ellipsis.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-linebreak-002.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-linebreak-003.html [ Failure ]
@@ -1638,7 +1534,7 @@
 crbug.com/591099 http/tests/devtools/editor/text-editor-word-jumps.js [ Pass ]
 crbug.com/714962 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Crash ]
 crbug.com/591099 http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure ]
+crbug.com/591099 http/tests/devtools/elements/elements-panel-rewrite-href.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside-scroll.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-shapes-outside.js [ Failure ]
 crbug.com/714962 http/tests/devtools/elements/inspect-pseudo-element.js [ Timeout ]
@@ -1658,7 +1554,7 @@
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
 crbug.com/783102 http/tests/incremental/frame-focus-before-load.html [ Timeout ]
 crbug.com/591099 http/tests/incremental/slow-utf8-text.pl [ Pass Timeout ]
-crbug.com/591099 http/tests/inspector-protocol/side-effects/evaluate-embedder-side-effect-free-attributes.js [ Timeout ]
+crbug.com/591099 http/tests/inspector-protocol/side-effects/evaluate-embedder-side-effect-free-attributes.js [ Pass Timeout ]
 crbug.com/591099 http/tests/loading/nested_bad_objects.php [ Failure ]
 crbug.com/591099 http/tests/loading/preload-picture-nested.html [ Failure ]
 crbug.com/591099 http/tests/loading/preload-picture-sizes-2x.html [ Failure ]
@@ -1693,11 +1589,11 @@
 crbug.com/591099 inspector-protocol/accessibility/accessibility-ignoredNodes.js [ Failure Timeout ]
 crbug.com/714962 inspector-protocol/accessibility/accessibility-ignoredNodesModal.js [ Failure ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-img-figure.js [ Pass Timeout ]
-crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js [ Timeout ]
+crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input-buttons.js [ Pass Timeout ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-input.js [ Timeout Failure ]
 crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Timeout Failure ]
-crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-visiblity.js [ Timeout ]
-crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Timeout ]
+crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-visiblity.js [ Pass Timeout ]
+crbug.com/591099 inspector-protocol/css/css-add-rule.js [ Pass Timeout ]
 crbug.com/714962 inspector-protocol/css/css-get-platform-fonts.js [ Failure ]
 crbug.com/591099 inspector-protocol/css/css-set-style-text.js [ Pass Timeout ]
 crbug.com/714962 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-viewport.js [ Failure ]
@@ -1708,6 +1604,7 @@
 crbug.com/714962 intersection-observer/text-target.html [ Failure ]
 crbug.com/591099 media/audio-controls-rendering.html [ Failure ]
 crbug.com/591099 media/autoplay/document-user-activation.html [ Failure ]
+crbug.com/591099 media/controls/modern/tap-to-hide-controls.html [ Failure ]
 crbug.com/591099 media/media-document-audio-repaint.html [ Failure ]
 crbug.com/591099 media/video-aspect-ratio.html [ Failure ]
 crbug.com/591099 media/video-colorspace-yuv420.html [ Failure ]
@@ -1898,6 +1795,7 @@
 crbug.com/591099 paint/invalidation/table/composited-table-background-initial-empty.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/composited-table-row.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/repaint-table-row-in-composited-document.html [ Failure ]
+crbug.com/591099 paint/invalidation/table/replace-col.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/resize-table-row-repaint.html [ Failure ]
@@ -1967,13 +1865,13 @@
 crbug.com/591099 printing/webgl-repeated-printing.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
 crbug.com/591099 scrollbars/scrollbar-miss-mousemove-disabled.html [ Failure ]
-crbug.com/591099 shadow-dom/focus-navigation-with-delegatesFocus.html [ Timeout ]
+crbug.com/591099 shadow-dom/focus-navigation-with-delegatesFocus.html [ Pass Timeout ]
 crbug.com/591099 shapedetection/detection-HTMLVideoElement.html [ Pass ]
 crbug.com/591099 storage/indexeddb/cursor-advance.html [ Pass Timeout ]
 crbug.com/591099 storage/indexeddb/cursor-continue-validity.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/cursor-key-order.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/cursor-update.html [ Pass Timeout ]
-crbug.com/591099 storage/indexeddb/deleted-objects.html [ Timeout ]
+crbug.com/591099 storage/indexeddb/deleted-objects.html [ Pass Timeout ]
 crbug.com/591099 storage/indexeddb/exceptions.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/index-cursor.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/keypath-basics.html [ Pass Timeout ]
@@ -1982,7 +1880,7 @@
 crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Timeout ]
-crbug.com/591099 storage/indexeddb/structured-clone.html [ Timeout ]
+crbug.com/591099 storage/indexeddb/structured-clone.html [ Pass Timeout ]
 crbug.com/714962 svg/as-background-image/svg-as-background-body.html [ Failure ]
 crbug.com/591099 svg/as-border-image/svg-as-border-image-2.html [ Failure ]
 crbug.com/591099 svg/as-border-image/svg-as-border-image.html [ Failure ]
@@ -2074,30 +1972,29 @@
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Pass ]
 crbug.com/591099 virtual/incremental-shadow-dom/external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html [ Failure ]
 crbug.com/714962 virtual/incremental-shadow-dom/fast/dom/shadow/scrollbar.html [ Crash ]
-crbug.com/591099 virtual/incremental-shadow-dom/fast/dom/shadow/selections-in-shadow.html [ Timeout ]
+crbug.com/591099 virtual/incremental-shadow-dom/fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ]
 crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode-align-center.html [ Failure ]
 crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode-align-left.html [ Failure ]
 crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode-align-right.html [ Failure ]
 crbug.com/591099 virtual/incremental-shadow-dom/html/details_summary/details-writing-mode.html [ Failure ]
-crbug.com/714962 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-with-delegatesFocus.html [ Timeout ]
+crbug.com/714962 virtual/incremental-shadow-dom/shadow-dom/focus-navigation-with-delegatesFocus.html [ Pass Timeout ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
 crbug.com/836297 virtual/layout_ng_experimental/printing/webgl-oversized-printing.html [ Pass Timeout ]
-crbug.com/591099 media/controls/modern/tap-to-hide-controls.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/drag-in-frames.html [ Failure ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/event-on-culled_inline.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/hr-timestamp/input-events.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/keyboardevent-getModifierState.html [ Timeout ]
 crbug.com/714962 virtual/mouseevent_fractional/fast/events/mouse-down-on-pseudo-element-remove-crash.html [ Failure ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouse-event-buttons-attribute.html [ Timeout ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouse-event-buttons-attribute.html [ Pass Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouse-relative-position.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouseevent-getModifierState.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onclick-list-marker.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture-transition-events.html [ Timeout ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture.html [ Timeout ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-preventdefault.html [ Timeout ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-capture.html [ Pass Timeout ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/mouse-pointer-preventdefault.html [ Pass Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/multi-pointer-preventdefault.html [ Pass Timeout ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture-in-iframe.html [ Timeout ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture-in-iframe.html [ Pass Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/pointerevents/touch-capture.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/select-element.html [ Timeout ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/sequential-focus-navigation-starting-point.html [ Failure ]
@@ -2105,6 +2002,8 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
+crbug.com/591099 virtual/off-main-thread-websocket/external/wpt/websockets/constructor/014.html?wss [ Pass Timeout ]
+crbug.com/591099 virtual/off-main-thread-websocket/external/wpt/websockets/keeping-connection-open/001.html?wss [ Pass Timeout ]
 crbug.com/591099 virtual/off-main-thread-websocket/http/tests/websocket/invalid-subprotocol-characters.html [ Timeout ]
 crbug.com/591099 virtual/outofblink-cors/ [ Skip ]
 crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/sibling-painting-first-image.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 95f2bc7..6486146 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -41,9 +41,7 @@
 
 # Cross-Origin Read Blocking is not implemented.
 crbug.com/792546 http/tests/inspector-protocol/network/block_cross_site_document_load.js [ Failure ]
-crbug.com/792546 external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html [ Failure ]

-crbug.com/792546 external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html [ Failure ]

-crbug.com/792546 external/wpt/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html [ Failure ]

+crbug.com/792546 external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html [ Failure ]
+crbug.com/792546 external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html [ Failure ]
+crbug.com/792546 external/wpt/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html [ Failure ]
 crbug.com/792546 external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html [ Failure ]
-
-crbug.com/812464 inspector-protocol/network/interception-file-url.js [ Pass Crash ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index f6b13e2..17e59858 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -92,12 +92,15 @@
 Bug(none) virtual/spv2/ [ Skip ]
 Bug(none) virtual/stable/ [ Skip ]
 Bug(none) virtual/targetedstylerecalc/ [ Skip ]
+Bug(none) virtual/video-surface-layer/ [ Skip ]
 Bug(none) virtual/reporting-api/ [ Skip ]
 Bug(none) virtual/wheelscrolllatching/ [ Skip ]
 Bug(none) virtual/windows-directwrite/ [ Skip ]
 Bug(none) virtual/without-smil/ [ Skip ]
 Bug(none) virtual/blink-gen-property-trees/ [ Skip ]
 
+crbug.com/778875 virtual/threaded/fast/animationworklet/ [ Skip ]
+
 # Fail on SPv1, but succeed on SPv2
 crbug.com/472330 fast/borders/border-image-outset-split-inline-vertical-lr.html [ Pass ]
 crbug.com/817175 compositing/overflow/clip-escaping-reverse-order-should-not-crash.html [ Pass ]
@@ -383,8 +386,10 @@
 Bug(none) compositing/squashing/squashing-sparsity-heuristic.html [ Failure ]
 Bug(none) compositing/tiled-layers-hidpi.html [ Failure ]
 Bug(none) compositing/update-paint-phases.html [ Failure ]
+Bug(none) compositing/video/video-controls-layer-creation-squashing.html [ Crash Failure ]
+Bug(none) compositing/video/video-controls-layer-creation.html [ Crash Failure ]
 Bug(none) compositing/video/video-poster.html [ Crash Failure ]
-Bug(none) compositing/video/video-reflection.html [ Crash Failure  ]
+Bug(none) compositing/video/video-reflection.html [ Crash Failure ]
 Bug(none) compositing/visibility/layer-visible-content.html [ Failure ]
 Bug(none) compositing/visibility/overlays.html [ Failure Crash ]
 Bug(none) compositing/visibility/visibility-image-layers-dynamic.html [ Crash Failure ]
@@ -1012,9 +1017,6 @@
 crbug.com/702353 virtual/threaded/transitions/transition-end-event-destroy-iframe.html [ Timeout ]
 crbug.com/702365 virtual/threaded/animations/composited-filter-webkit-filter.html [ Failure ]
 crbug.com/702370 virtual/threaded/animations/compositor-independent-transform-cancel.html [ Failure ]
-crbug.com/778875 virtual/threaded/fast/animationworklet/animation-worklet-visual-update.html [ Failure Crash ]
-crbug.com/778875 virtual/threaded/fast/animationworklet/animation-worklet-animator-animate.html [ Failure ]
-crbug.com/778875 virtual/threaded/fast/animationworklet/animation-worklet-scroll-timeline.html [ Failure ]
 
 # Eight of the frames in the test below paint no content. In SPv2 we will never
 # composite animations that paint nothing. For now we mark this test as failing,
@@ -1406,4 +1408,4 @@
 
 Bug(none) compositing/squashing/frame-clip-squashed-scrolled.html [ Failure ]
 Bug(none) fast/block/positioning/vertical-rl/002.html [ Failure ]
-Bug(none) virtual/threaded/fast/animationworklet/animation-worklet-start-delay.html [ Failure ]
+Bug(none) rootscroller/gesture-scroll-document-not-root-scroller.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 500f3ac..17e8fe3f 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -153,6 +153,10 @@
 # Not relevant, because SPv175 is launching imminently.
 crbug.com/804670 virtual/disable-spv175/paint/filters/drop-shadow-clipped.html [ Skip ]
 
+
+crbug.com/795549 external/wpt/css/css-filter/filtered-block-is-container.html [ Failure ]
+crbug.com/795549 external/wpt/css/css-filter/filtered-inline-is-container.html [ Failure ]
+
 # ====== Paint team owned tests to here ======
 
 # ====== Layout team owned tests from here ======
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 37ef0e3..659df7f 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -35999,6 +35999,42 @@
      {}
     ]
    ],
+   "css/css-filter/filtered-block-is-container.html": [
+    [
+     "/css/css-filter/filtered-block-is-container.html",
+     [
+      [
+       "/css/css-filter/filtered-block-is-container-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-filter/filtered-html-is-not-container.html": [
+    [
+     "/css/css-filter/filtered-html-is-not-container.html",
+     [
+      [
+       "/css/css-filter/filtered-html-is-not-container-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-filter/filtered-inline-is-container.html": [
+    [
+     "/css/css-filter/filtered-inline-is-container.html",
+     [
+      [
+       "/css/css-filter/filtered-inline-is-container-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/Flexible-order.html": [
     [
      "/css/css-flexbox/Flexible-order.html",
@@ -99265,6 +99301,11 @@
      {}
     ]
    ],
+   "WebCryptoAPI/derive_bits_keys/pbkdf2.https.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "WebCryptoAPI/derive_bits_keys/pbkdf2.js": [
     [
      {}
@@ -109495,6 +109536,21 @@
      {}
     ]
    ],
+   "css/css-filter/filtered-block-is-container-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-filter/filtered-html-is-not-container-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-filter/filtered-inline-is-container-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-flexbox/OWNERS": [
     [
      {}
@@ -132690,6 +132746,11 @@
      {}
     ]
    ],
+   "css/cssom/historical-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/cssom/interfaces-expected.txt": [
     [
      {}
@@ -168825,6 +168886,11 @@
      {}
     ]
    ],
+   "x-frame-options/README.md": [
+    [
+     {}
+    ]
+   ],
    "x-frame-options/support/helper.js": [
     [
      {}
@@ -190618,6 +190684,12 @@
      {}
     ]
    ],
+   "css/cssom-view/elementScroll-002.html": [
+    [
+     "/css/cssom-view/elementScroll-002.html",
+     {}
+    ]
+   ],
    "css/cssom-view/elementScroll.html": [
     [
      "/css/cssom-view/elementScroll.html",
@@ -210276,6 +210348,16 @@
      {}
     ]
    ],
+   "html/webappapis/timers/missing-timeout-setinterval.any.js": [
+    [
+     "/html/webappapis/timers/missing-timeout-setinterval.any.html",
+     {}
+    ],
+    [
+     "/html/webappapis/timers/missing-timeout-setinterval.any.worker.html",
+     {}
+    ]
+   ],
    "html/webappapis/timers/negative-setinterval.html": [
     [
      "/html/webappapis/timers/negative-setinterval.html",
@@ -211258,6 +211340,12 @@
      {}
     ]
    ],
+   "mediacapture-streams/MediaStreamTrack-applyConstraints.https.html": [
+    [
+     "/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html",
+     {}
+    ]
+   ],
    "mediacapture-streams/MediaStreamTrack-getCapabilities.https.html": [
     [
      "/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html",
@@ -255902,11 +255990,11 @@
    "testharness"
   ],
   "IndexedDB/keypath-special-identifiers.htm": [
-   "588026e7e95192b98b594e77fafe67495d5cd481",
+   "0392d5dc6be8c17d435f2e0382e378521551c4fb",
    "testharness"
   ],
   "IndexedDB/keypath.htm": [
-   "a21b6eecc56a924bdf017d9053be2f0eecd25eeb",
+   "169a6f8e0f70ecf9089e2a6aa9232f632fe24e9a",
    "testharness"
   ],
   "IndexedDB/keypath_invalid.htm": [
@@ -256109,6 +256197,10 @@
    "766a7184da406918e9dc6718125975a59d3d5d36",
    "support"
   ],
+  "WebCryptoAPI/derive_bits_keys/pbkdf2.https.worker-expected.txt": [
+   "bbc9e6ea6464cb50fdd14aee00e460e831f1c507",
+   "support"
+  ],
   "WebCryptoAPI/derive_bits_keys/pbkdf2.https.worker.js": [
    "1149c335951baa52b7d1ad3192292fb46176d491",
    "testharness"
@@ -282117,6 +282209,30 @@
    "35eb3b4cfe4505a5c9761dcecc047a8cd09f8fb9",
    "support"
   ],
+  "css/css-filter/filtered-block-is-container-ref.html": [
+   "937aebf17944a83bfb41b3d9a6035f00e975c05d",
+   "support"
+  ],
+  "css/css-filter/filtered-block-is-container.html": [
+   "e910cc30bcb2aecc0fcc60ca3cbf381c39dab837",
+   "reftest"
+  ],
+  "css/css-filter/filtered-html-is-not-container-ref.html": [
+   "2e7b8249aa26a996e173f8f0d5e42b0b45457719",
+   "support"
+  ],
+  "css/css-filter/filtered-html-is-not-container.html": [
+   "5fb31e59005e70dd8bb10525698c4b343c22b2dc",
+   "reftest"
+  ],
+  "css/css-filter/filtered-inline-is-container-ref.html": [
+   "7c985ca7fb9e26a2b6139ff863817aaf236d6af2",
+   "support"
+  ],
+  "css/css-filter/filtered-inline-is-container.html": [
+   "0c1b258810f515e72269ab07d8efb34791a9b0c4",
+   "reftest"
+  ],
   "css/css-flexbox/Flexible-order.html": [
    "ff6b01d6069b9106c60e3f86ac29bffb7c94f916",
    "reftest"
@@ -323373,6 +323489,10 @@
    "f033a1ec4b1f0636897c4ee16b67c1c13f0eac4e",
    "testharness"
   ],
+  "css/cssom-view/elementScroll-002.html": [
+   "98dec0c15711c0f7baf4a0ea404e1fda872e3d5b",
+   "testharness"
+  ],
   "css/cssom-view/elementScroll.html": [
    "2119d689cc369bd6632ee1a9525bcbf7d1d4ba65",
    "testharness"
@@ -323933,8 +324053,12 @@
    "d3ef09fb6092078562f8923879b9ece97938df47",
    "testharness"
   ],
+  "css/cssom/historical-expected.txt": [
+   "ae1b10ae00e5fec559c56734b2d42d2c1766d9c7",
+   "support"
+  ],
   "css/cssom/historical.html": [
-   "02b135e62439d775d7e8de7ca94c831a8d00e077",
+   "89c506ea58f2ad38eb9ecc1e5f422b81a45b07fa",
    "testharness"
   ],
   "css/cssom/inline-style-001.html": [
@@ -330226,11 +330350,11 @@
    "testharness"
   ],
   "dom/events/relatedTarget.window-expected.txt": [
-   "4e0722bf72ed7df73fe9fe833df9186b09d11596",
+   "2d8e58a9fe23b6068ecd4c5ceae4dac6dd512d12",
    "support"
   ],
   "dom/events/relatedTarget.window.js": [
-   "0426d2ecae3f3562be175e4364353d979365ed1c",
+   "3dd9ddfa4d8d584f6ddf6db52e4e9020491088d8",
    "testharness"
   ],
   "dom/historical-expected.txt": [
@@ -335826,7 +335950,7 @@
    "reftest"
   ],
   "fetch/corb/img-mime-types-coverage.tentative.sub.html": [
-   "58422f923455c1f62e0c4e743b1c900061657146",
+   "02da8b9ee9430d552c4cb71fb759e05e939ec05e",
    "testharness"
   ],
   "fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub-expected.html": [
@@ -335938,11 +336062,11 @@
    "support"
   ],
   "fetch/corb/script-html-correctly-labeled.tentative.sub.html": [
-   "71cb97517821177aa1c1d116f830cd2315963d18",
+   "971fcca2f52153a39bf3643b52fb69b6255acf32",
    "testharness"
   ],
   "fetch/corb/script-html-js-polyglot.sub.html": [
-   "19d0530fcb573b6bcbffebc5dbe2ce3537faa8a3",
+   "4b28bd95bd19ea95df3e78bbfc477fb7dea60e29",
    "testharness"
   ],
   "fetch/corb/script-html-via-cross-origin-blob-url.sub.html": [
@@ -342714,15 +342838,15 @@
    "manual"
   ],
   "html/editing/dnd/file/001.html": [
-   "28e4e1d0e06a8c300c116aeb2d07e4808bdf56fe",
+   "9a004cc780577f28242feeedce7a15deb7849c8c",
    "support"
   ],
   "html/editing/dnd/file/002.html": [
-   "62f40d477019e663e377f314947c28ea6b556864",
+   "fdb4d92324f81cd4412fa8334aeb75fa79044804",
    "support"
   ],
   "html/editing/dnd/file/003.html": [
-   "df5bb0614ea6c7135caead8c5a1258bf981aeb13",
+   "578bc2823d303d41577abc9c0a855af338baf8be",
    "support"
   ],
   "html/editing/dnd/file/004.html": [
@@ -342738,11 +342862,11 @@
    "support"
   ],
   "html/editing/dnd/file/007.html": [
-   "21851c97db234d854576e3ea6e1029ffed38a761",
+   "bb927ac9126c217f7cb0bcf07e58f6e8f756fc06",
    "support"
   ],
   "html/editing/dnd/file/008.html": [
-   "081def5342c9b8bb426812bef312e6cdee3dd66e",
+   "b632d267d0c66c631670957566e763d8511efbe4",
    "support"
   ],
   "html/editing/dnd/file/009.html": [
@@ -342754,7 +342878,7 @@
    "support"
   ],
   "html/editing/dnd/file/011.html": [
-   "6c5de23f6a63e817d60d1357020ee90f71193372",
+   "4e78bcbbdd8b8f220e1b431f964c299636d2a064",
    "support"
   ],
   "html/editing/dnd/file/fail.txt": [
@@ -356601,6 +356725,10 @@
    "49fd55dbbf64c6973a0e76284c0e3d8b7bf0ef3c",
    "testharness"
   ],
+  "html/webappapis/timers/missing-timeout-setinterval.any.js": [
+   "40ad74d6ed3719dcad2097246d74d49c87b989aa",
+   "testharness"
+  ],
   "html/webappapis/timers/negative-setinterval.html": [
    "405046cab9cd15a88d57eace1f293ebdd7b1b3e2",
    "testharness"
@@ -358450,7 +358578,7 @@
    "testharness"
   ],
   "mediacapture-streams/MediaDevices-getUserMedia.https.html": [
-   "a515deeec87c394b4a826b538df6dd0baa05cae6",
+   "dbd2cbacb24f088167e1c34207bea12c19f5d0e1",
    "testharness"
   ],
   "mediacapture-streams/MediaStream-MediaElement-preload-none-manual.https.html": [
@@ -358525,6 +358653,10 @@
    "e3358344a76f874b68bdba743f113caa3b61ec88",
    "testharness"
   ],
+  "mediacapture-streams/MediaStreamTrack-applyConstraints.https.html": [
+   "cda78cab93e93f9e436d46db8b7a6a0d12471e87",
+   "testharness"
+  ],
   "mediacapture-streams/MediaStreamTrack-end-manual.https.html": [
    "6511203b417168722d1e05d90e58364ebce145ea",
    "manual"
@@ -391921,6 +392053,10 @@
    "fad08f267635717c6a2930de14df27107039b3a8",
    "support"
   ],
+  "x-frame-options/README.md": [
+   "cb5f2cb5d74263ce584e1ad76045a04afae4ba0a",
+   "support"
+  ],
   "x-frame-options/deny.sub.html": [
    "eb6b6474a393714f62a85bf435e7f342ceff2e0e",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath-special-identifiers.htm b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath-special-identifiers.htm
index 331169b5..cb64d0b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath-special-identifiers.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath-special-identifiers.htm
@@ -38,11 +38,6 @@
     property: 'lastModified',
     instance: new File([''], '', {lastModified: 123}),
   },
-  {
-    type: 'File',
-    property: 'lastModifiedDate',
-    instance: new File([''], '', {lastModified: 123}),
-  },
 ].forEach(function(testcase) {
   indexeddb_test(
     (t, db) => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath.htm b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath.htm
index b59d614..4985712 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/keypath.htm
@@ -125,7 +125,7 @@
             "[Blob.length, Blob.type]");
     }
 
-    // File.name and File.lastModifiedDate is not testable automatically
+    // File.name and File.lastModified is not testable automatically
 
     keypath(['name', 'type'],
         [ { name: "orange", type: "fruit" }, { name: "orange", type: ["telecom", "french"] } ],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-block-is-container-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-block-is-container-ref.html
new file mode 100644
index 0000000..fc9467f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-block-is-container-ref.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Filter: Filtered block establishes a containing block reference.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+<style>
+#scroller {
+  width: 500px;
+  height: 500px;
+  overflow: scroll
+}
+.spacer {
+  width: 1000px;
+  height: 500px;
+  background-color: lightgreen;
+}
+#transform {
+  /* no-op transform */
+  transform: translateX(0px);
+  width: 100px;
+  height: 50px;
+  background-color: lightblue;
+}
+#fixed, #absolute {
+  width: 100px;
+  height: 100px;
+}
+#fixed {
+  position: fixed;
+  top: 100px;
+  left: 150px;
+  background-color: green;
+}
+#absolute {
+  position: absolute;
+  top: 200px;
+  left: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="scroller">
+  <div class="spacer">
+  </div>
+  <div id="transform">
+    <div id="fixed"></div>
+    <div id="absolute"></div>
+  </div>
+  <div class="spacer">
+  </div>
+</div>
+
+<script>
+window.onload = function() {
+  document.getElementById("scroller").scrollTo(50, 250);
+}
+</script>
+
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-block-is-container.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-block-is-container.html
new file mode 100644
index 0000000..6f99f36
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-block-is-container.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Filter: Filtered block establishes a containing block.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="match" href="filtered-block-is-container-ref.html">
+
+<style>
+#scroller {
+  width: 500px;
+  height: 500px;
+  overflow: scroll
+}
+.spacer {
+  width: 1000px;
+  height: 500px;
+  background-color: lightgreen;
+}
+#filter {
+  /* no-op filter */
+  filter: blur(0px);
+  width: 100px;
+  height: 50px;
+  background-color: lightblue;
+}
+#fixed, #absolute {
+  width: 100px;
+  height: 100px;
+}
+#fixed {
+  position: fixed;
+  top: 100px;
+  left: 150px;
+  background-color: green;
+}
+#absolute {
+  position: absolute;
+  top: 200px;
+  left: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="scroller">
+  <div class="spacer">
+  </div>
+  <div id="filter">
+    <div id="fixed"></div>
+    <div id="absolute"></div>
+  </div>
+  <div class="spacer">
+  </div>
+</div>
+
+<script>
+window.onload = function() {
+  document.getElementById("scroller").scrollTo(50, 250);
+}
+</script>
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-html-is-not-container-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-html-is-not-container-ref.html
new file mode 100644
index 0000000..c1f179a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-html-is-not-container-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Filter: Filtered html element does not establish a containing block.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+<style>
+#spacer {
+  width: 2000px;
+  height: 2000px;
+  background-color: lightgreen;
+}
+#fixed, #absolute {
+  width: 100px;
+  height: 100px;
+}
+#fixed {
+  position: fixed;
+  top: 100px;
+  left: 150px;
+  background-color: green;
+}
+#absolute {
+  position: absolute;
+  top: 200px;
+  left: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="fixed"></div>
+<div id="absolute"></div>
+<div id="spacer"></div>
+
+<script>
+window.onload = function() { window.scrollTo(50, 100); };
+</script>
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-html-is-not-container.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-html-is-not-container.html
new file mode 100644
index 0000000..8adc302
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-html-is-not-container.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Filter: Filtered html element does not establish a containing block.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="match" href="filtered-html-is-not-container-ref.html">
+
+<style>
+html {
+  filter: blur(0px);
+}
+#spacer {
+  width: 2000px;
+  height: 2000px;
+  background-color: lightgreen;
+}
+#fixed, #absolute {
+  width: 100px;
+  height: 100px;
+}
+#fixed {
+  position: fixed;
+  top: 100px;
+  left: 150px;
+  background-color: green;
+}
+#absolute {
+  position: absolute;
+  top: 200px;
+  left: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="fixed"></div>
+<div id="absolute"></div>
+<div id="spacer"></div>
+
+<script>
+window.onload = function() { window.scrollTo(50, 100); };
+</script>
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-inline-is-container-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-inline-is-container-ref.html
new file mode 100644
index 0000000..aa6c12e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-inline-is-container-ref.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Filter: Filtered inline establishes a containing block.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+
+<style>
+#scroller {
+  width: 500px;
+  height: 500px;
+  overflow: scroll
+}
+.spacer {
+  width: 1000px;
+  height: 500px;
+  background-color: lightgreen;
+}
+#transform {
+  /* no-op filter */
+  transform: translateX(0px);
+}
+#fixed, #absolute {
+  width: 100px;
+  height: 100px;
+}
+#fixed {
+  position: fixed;
+  top: 100px;
+  left: 150px;
+  background-color: green;
+}
+#absolute {
+  position: absolute;
+  top: 200px;
+  left: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="scroller">
+  <div class="spacer">
+  </div>
+  <div id="transform">
+    a
+    <div id="fixed"></div>
+    <div id="absolute"></div>
+  </div>
+  <div class="spacer">
+  </div>
+</div>
+
+<script>
+window.onload = function() {
+  document.getElementById("scroller").scrollTo(50, 250);
+}
+</script>
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-inline-is-container.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-inline-is-container.html
new file mode 100644
index 0000000..56f1d91f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-filter/filtered-inline-is-container.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Filter: Filtered inline establishes a containing block reference.</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="match" href="filtered-inline-is-container-ref.html">
+
+<style>
+#scroller {
+  width: 500px;
+  height: 500px;
+  overflow: scroll
+}
+.spacer {
+  width: 1000px;
+  height: 500px;
+  background-color: lightgreen;
+}
+#filter {
+  /* no-op filter */
+  filter: blur(0px);
+  display: inline;
+}
+#fixed, #absolute {
+  width: 100px;
+  height: 100px;
+}
+#fixed {
+  position: fixed;
+  top: 100px;
+  left: 150px;
+  background-color: green;
+}
+#absolute {
+  position: absolute;
+  top: 200px;
+  left: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="scroller">
+  <div class="spacer">
+  </div>
+  <div id="filter">
+    a
+    <div id="fixed"></div>
+    <div id="absolute"></div>
+  </div>
+  <div class="spacer">
+  </div>
+</div>
+
+<script>
+window.onload = function() {
+  document.getElementById("scroller").scrollTo(50, 250);
+}
+</script>
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/elementScroll-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/elementScroll-002.html
new file mode 100644
index 0000000..a1a28aab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/elementScroll-002.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>cssom-view - elementScroll - 002</title>
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrolltop">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-element-scrollleft">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="scroller1" style="height: 100px; width: 100px; overflow: scroll; background: red;">
+    <div style="background: green; margin-top: 100px; margin-left: 100px; width: 100px; height: 100px;"></div>
+</div>
+<div id="scroller2" style="height: 100px; width: 100px; overflow: hidden; background: red;">
+    <div style="background: green; margin-top: 100px; padding-left: 100px; width: 100px; height: 100px;"></div>
+</div>
+<div id="scroller3" style="height: 100px; width: 100px; overflow: scroll; background: red;">
+    <div style="background: green; padding-top: 100px; margin-left: 100px; width: 100px; height: 100px;"></div>
+</div>
+<div id="scroller4" style="height: 100px; width: 100px; overflow: hidden; background: red;">
+    <div style="background: green; padding-top: 100px; padding-left: 100px; width: 100px; height: 100px;"></div>
+</div>
+<script>
+    test(function () {
+        var scroller1 = document.getElementById("scroller1");
+
+        scroller1.scrollTop = 100;
+        scroller1.scrollLeft = 100;
+        assert_equals(scroller1.scrollTop, 100, "changed scrollTop should be 100");
+        assert_equals(scroller1.scrollLeft, 100, "changed scrollLeft should be 100");
+
+    }, "simple scroll with style: 'margin' and 'overflow: scroll'");
+    test(function () {
+        var scroller2 = document.getElementById("scroller2");
+
+        scroller2.scrollTop = 100;
+        scroller2.scrollLeft = 100;
+        assert_equals(scroller2.scrollTop, 100, "changed scrollTop should be 100");
+        assert_equals(scroller2.scrollLeft, 100, "changed scrollLeft should be 100");
+
+    }, "simple scroll with style: 'margin' and 'overflow: hidden'");
+    test(function () {
+        var scroller3 = document.getElementById("scroller3");
+
+        scroller3.scrollTop = 100;
+        scroller3.scrollLeft = 100;
+        assert_equals(scroller3.scrollTop, 100, "changed scrollTop should be 100");
+        assert_equals(scroller3.scrollLeft, 100, "changed scrollLeft should be 100");
+
+    }, "simple scroll with style: 'padding' and 'overflow: scroll'");
+    test(function () {
+        var scroller4 = document.getElementById("scroller4");
+
+        scroller4.scrollTop = 100;
+        scroller4.scrollLeft = 100;
+        assert_equals(scroller4.scrollTop, 100, "changed scrollTop should be 100");
+        assert_equals(scroller4.scrollLeft, 100, "changed scrollLeft should be 100");
+
+    }, "simple scroll with style: 'padding' and 'overflow: hidden'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical-expected.txt
new file mode 100644
index 0000000..f2193a15
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical-expected.txt
@@ -0,0 +1,14 @@
+This is a testharness.js-based test.
+PASS Historical Document member: selectedStyleSheetSet
+PASS Historical Document member: lastStyleSheetSet
+PASS Historical Document member: preferredStyleSheetSet
+PASS Historical Document member: styleSheetSets
+PASS Historical Document member: enableStyleSheetsForSet
+FAIL Historical Document member: selectedStylesheetSet assert_false: expected false got true
+FAIL Historical Document member: preferredStylesheetSet assert_false: expected false got true
+PASS Historical Element member: cascadedStyle
+PASS Historical Element member: defaultStyle
+PASS Historical Element member: rawComputedStyle
+PASS Historical Element member: usedStyle
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical.html
index d956f14..ddd264c8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom/historical.html
@@ -11,6 +11,8 @@
   "preferredStyleSheetSet",
   "styleSheetSets",
   "enableStyleSheetsForSet",
+  "selectedStylesheetSet",
+  "preferredStylesheetSet",
 ].forEach(function(name) {
   test(function() {
     assert_false(name in document);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window-expected.txt
index bab0020..b22cc5b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window-expected.txt
@@ -2,8 +2,7 @@
 PASS Reset if target pointed to a shadow tree
 FAIL Reset if relatedTarget pointed to a shadow tree assert_equals: expected null but got object "[object XMLHttpRequest]"
 PASS Reset if target pointed to a shadow tree pre-dispatch
-FAIL Reset if relatedTarget pointed to a shadow tree pre-dispatch assert_equals: expected Element node <body><div id="log"></div>
-<script src="/dom/events/relat... but got DocumentFragment node with 2 children
+PASS Reset if relatedTarget pointed to a shadow tree pre-dispatch
 FAIL Reset targets on early return assert_false: expected false got true
 FAIL Reset targets before activation behavior assert_equals: expected null but got Element node <input type="checkbox"></input>
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window.js b/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window.js
index d3632bb9..4f68550a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/events/relatedTarget.window.js
@@ -41,13 +41,15 @@
 
 async_test(t => {
   const shadowChild = shadow.appendChild(document.createElement("div"));
-  shadowChild.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild)));
+  const shadowChild2 = shadow.appendChild(document.createElement("div"));
+  shadowChild2.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild)));
   const event = new FocusEvent("demo", { relatedTarget: shadowChild });
-  document.body.dispatchEvent(event);
+  shadowChild2.dispatchEvent(event);
   assert_equals(shadowChild.parentNode, document.body);
   assert_equals(event.target, null);
   assert_equals(event.relatedTarget, null);
   shadowChild.remove();
+  shadowChild2.remove();
   t.done();
 }, "Reset if relatedTarget pointed to a shadow tree pre-dispatch");
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html
index 7ccc41b4..65c5b84 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html
@@ -19,6 +19,7 @@
       // MIME-types not protected by CORB
       "image/gif", "image/png", "image/png;blah", "image/svg+xml",
       "application/javascript", "application/jsonp",
+      "image/gif;HI=THERE",
 
       // MIME types that may seem to be JSON or XML, but really aren't - i.e.
       // these MIME types are not covered by:
@@ -39,7 +40,8 @@
       "text/json", "application/json", "text/xml", "application/xml",
       "application/blah+json", "text/blah+json",
       "application/blah+xml", "text/blah+xml",
-      "TEXT/HTML", "TEXT/JSON", "TEXT/BLAH+JSON", "APPLICATION/BLAH+XML"]
+      "TEXT/HTML", "TEXT/JSON", "TEXT/BLAH+JSON", "APPLICATION/BLAH+XML",
+      "text/json;does=it;matter", "text/HTML;NO=it;does=NOT"]
 
   const get_url = (mime) => {
     // www1 is cross-origin, so the HTTP response is CORB-eligible -->
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html
index 76a8fad..8f4d767 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html
@@ -26,5 +26,5 @@
   // www1 is cross-origin, so the HTTP response is CORB-eligible.
   script.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html';
   document.body.appendChild(script)
-});
+}, "CORB-blocked script has no syntax errors");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-js-polyglot.sub.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-js-polyglot.sub.html
index 8395901..950a907 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-js-polyglot.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/corb/script-html-js-polyglot.sub.html
@@ -25,5 +25,5 @@
   // www1 is cross-origin, so the HTTP response is CORB-eligible.
   script.src = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-js-polyglot.js"
   document.body.appendChild(script)
-});
+}, "CORB cannot block polyglot HTML/JS");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/001.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/001.html
index 07ef4dbbb..b911920 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/001.html
@@ -55,8 +55,8 @@
       fails[fails.length] = 'dataTransfer.files[0].size '+e.dataTransfer.files[0].size+' instead of '+filesize;
     }
     /*
-    if( !e.dataTransfer.files[0].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files[0].lastModifiedDate';
+    if( !e.dataTransfer.files[0].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files[0].lastModified';
     }
     */
     if( e.dataTransfer.files[0].name != filename ) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/002.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/002.html
index b029afb..c8d633d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/002.html
@@ -66,8 +66,8 @@
       fails[fails.length] = 'dataTransfer.files['+i0+'].size '+e.dataTransfer.files[i0].size+' instead of '+filesize1;
     }
     /*
-    if( !e.dataTransfer.files[i0].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files['+i0+'].lastModifiedDate';
+    if( !e.dataTransfer.files[i0].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files['+i0+'].lastModified';
     }
     */
     if( e.dataTransfer.files[i0].name != filename1 ) {
@@ -80,8 +80,8 @@
       fails[fails.length] = 'dataTransfer.files['+i1+'].size '+e.dataTransfer.files[i1].size+' instead of '+filesize2;
     }
     /*
-    if( !e.dataTransfer.files[i1].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files['+i1+'].lastModifiedDate';
+    if( !e.dataTransfer.files[i1].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files['+i1+'].lastModified';
     }
     */
     if( e.dataTransfer.files[i1].name != filename2 ) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/003.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/003.html
index 0c532ea5c..51e5a5a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/003.html
@@ -42,8 +42,8 @@
       fails[fails.length] = 'dataTransfer.files[0].size '+e.dataTransfer.files[0].size+' instead of '+filesize;
     }
     /*
-    if( !e.dataTransfer.files[0].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files[0].lastModifiedDate';
+    if( !e.dataTransfer.files[0].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files[0].lastModified';
     }
     */
     if( e.dataTransfer.files[0].name != filename ) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/007.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/007.html
index f3e51179..099716f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/007.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/007.html
@@ -57,8 +57,8 @@
       fails[fails.length] = 'dataTransfer.files[0].size '+e.dataTransfer.files[0].size+' instead of '+filesize1+' or '+filesize2;
     }
     /*
-    if( !e.dataTransfer.files[0].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files[0].lastModifiedDate';
+    if( !e.dataTransfer.files[0].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files[0].lastModified';
     }
     */
     if( !window.FileReader ) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/008.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/008.html
index 3ba28276..49751582 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/008.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/008.html
@@ -60,8 +60,8 @@
     }
     */
     /*
-    if( !e.dataTransfer.files[0].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files[0].lastModifiedDate';
+    if( !e.dataTransfer.files[0].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files[0].lastModified';
     }
     */
     if( !window.FileReader ) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/011.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/011.html
index 2c12d64ec..a265e7b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/011.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/file/011.html
@@ -45,8 +45,8 @@
       fails[fails.length] = 'dataTransfer.files[0].size '+e.dataTransfer.files[0].size+' instead of '+filesize;
     }
     /*
-    if( !e.dataTransfer.files[0].lastModifiedDate ) {
-      fails[fails.length] = 'no dataTransfer.files[0].lastModifiedDate';
+    if( !e.dataTransfer.files[0].lastModified ) {
+      fails[fails.length] = 'no dataTransfer.files[0].lastModified';
     }
     */
     if( e.dataTransfer.files[0].name != filename ) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/missing-timeout-setinterval.any.js b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/missing-timeout-setinterval.any.js
new file mode 100644
index 0000000..33a1cc0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/missing-timeout-setinterval.any.js
@@ -0,0 +1,34 @@
+function timeout_trampoline(t, timeout, message) {
+  t.step_timeout(function() {
+    // Yield in case we managed to be called before the second interval callback.
+    t.step_timeout(function() {
+      assert_unreached(message);
+    }, timeout);
+  }, timeout);
+}
+
+async_test(function(t) {
+  let ctr = 0;
+  let h = setInterval(t.step_func(function() {
+    if (++ctr == 2) {
+      clearInterval(h);
+      t.done();
+      return;
+    }
+  }) /* no interval */);
+
+  timeout_trampoline(t, 100, "Expected setInterval callback to be called two times");
+}, "Calling setInterval with no interval should be the same as if called with 0 interval");
+
+async_test(function(t) {
+  let ctr = 0;
+  let h = setInterval(t.step_func(function() {
+    if (++ctr == 2) {
+      clearInterval(h);
+      t.done();
+      return;
+    }
+  }),  undefined);
+
+  timeout_trampoline(t, 100, "Expected setInterval callback to be called two times");
+}, "Calling setInterval with undefined interval should be the same as if called with 0 interval");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/x-frame-options/README.md b/third_party/WebKit/LayoutTests/external/wpt/x-frame-options/README.md
new file mode 100644
index 0000000..7b35f0f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/x-frame-options/README.md
@@ -0,0 +1,2 @@
+This directory contains tests for
+[HTTP Header Field X-Frame-Options](https://tools.ietf.org/html/rfc7034).
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table/replace-col-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table/replace-col-expected.txt
new file mode 100644
index 0000000..a1b9688
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/table/replace-col-expected.txt
@@ -0,0 +1,50 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection THEAD",
+          "rect": [8, 82, 56, 26],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutTableSection TFOOT",
+          "rect": [8, 132, 56, 24],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 108, 56, 24],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTable TABLE",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutTableSection THEAD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TFOOT",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL",
+      "reason": "appeared"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt-expected.txt
index 7365feb..5735d66 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt-expected.txt
@@ -44,3 +44,17 @@
 Setting max length for evaluation to 0
 Expression: "1 + 2" yielded preview: ""
 
+Running: testClickingPreviewFocusesEditor
+Prompt text set to `1 + 2`
+Selection before: {"startLine":0,"startColumn":0,"endLine":0,"endColumn":0}
+Clicking preview element
+Selection after: {"startLine":0,"startColumn":5,"endLine":0,"endColumn":5}
+Editor has focus: true
+
+Running: testClickWithSelectionDoesNotFocusEditor
+Prompt text set to `1 + 2`
+Selection before: 3
+Clicking preview element
+Selection after: 3
+Editor has focus: false
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt.js
index 2fdd3c9..f648ddbc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-runtime-result-below-prompt.js
@@ -6,11 +6,11 @@
   TestRunner.addResult(`Tests that console fills the empty element below the prompt editor.\n`);
   await TestRunner.loadModule('console_test_runner');
   await TestRunner.showPanel('console');
-  await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
   await ConsoleTestRunner.waitForPendingViewportUpdates();
 
   const consoleView = Console.ConsoleView.instance();
   const prompt = consoleView._prompt;
+  const editor = await ConsoleTestRunner.waitUntilConsoleEditorLoaded();
 
   TestRunner.runTestSuite([
     async function testUnsafeExpressions(next) {
@@ -39,6 +39,44 @@
 
       next();
     },
+
+    async function testClickingPreviewFocusesEditor(next) {
+      const expression = `1 + 2`;
+      TestRunner.addResult(`Prompt text set to \`${expression}\``);
+      prompt.setText(expression);
+      await prompt._previewRequestForTest;
+
+      editor.setSelection(TextUtils.TextRange.createFromLocation(0, 0));
+      TestRunner.addResult('Selection before: ' + editor.selection().toString());
+
+      TestRunner.addResult(`Clicking preview element`);
+      prompt._eagerPreviewElement.click();
+
+      TestRunner.addResult('Selection after: ' + editor.selection().toString());
+      TestRunner.addResult(`Editor has focus: ${editor.element.hasFocus()}`);
+
+      next();
+    },
+
+    async function testClickWithSelectionDoesNotFocusEditor(next) {
+      const expression = `1 + 2`;
+      TestRunner.addResult(`Prompt text set to \`${expression}\``);
+      prompt.setText(expression);
+      await prompt._previewRequestForTest;
+      document.activeElement.blur();
+
+      var firstTextNode = prompt.belowEditorElement().traverseNextTextNode();
+      window.getSelection().setBaseAndExtent(firstTextNode, 0, firstTextNode, 1);
+      TestRunner.addResult('Selection before: ' + window.getSelection().toString());
+
+      TestRunner.addResult(`Clicking preview element`);
+      prompt._eagerPreviewElement.click();
+
+      TestRunner.addResult('Selection after: ' + window.getSelection().toString());
+      TestRunner.addResult(`Editor has focus: ${editor.element.hasFocus()}`);
+
+      next();
+    },
   ]);
 
   async function checkExpression(expression) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-with-large-prompt.js b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-with-large-prompt.js
index c3a4d082..d8c067d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-with-large-prompt.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console/viewport-testing/console-stick-to-bottom-with-large-prompt.js
@@ -21,7 +21,7 @@
 
   const consoleView = Console.ConsoleView.instance();
   const viewport = consoleView._viewport;
-  const heightBelowPromptEditor = consoleView._prompt.heightBelowEditor();
+  const heightBelowPromptEditor = consoleView._prompt.belowEditorElement().offsetHeight;
   const messagesCount = 150;
 
   TestRunner.runTestSuite([
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col-expected.html
new file mode 100644
index 0000000..7fb4fad
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col-expected.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<style>td { width: 50px; height: 20px; background: green }</style>
+<p style="height: 50px">
+Tests repaint of table sections when a col is replaced.
+Passes if there are 3 green rectangles without red.
+</p>
+<table>
+  <thead><tr><td></td></tr></thead>
+  <tbody><tr><td></td></tr></tbody>
+  <tfoot><tr><td></td></tr></tfoot>
+</table>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col-expected.txt
new file mode 100644
index 0000000..97db693
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col-expected.txt
@@ -0,0 +1,61 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTableSection THEAD",
+          "rect": [8, 82, 56, 26],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutTableSection TFOOT",
+          "rect": [8, 132, 56, 24],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutTableSection TBODY",
+          "rect": [8, 108, 56, 24],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTable TABLE",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutTableSection THEAD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TFOOT",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL",
+      "reason": "appeared"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col.html b/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col.html
new file mode 100644
index 0000000..a0ca9b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table/replace-col.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<style>td { width: 50px; height: 20px }</style>
+<script src="../resources/text-based-repaint.js"></script>
+<script>
+function repaintTest() {
+  col.remove();
+  var new_col = document.createElement('col');
+  new_col.style.background = 'green';
+  colgroup.insertBefore(new_col, colgroup.firstChild);
+}
+onload = runRepaintAndPixelTest;
+</script>
+<p style="height: 50px">
+Tests repaint of table sections when a col is replaced.
+Passes if there are 3 green rectangles without red.
+</p>
+<table>
+  <colgroup id="colgroup">
+    <col id="col" style="background: red">
+  </colgroup>
+  <thead><tr><td></td></tr></thead>
+  <tbody><tr><td></td></tr></tbody>
+  <tfoot><tr><td></td></tr></tfoot>
+</table>
diff --git a/third_party/WebKit/LayoutTests/virtual/disable-spv175/paint/invalidation/table/replace-col-expected.txt b/third_party/WebKit/LayoutTests/virtual/disable-spv175/paint/invalidation/table/replace-col-expected.txt
new file mode 100644
index 0000000..15a6ca7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/disable-spv175/paint/invalidation/table/replace-col-expected.txt
@@ -0,0 +1,65 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "drawsContent": false,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "Scrolling Layer",
+      "bounds": [800, 600],
+      "drawsContent": false
+    },
+    {
+      "name": "Scrolling Contents Layer",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutTable TABLE",
+          "rect": [8, 82, 56, 74],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutTableCol COL",
+          "rect": [8, 82, 56, 74],
+          "reason": "appeared"
+        },
+        {
+          "object": "LayoutTableCol COL id='col'",
+          "rect": [8, 82, 56, 74],
+          "reason": "disappeared"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutTableCol COL id='col'",
+      "reason": "disappeared"
+    },
+    {
+      "object": "LayoutTable TABLE",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutTableSection THEAD",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TBODY",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableSection TFOOT",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutTableCol COL",
+      "reason": "appeared"
+    }
+  ]
+}
+
diff --git a/third_party/blink/public/platform/web_layer.h b/third_party/blink/public/platform/web_layer.h
index a4ba289b3..df50dd3 100644
--- a/third_party/blink/public/platform/web_layer.h
+++ b/third_party/blink/public/platform/web_layer.h
@@ -89,13 +89,6 @@
 
   virtual void SetOpacity(float) = 0;
   virtual float Opacity() const = 0;
-  // If set to true, content opaqueness cannot be changed using
-  // WebLayer::SetOpaque. However, it can still be modified using
-  // SetContentsOpaque on the cc::Layer. This is a roundabout way of allowing
-  // creators of WebLayers to specify opaqueness without
-  // CompositedLayerMapping/PaintArtifactCompositor clobbering it later. This
-  // will be addressed once WebLayer is removed.
-  virtual void SetContentsOpaqueIsFixed(bool) = 0;
 
   virtual void SetBlendMode(SkBlendMode) = 0;
   virtual SkBlendMode BlendMode() const = 0;
diff --git a/third_party/blink/public/web/web_plugin_container.h b/third_party/blink/public/web/web_plugin_container.h
index c3693f44..3e324f0 100644
--- a/third_party/blink/public/web/web_plugin_container.h
+++ b/third_party/blink/public/web/web_plugin_container.h
@@ -138,7 +138,7 @@
 
   // Sets the layer representing the plugin for compositing. The
   // WebPluginContainer does *not* take ownership.
-  virtual void SetWebLayer(WebLayer*) = 0;
+  virtual void SetWebLayer(WebLayer*, bool prevent_contents_opaque_changes) = 0;
 
   virtual void RequestFullscreen() = 0;
   virtual bool IsFullscreenElement() const = 0;
diff --git a/third_party/blink/public/web/web_remote_frame.h b/third_party/blink/public/web/web_remote_frame.h
index 85b44de..0d3e5e0 100644
--- a/third_party/blink/public/web/web_remote_frame.h
+++ b/third_party/blink/public/web/web_remote_frame.h
@@ -61,7 +61,7 @@
                                             WebFrame* opener) = 0;
 
   // Layer for the in-process compositor.
-  virtual void SetWebLayer(WebLayer*) = 0;
+  virtual void SetWebLayer(WebLayer*, bool prevent_contents_opaque_changes) = 0;
 
   // Set security origin replicated from another process.
   virtual void SetReplicatedOrigin(
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index d8f1b72..b873fc98 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1280,17 +1280,39 @@
 }
 
 IntRect Element::VisibleBoundsInVisualViewport() const {
-  if (!GetLayoutObject() || !GetDocument().GetPage())
+  if (!GetLayoutObject() || !GetDocument().GetPage() ||
+      !GetDocument().GetFrame())
     return IntRect();
-  // TODO(tkent): Can we check invisibility by scrollable non-frame elements?
 
-  IntSize viewport_size = GetDocument().GetPage()->GetVisualViewport().Size();
-  IntRect rect(0, 0, viewport_size.Width(), viewport_size.Height());
   // We don't use absoluteBoundingBoxRect() because it can return an IntRect
   // larger the actual size by 1px. crbug.com/470503
-  rect.Intersect(GetDocument().View()->ContentsToViewport(
-      RoundedIntRect(GetLayoutObject()->AbsoluteBoundingBoxFloatRect())));
-  return rect;
+  LayoutRect rect(
+      RoundedIntRect(GetLayoutObject()->AbsoluteBoundingBoxFloatRect()));
+  LayoutRect frame_clip_rect =
+      GetDocument().View()->GetLayoutBox()->ClippingRect(LayoutPoint());
+  rect.Intersect(frame_clip_rect);
+
+  // MapToVisualRectInAncestorSpace, called with a null ancestor argument,
+  // returns the viewport-visible rect in the local frame root's coordinates,
+  // accounting for clips and transformed in embedding containers. This
+  // includes clips that might be applied by out-of-process frame ancestors.
+  GetDocument().View()->GetLayoutView()->MapToVisualRectInAncestorSpace(
+      nullptr, rect, kUseTransforms | kTraverseDocumentBoundaries,
+      kDefaultVisualRectFlags);
+
+  IntRect visible_rect = PixelSnappedIntRect(rect);
+  // If the rect is in the coordinates of the main frame, then it should
+  // also be clipped to the viewport to account for page scale. For OOPIFs,
+  // local frame root -> viewport coordinate conversion is done in the
+  // browser process.
+  if (GetDocument().GetFrame()->LocalFrameRoot().IsMainFrame()) {
+    IntSize viewport_size = GetDocument().GetPage()->GetVisualViewport().Size();
+    visible_rect =
+        GetDocument().GetPage()->GetVisualViewport().RootFrameToViewport(
+            visible_rect);
+    visible_rect.Intersect(IntRect(IntPoint(), viewport_size));
+  }
+  return visible_rect;
 }
 
 void Element::ClientQuads(Vector<FloatQuad>& quads) {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 2d863ee..67433507 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -281,9 +281,12 @@
   virtual void scrollTo(const ScrollToOptions&);
 
   IntRect BoundsInViewport() const;
-  // Returns an intersection rectangle of the bounds rectangle and the
-  // viewport rectangle, in the visual viewport coordinate. This function is
-  // used to show popups beside this element.
+  // For elements that are not contained in any OOPIFs, this returns an
+  // intersection rectangle of the bounds rectangle and the viewport
+  // rectangle, in the visual viewport coordinate. For elements within OOPIFs,
+  // the returned rect is the intersection with the viewport but in the
+  // coordinate space of the local frame root.
+  // This function is used to show popups beside this element.
   IntRect VisibleBoundsInVisualViewport() const;
 
   DOMRectList* getClientRects();
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index 2600295..09abcec 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -325,8 +325,10 @@
   return frame->PageZoomFactor();
 }
 
-void WebPluginContainerImpl::SetWebLayer(WebLayer* layer) {
-  if (web_layer_ == layer)
+void WebPluginContainerImpl::SetWebLayer(WebLayer* layer,
+                                         bool prevent_contents_opaque_changes) {
+  if (web_layer_ == layer &&
+      prevent_contents_opaque_changes == prevent_contents_opaque_changes_)
     return;
 
   if (web_layer_)
@@ -335,6 +337,7 @@
     GraphicsLayer::RegisterContentsLayer(layer);
 
   web_layer_ = layer;
+  prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
 
   if (element_)
     element_->SetNeedsCompositingUpdate();
@@ -693,6 +696,11 @@
   return web_layer_;
 }
 
+bool WebPluginContainerImpl::PreventContentsOpaqueChangesToPlatformLayer()
+    const {
+  return prevent_contents_opaque_changes_;
+}
+
 v8::Local<v8::Object> WebPluginContainerImpl::ScriptableObject(
     v8::Isolate* isolate) {
   // With Oilpan, on plugin element detach dispose() will be called to safely
@@ -737,6 +745,7 @@
       web_plugin_(web_plugin),
       web_layer_(nullptr),
       touch_event_request_type_(kTouchEventRequestTypeNone),
+      prevent_contents_opaque_changes_(false),
       wants_wheel_events_(false),
       self_visible_(false),
       parent_visible_(false),
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
index c33ab33e..5290f85 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.h
@@ -102,6 +102,7 @@
   void Hide() override;
 
   WebLayer* PlatformLayer() const;
+  bool PreventContentsOpaqueChangesToPlatformLayer() const;
   v8::Local<v8::Object> ScriptableObject(v8::Isolate*);
   bool SupportsKeyboardFocus() const;
   bool SupportsInputMethod() const;
@@ -147,7 +148,7 @@
   float PageScaleFactor() override;
   float PageZoomFactor() override;
 
-  void SetWebLayer(WebLayer*) override;
+  void SetWebLayer(WebLayer*, bool prevent_contents_opaque_changes) override;
 
   void RequestFullscreen() override;
   bool IsFullscreenElement() const override;
@@ -234,6 +235,7 @@
   WebLayer* web_layer_;
   IntRect frame_rect_;
   TouchEventRequestType touch_event_request_type_;
+  bool prevent_contents_opaque_changes_;
   bool wants_wheel_events_;
   bool self_visible_;
   bool parent_visible_;
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
index e43a87ef..1210242 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -1334,12 +1334,12 @@
   bool Initialize(WebPluginContainer* container) override {
     if (!FakeWebPlugin::Initialize(container))
       return false;
-    container->SetWebLayer(layer_.get());
+    container->SetWebLayer(layer_.get(), false);
     return true;
   }
 
   void Destroy() override {
-    Container()->SetWebLayer(nullptr);
+    Container()->SetWebLayer(nullptr, false);
     FakeWebPlugin::Destroy();
   }
 
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
index db660a3..dcf6140 100644
--- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.cc
@@ -183,11 +183,12 @@
   return child;
 }
 
-void WebRemoteFrameImpl::SetWebLayer(WebLayer* layer) {
+void WebRemoteFrameImpl::SetWebLayer(WebLayer* layer,
+                                     bool prevent_contents_opaque_changes) {
   if (!GetFrame())
     return;
 
-  GetFrame()->SetWebLayer(layer);
+  GetFrame()->SetWebLayer(layer, prevent_contents_opaque_changes);
 }
 
 void WebRemoteFrameImpl::SetCoreFrame(RemoteFrame* frame) {
diff --git a/third_party/blink/renderer/core/exported/web_remote_frame_impl.h b/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
index dcdccee..a7fd042 100644
--- a/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
+++ b/third_party/blink/renderer/core/exported/web_remote_frame_impl.h
@@ -56,7 +56,7 @@
                                     const ParsedFeaturePolicy&,
                                     WebRemoteFrameClient*,
                                     WebFrame* opener) override;
-  void SetWebLayer(WebLayer*) override;
+  void SetWebLayer(WebLayer*, bool prevent_contents_opaque_changes) override;
   void SetReplicatedOrigin(
       const WebSecurityOrigin&,
       bool is_potentially_trustworthy_unique_origin) override;
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index a65038b..867d7a1 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -108,7 +108,7 @@
   // of all these objects. Break the cycle by notifying of detachment.
   ToRemoteDOMWindow(dom_window_)->FrameDetached();
   if (web_layer_)
-    SetWebLayer(nullptr);
+    SetWebLayer(nullptr, false);
   Frame::Detach(type);
 }
 
@@ -172,10 +172,12 @@
   return static_cast<RemoteFrameClient*>(Frame::Client());
 }
 
-void RemoteFrame::SetWebLayer(WebLayer* web_layer) {
+void RemoteFrame::SetWebLayer(WebLayer* web_layer,
+                              bool prevent_contents_opaque_changes) {
   if (web_layer_)
     GraphicsLayer::UnregisterContentsLayer(web_layer_);
   web_layer_ = web_layer;
+  prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
   if (web_layer_)
     GraphicsLayer::RegisterContentsLayer(web_layer_);
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index 5edd418b..0aa8d936 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -41,8 +41,11 @@
   void DidResume() override;
   void SetIsInert(bool) override;
 
-  void SetWebLayer(WebLayer*);
+  void SetWebLayer(WebLayer*, bool prevent_contents_opaque_changes);
   WebLayer* GetWebLayer() const { return web_layer_; }
+  bool WebLayerHasFixedContentsOpaque() const {
+    return prevent_contents_opaque_changes_;
+  }
 
   void AdvanceFocus(WebFocusType, LocalFrame* source);
 
@@ -66,6 +69,7 @@
   Member<RemoteFrameView> view_;
   Member<RemoteSecurityContext> security_context_;
   WebLayer* web_layer_ = nullptr;
+  bool prevent_contents_opaque_changes_ = false;
 };
 
 inline RemoteFrameView* RemoteFrame::View() const {
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.cc b/third_party/blink/renderer/core/frame/visual_viewport.cc
index d7502963..a8e290b 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport.cc
@@ -471,7 +471,8 @@
     // by default so scrollbars don't show up in layout tests.
     web_scrollbar_layer->Layer()->SetOpacity(0);
     scrollbar_graphics_layer->SetContentsToPlatformLayer(
-        web_scrollbar_layer->Layer());
+        web_scrollbar_layer->Layer(),
+        /*prevent_contents_opaque_changes=*/false);
     scrollbar_graphics_layer->SetDrawsContent(false);
     web_scrollbar_layer->SetScrollLayer(
         inner_viewport_scroll_layer_->PlatformLayer());
diff --git a/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index 5f35204..061c513b 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -1598,6 +1598,10 @@
 }
 
 TEST_P(VisualViewportTest, ElementVisibleBoundsInVisualViewport) {
+  // VisibleBoundsInVisualViewport() assumes root layer scrolling is enabled.
+  if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled())
+    return;
+
   InitializeWithAndroidSettings();
   WebView()->Resize(IntSize(640, 1080));
   RegisterMockedHttpURLLoad("viewport-select.html");
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index fac87e2..1e46e1b 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -5537,7 +5537,7 @@
       optional integer width
       # Frame height in DIP (headless chrome only).
       optional integer height
-      # The browser context to create the page in.
+      # The browser context to create the page in (headless chrome only).
       optional BrowserContextID browserContextId
       # Whether BeginFrames for this target will be controlled via DevTools (headless chrome only,
       # not supported on MacOS yet, false by default).
@@ -5554,11 +5554,12 @@
       # Deprecated.
       deprecated optional TargetID targetId
 
-  # Deletes a BrowserContext. All the belonging pages will be closed without calling their
-  # beforeunload hooks.
+  # Deletes a BrowserContext, will fail of any open page uses it.
   experimental command disposeBrowserContext
     parameters
       BrowserContextID browserContextId
+    returns
+      boolean success
 
   # Returns information about a target.
   experimental command getTargetInfo
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index e5bdbc84..a711c24 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -2328,7 +2328,7 @@
           needs_paint_property_update_(true),
           subtree_needs_paint_property_update_(true),
           descendant_needs_paint_property_update_(true),
-          background_changed_since_last_paint_invalidation_(false),
+          background_changed_since_last_paint_invalidation_(true),
           outline_may_be_affected_by_descendants_(false),
           previous_outline_may_be_affected_by_descendants_(false),
           is_truncated_(false),
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
index 6c65aee99..41b5da1 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.cc
@@ -367,7 +367,7 @@
 static void DetachScrollbarLayer(GraphicsLayer* scrollbar_graphics_layer) {
   DCHECK(scrollbar_graphics_layer);
 
-  scrollbar_graphics_layer->SetContentsToPlatformLayer(nullptr);
+  scrollbar_graphics_layer->SetContentsToPlatformLayer(nullptr, false);
   scrollbar_graphics_layer->SetDrawsContent(true);
 }
 
@@ -383,7 +383,7 @@
   }
   scrollbar_layer->SetScrollLayer(scroll_layer);
   scrollbar_graphics_layer->SetContentsToPlatformLayer(
-      scrollbar_layer->Layer());
+      scrollbar_layer->Layer(), /*prevent_contents_opaque_changes=*/false);
   scrollbar_graphics_layer->SetDrawsContent(false);
 }
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index ef65db7..f21c20a 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -159,12 +159,10 @@
   return ContentsRect(layout_object).Contains(BackgroundRect(layout_object));
 }
 
-static WebLayer* PlatformLayerForPlugin(LayoutObject& layout_object) {
+static WebPluginContainerImpl* GetPluginContainer(LayoutObject& layout_object) {
   if (!layout_object.IsEmbeddedObject())
     return nullptr;
-  WebPluginContainerImpl* plugin =
-      ToLayoutEmbeddedObject(layout_object).Plugin();
-  return plugin ? plugin->PlatformLayer() : nullptr;
+  return ToLayoutEmbeddedObject(layout_object).Plugin();
 }
 
 static inline bool IsAcceleratedContents(LayoutObject& layout_object) {
@@ -831,30 +829,39 @@
     }
   }
 
-  if (WebLayer* layer = PlatformLayerForPlugin(layout_object)) {
-    graphics_layer_->SetContentsToPlatformLayer(layer);
+  if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) {
+    graphics_layer_->SetContentsToPlatformLayer(
+        plugin->PlatformLayer(),
+        plugin->PreventContentsOpaqueChangesToPlatformLayer());
   } else if (layout_object.GetNode() &&
              layout_object.GetNode()->IsFrameOwnerElement() &&
              ToHTMLFrameOwnerElement(layout_object.GetNode())->ContentFrame()) {
     Frame* frame =
         ToHTMLFrameOwnerElement(layout_object.GetNode())->ContentFrame();
     if (frame->IsRemoteFrame()) {
-      WebLayer* layer = ToRemoteFrame(frame)->GetWebLayer();
-      graphics_layer_->SetContentsToPlatformLayer(layer);
+      RemoteFrame* remote = ToRemoteFrame(frame);
+      WebLayer* layer = remote->GetWebLayer();
+      graphics_layer_->SetContentsToPlatformLayer(
+          layer, remote->WebLayerHasFixedContentsOpaque());
     }
   } else if (layout_object.IsVideo()) {
     HTMLMediaElement* media_element =
         ToHTMLMediaElement(layout_object.GetNode());
-    graphics_layer_->SetContentsToPlatformLayer(media_element->PlatformLayer());
+    graphics_layer_->SetContentsToPlatformLayer(
+        media_element->PlatformLayer(),
+        /*prevent_contents_opaque_changes=*/true);
   } else if (IsSurfaceLayerCanvas(layout_object)) {
     HTMLCanvasElement* canvas = ToHTMLCanvasElement(layout_object.GetNode());
     graphics_layer_->SetContentsToPlatformLayer(
-        canvas->SurfaceLayerBridge()->GetWebLayer());
+        canvas->SurfaceLayerBridge()->GetWebLayer(),
+        /*prevent_contents_opaque_changes=*/false);
     layer_config_changed = true;
   } else if (IsTextureLayerCanvas(layout_object)) {
     HTMLCanvasElement* canvas = ToHTMLCanvasElement(layout_object.GetNode());
-    if (CanvasRenderingContext* context = canvas->RenderingContext())
-      graphics_layer_->SetContentsToPlatformLayer(context->PlatformLayer());
+    if (CanvasRenderingContext* context = canvas->RenderingContext()) {
+      graphics_layer_->SetContentsToPlatformLayer(
+          context->PlatformLayer(), /*prevent_contents_opaque_changes=*/false);
+    }
     layer_config_changed = true;
   }
   if (layout_object.IsLayoutEmbeddedContent()) {
diff --git a/third_party/blink/renderer/devtools/front_end/Tests.js b/third_party/blink/renderer/devtools/front_end/Tests.js
index 572ba99..add96169 100644
--- a/third_party/blink/renderer/devtools/front_end/Tests.js
+++ b/third_party/blink/renderer/devtools/front_end/Tests.js
@@ -1125,12 +1125,13 @@
     this.assertEquals(await evalCode(target2, 'localStorage.getItem("page1")'), null);
     this.assertEquals(await evalCode(target2, 'localStorage.getItem("page2")'), 'page2');
 
-    const removedTargets = [];
-    SDK.targetManager.observeTargets({targetAdded: () => {}, targetRemoved: target => removedTargets.push(target)});
-    await Promise.all([disposeBrowserContext(browserContextIds[0]), disposeBrowserContext(browserContextIds[1])]);
-    this.assertEquals(removedTargets.length, 2);
-    this.assertEquals(removedTargets.indexOf(target1) !== -1, true);
-    this.assertEquals(removedTargets.indexOf(target2) !== -1, true);
+    this.assertEquals(await disposeBrowserContext(browserContextIds[0]), false);
+    this.assertEquals(await disposeBrowserContext(browserContextIds[1]), false);
+
+    await closeTarget(target1);
+    await closeTarget(target2);
+    this.assertEquals(await disposeBrowserContext(browserContextIds[0]), true);
+    this.assertEquals(await disposeBrowserContext(browserContextIds[1]), true);
 
     this.releaseControl();
 
@@ -1153,9 +1154,15 @@
       return target;
     }
 
+    async function closeTarget(target) {
+      const targetAgent = SDK.targetManager.mainTarget().targetAgent();
+      await targetAgent.invoke_closeTarget({targetId: target.id()});
+    }
+
     async function disposeBrowserContext(browserContextId) {
       const targetAgent = SDK.targetManager.mainTarget().targetAgent();
-      await targetAgent.invoke_disposeBrowserContext({browserContextId});
+      const {success} = await targetAgent.invoke_disposeBrowserContext({browserContextId});
+      return success;
     }
 
     async function evalCode(target, code) {
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsolePrompt.js b/third_party/blink/renderer/devtools/front_end/console/ConsolePrompt.js
index edb272f..4a50380 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsolePrompt.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsolePrompt.js
@@ -46,17 +46,18 @@
       delete this._initialText;
       if (this.hasFocus())
         this.focus();
-      this.element.tabIndex = -1;
+      this.element.removeAttribute('tabindex');
+      this._editor.widget().element.tabIndex = -1;
 
       this._editorSetForTest();
     }
   }
 
   /**
-   * @return {number}
+   * @return {!Element}
    */
-  heightBelowEditor() {
-    return this._eagerPreviewElement.offsetHeight;
+  belowEditorElement() {
+    return this._eagerPreviewElement;
   }
 
   _onTextChanged() {
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
index bd259ed..d801337 100644
--- a/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
+++ b/third_party/blink/renderer/devtools/front_end/console/ConsoleView.js
@@ -833,9 +833,11 @@
    * @param {!Event} event
    */
   _messagesClicked(event) {
+    const target = /** @type {?Node} */ (event.target);
     // Do not focus prompt if messages have selection.
     if (!this._messagesElement.hasSelection()) {
-      const clickedOutsideMessageList = event.target === this._messagesElement;
+      const clickedOutsideMessageList =
+          target === this._messagesElement || this._prompt.belowEditorElement().isSelfOrAncestor(target);
       if (clickedOutsideMessageList)
         this._prompt.moveCaretToEndOfPrompt();
       this.focus();
@@ -1168,7 +1170,7 @@
     if (!this._isBelowPromptEnabled)
       return this._messagesElement.isScrolledToBottom();
     const distanceToPromptEditorBottom = this._messagesElement.scrollHeight - this._messagesElement.scrollTop -
-        this._messagesElement.clientHeight - this._prompt.heightBelowEditor();
+        this._messagesElement.clientHeight - this._prompt.belowEditorElement().offsetHeight;
     return distanceToPromptEditorBottom <= 2;
   }
 };
diff --git a/third_party/blink/renderer/devtools/front_end/externs.js b/third_party/blink/renderer/devtools/front_end/externs.js
index df8a357..b363c2c 100644
--- a/third_party/blink/renderer/devtools/front_end/externs.js
+++ b/third_party/blink/renderer/devtools/front_end/externs.js
@@ -526,7 +526,7 @@
   setHistory: function(histData) {},
   setLine: function(line, text) {},
   setOption: function(option, value) {},
-  setSelection: function(anchor, head) {},
+  setSelection: function(anchor, head, options) {},
   /**
    * @param {number=} primaryIndex
    * @param {?Object=} config
diff --git a/third_party/blink/renderer/devtools/front_end/main/Main.js b/third_party/blink/renderer/devtools/front_end/main/Main.js
index c25eb1d..693f3829 100644
--- a/third_party/blink/renderer/devtools/front_end/main/Main.js
+++ b/third_party/blink/renderer/devtools/front_end/main/Main.js
@@ -108,7 +108,7 @@
     Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
     Runtime.experiments.register('blackboxJSFramesOnTimeline', 'Blackbox JavaScript frames on Timeline', true);
     Runtime.experiments.register('colorContrastRatio', 'Color contrast ratio line in color picker', true);
-    Runtime.experiments.register('consoleBelowPrompt', 'Console below-prompt UI', true);
+    Runtime.experiments.register('consoleBelowPrompt', 'Eager evaluation');
     Runtime.experiments.register('emptySourceMapAutoStepping', 'Empty sourcemap auto-stepping');
     Runtime.experiments.register('inputEventsOnTimelineOverview', 'Input events on Timeline overview', true);
     Runtime.experiments.register('nativeHeapProfiler', 'Native memory sampling heap profiler', true);
diff --git a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
index ca4d3be1..e37467a5 100644
--- a/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
+++ b/third_party/blink/renderer/devtools/front_end/object_ui/ObjectPropertiesSection.js
@@ -801,11 +801,11 @@
     const name = this.property.name;
     const parentPath = this.parent.nameElement ? this.parent.nameElement.title : '';
     if (useDotNotation.test(name))
-      this.nameElement.title = parentPath + '.' + name;
+      this.nameElement.title = parentPath ? `${parentPath}.${name}` : name;
     else if (isInteger.test(name))
       this.nameElement.title = parentPath + '[' + name + ']';
     else
-      this.nameElement.title = parentPath + '["' + name + '"]';
+      this.nameElement.title = parentPath + '["' + JSON.stringify(name) + '"]';
   }
 
   /**
@@ -813,6 +813,7 @@
    */
   _contextMenuFired(event) {
     const contextMenu = new UI.ContextMenu(event);
+    contextMenu.appendApplicableItems(this);
     if (this.property.symbol)
       contextMenu.appendApplicableItems(this.property.symbol);
     if (this.property.value)
@@ -962,6 +963,13 @@
       this.setExpandable(false);
     }
   }
+
+  /**
+   * @return {string}
+   */
+  path() {
+    return this.nameElement.title;
+  }
 };
 
 
diff --git a/third_party/blink/renderer/devtools/front_end/source_frame/SourceFrame.js b/third_party/blink/renderer/devtools/front_end/source_frame/SourceFrame.js
index 44d1806..740e181 100644
--- a/third_party/blink/renderer/devtools/front_end/source_frame/SourceFrame.js
+++ b/third_party/blink/renderer/devtools/front_end/source_frame/SourceFrame.js
@@ -110,12 +110,32 @@
     this._prettyToggle.setToggled(value);
     this._prettyToggle.setEnabled(false);
 
+    const wasLoaded = this.loaded;
     const selection = this.selection();
+    let newSelection;
     if (this._pretty && this._rawContent) {
       this.setContent(await this._requestFormattedContent());
       const start = this._rawToPrettyLocation(selection.startLine, selection.startColumn);
       const end = this._rawToPrettyLocation(selection.endLine, selection.endColumn);
-      this.setSelection(new TextUtils.TextRange(start[0], start[1], end[0], end[1]));
+      newSelection = new TextUtils.TextRange(start[0], start[1], end[0], end[1]);
+    } else {
+      this.setContent(this._rawContent);
+      const start = this._prettyToRawLocation(selection.startLine, selection.startColumn);
+      const end = this._prettyToRawLocation(selection.endLine, selection.endColumn);
+      newSelection = new TextUtils.TextRange(start[0], start[1], end[0], end[1]);
+    }
+    if (wasLoaded) {
+      this.textEditor.revealPosition(newSelection.endLine, newSelection.endColumn, this._editable);
+      this.textEditor.setSelection(newSelection);
+    }
+    this._prettyToggle.setEnabled(true);
+    this._updatePrettyPrintState();
+  }
+
+  _updatePrettyPrintState() {
+    this._prettyToggle.setToggled(this._pretty);
+    this._textEditor.element.classList.toggle('pretty-printed', this._pretty);
+    if (this._pretty) {
       this._textEditor.setLineNumberFormatter(lineNumber => {
         const line = this._prettyToRawLocation(lineNumber - 1, 0)[0] + 1;
         if (lineNumber === 1)
@@ -128,12 +148,7 @@
       this._textEditor.setLineNumberFormatter(lineNumber => {
         return String(lineNumber);
       });
-      this.setContent(this._rawContent);
-      const start = this._prettyToRawLocation(selection.startLine, selection.startColumn);
-      const end = this._prettyToRawLocation(selection.endLine, selection.endColumn);
-      this.setSelection(new TextUtils.TextRange(start[0], start[1], end[0], end[1]));
     }
-    this._prettyToggle.setEnabled(true);
   }
 
   /**
@@ -294,7 +309,7 @@
 
   _innerSetSelectionIfNeeded() {
     if (this._selectionToSet && this.loaded && this.isShowing()) {
-      this._textEditor.setSelection(this._selectionToSet);
+      this._textEditor.setSelection(this._selectionToSet, true);
       this._selectionToSet = null;
     }
   }
diff --git a/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js b/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
index 320aef7c..c5462594 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
+++ b/third_party/blink/renderer/devtools/front_end/sources/WatchExpressionsSidebarPane.js
@@ -180,6 +180,23 @@
   }
 
   /**
+   * @param {string} expression
+   */
+  _focusAndAddExpressionToWatch(expression) {
+    UI.viewManager.showView('sources.watch');
+    this.doUpdate();
+    this._addExpressionToWatch(expression);
+  }
+
+  /**
+   * @param {string} expression
+   */
+  _addExpressionToWatch(expression) {
+    this._createWatchExpression(expression);
+    this._saveExpressions();
+  }
+
+  /**
    * @override
    * @param {!UI.Context} context
    * @param {string} actionId
@@ -190,20 +207,29 @@
     if (!frame)
       return false;
     const text = frame.textEditor.text(frame.textEditor.selection());
-    UI.viewManager.showView('sources.watch');
-    this.doUpdate();
-    this._createWatchExpression(text);
-    this._saveExpressions();
+    this._focusAndAddExpressionToWatch(text);
     return true;
   }
 
   /**
+   * @param {!ObjectUI.ObjectPropertyTreeElement} target
+   */
+  _addPropertyPathToWatch(target) {
+    this._addExpressionToWatch(target.path());
+  }
+
+  /**
    * @override
    * @param {!Event} event
    * @param {!UI.ContextMenu} contextMenu
    * @param {!Object} target
    */
   appendApplicableItems(event, contextMenu, target) {
+    if (target instanceof ObjectUI.ObjectPropertyTreeElement) {
+      contextMenu.debugSection().appendItem(
+          ls`Add property path to watch`, this._addPropertyPathToWatch.bind(this, target));
+    }
+
     const frame = UI.context.flavor(Sources.UISourceCodeFrame);
     if (!frame || frame.textEditor.selection().isEmpty())
       return;
diff --git a/third_party/blink/renderer/devtools/front_end/sources/module.json b/third_party/blink/renderer/devtools/front_end/sources/module.json
index aed8aea..bbb61d2 100644
--- a/third_party/blink/renderer/devtools/front_end/sources/module.json
+++ b/third_party/blink/renderer/devtools/front_end/sources/module.json
@@ -197,6 +197,15 @@
         },
         {
             "type": "@UI.ContextMenu.Provider",
+            "actionId": "sources.add-to-watch",
+            "className": "Sources.WatchExpressionsSidebarPane",
+            "title": "Add to watch",
+            "contextTypes": [
+                "ObjectUI.ObjectPropertyTreeElement"
+            ]
+        },
+        {
+            "type": "@UI.ContextMenu.Provider",
             "contextTypes": [
                 "TextEditor.CodeMirrorTextEditor"
             ],
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
index 2b74611..f5605569 100644
--- a/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
+++ b/third_party/blink/renderer/devtools/front_end/text_editor/CodeMirrorTextEditor.js
@@ -1163,15 +1163,16 @@
   /**
    * @override
    * @param {!TextUtils.TextRange} textRange
+   * @param {boolean=} dontScroll
    */
-  setSelection(textRange) {
+  setSelection(textRange, dontScroll) {
     this._lastSelection = textRange;
     if (!this._editorSizeInSync) {
       this._selectionSetScheduled = true;
       return;
     }
     const pos = TextEditor.CodeMirrorUtils.toPos(textRange);
-    this._codeMirror.setSelection(pos.start, pos.end);
+    this._codeMirror.setSelection(pos.start, pos.end, {scroll: !dontScroll});
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css b/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
index 5ff40d8..e451a8f 100644
--- a/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
+++ b/third_party/blink/renderer/devtools/front_end/text_editor/cmdevtools.css
@@ -546,3 +546,7 @@
 .CodeMirror-composing {
     border-bottom: 2px solid;
 }
+
+.pretty-printed .CodeMirror-linenumber {
+    color: var(--accent-color-b);
+}
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index 799a5303..41deb4a 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -89,6 +89,7 @@
       blend_mode_(BlendMode::kNormal),
       has_transform_origin_(false),
       contents_opaque_(false),
+      prevent_contents_opaque_changes_(false),
       should_flatten_transform_(true),
       backface_visibility_(true),
       draws_content_(false),
@@ -493,7 +494,8 @@
   layer->SetLayerClient(nullptr);
 }
 
-void GraphicsLayer::SetContentsTo(WebLayer* layer) {
+void GraphicsLayer::SetContentsTo(WebLayer* layer,
+                                  bool prevent_contents_opaque_changes) {
   bool children_changed = false;
   if (layer) {
     DCHECK(g_registered_layer_set);
@@ -503,6 +505,7 @@
       children_changed = true;
     }
     UpdateContentsRect();
+    prevent_contents_opaque_changes_ = prevent_contents_opaque_changes;
   } else {
     if (contents_layer_) {
       children_changed = true;
@@ -1101,7 +1104,7 @@
   contents_opaque_ = opaque;
   layer_->Layer()->SetOpaque(contents_opaque_);
   ClearContentsLayerIfUnregistered();
-  if (contents_layer_)
+  if (contents_layer_ && !prevent_contents_opaque_changes_)
     contents_layer_->SetOpaque(opaque);
 }
 
@@ -1260,7 +1263,7 @@
     image_layer_.reset();
   }
 
-  SetContentsTo(image_layer_ ? image_layer_->Layer() : nullptr);
+  SetContentsTo(image_layer_ ? image_layer_->Layer() : nullptr, true);
 }
 
 WebLayer* GraphicsLayer::PlatformLayer() const {
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.h b/third_party/blink/renderer/platform/graphics/graphics_layer.h
index d179891..59cff46 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.h
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.h
@@ -171,7 +171,7 @@
   Color BackgroundColor() const { return background_color_; }
   void SetBackgroundColor(const Color&);
 
-  // opaque means that we know the layer contents have no alpha
+  // Opaque means that we know the layer contents have no alpha.
   bool ContentsOpaque() const { return contents_opaque_; }
   void SetContentsOpaque(bool);
 
@@ -216,7 +216,14 @@
       Image*,
       Image::ImageDecodingMode decode_mode,
       RespectImageOrientationEnum = kDoNotRespectImageOrientation);
-  void SetContentsToPlatformLayer(WebLayer* layer) { SetContentsTo(layer); }
+  // If |prevent_contents_opaque_changes| is set to true, then calls to
+  // SetContentsOpaque() will not be passed on to the |layer|. Use when
+  // the client wants to have control of the opaqueness of the contents
+  // |layer| independently of what outcome painting produces.
+  void SetContentsToPlatformLayer(WebLayer* layer,
+                                  bool prevent_contents_opaque_changes) {
+    SetContentsTo(layer, prevent_contents_opaque_changes);
+  }
   bool HasContentsLayer() const { return contents_layer_; }
 
   // For hosting this GraphicsLayer in a native layer hierarchy.
@@ -343,7 +350,7 @@
   void UpdateLayerIsDrawable();
   void UpdateContentsRect();
 
-  void SetContentsTo(WebLayer*);
+  void SetContentsTo(WebLayer*, bool prevent_contents_opaque_changes);
   void SetupContentsLayer(WebLayer*);
   void ClearContentsLayerIfUnregistered();
   WebLayer* ContentsLayerIfRegistered();
@@ -385,6 +392,7 @@
 
   bool has_transform_origin_ : 1;
   bool contents_opaque_ : 1;
+  bool prevent_contents_opaque_changes_ : 1;
   bool should_flatten_transform_ : 1;
   bool backface_visibility_ : 1;
   bool draws_content_ : 1;
@@ -414,10 +422,10 @@
   std::unique_ptr<WebContentLayer> layer_;
   std::unique_ptr<WebImageLayer> image_layer_;
   WebLayer* contents_layer_;
-  // We don't have ownership of m_contentsLayer, but we do want to know if a
-  // given layer is the same as our current layer in setContentsTo(). Since
-  // |m_contentsLayer| may be deleted at this point, we stash an ID away when we
-  // know |m_contentsLayer| is alive and use that for comparisons from that
+  // We don't have ownership of contents_layer_, but we do want to know if a
+  // given layer is the same as our current layer in SetContentsTo(). Since
+  // |contents_layer_| may be deleted at this point, we stash an ID away when we
+  // know |contents_layer_| is alive and use that for comparisons from that
   // point on.
   int contents_layer_id_;
 
diff --git a/tools/cfi/blacklist.txt b/tools/cfi/blacklist.txt
index 03de7354..d7b086b 100644
--- a/tools/cfi/blacklist.txt
+++ b/tools/cfi/blacklist.txt
@@ -184,6 +184,10 @@
 # Call to libcurl.so from the symupload utility
 src:*third_party/breakpad/breakpad/src/common/linux/http_upload.cc
 
+# The Kerberos code includes calls to dynamically resolved functions; however,
+# the unit tests do not exercise those code paths. Be careful removing.
+src:*net/http/http_auth_gssapi_posix.cc
+
 ######### Function pointers cast to incorrect type signatures
 
 # libicu is currently compiled such that in libicu the 'UChar' type is a
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index 314df30..58d016c 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -110,7 +110,10 @@
 # Name of the final profdata file, and this file needs to be passed to
 # "llvm-cov" command in order to call "llvm-cov show" to inspect the
 # line-by-line coverage of specific files.
-PROFDATA_FILE_NAME = 'coverage.profdata'
+PROFDATA_FILE_NAME = os.extsep.join(['coverage', 'profdata'])
+
+# Name of the file with summary information generated by llvm-cov export.
+SUMMARY_FILE_NAME = os.extsep.join(['summary', 'json'])
 
 # Build arg required for generating code coverage data.
 CLANG_COVERAGE_BUILD_ARG = 'use_clang_coverage'
@@ -119,9 +122,12 @@
 DIRECTORY_COVERAGE_HTML_REPORT_NAME = os.extsep.join(['report', 'html'])
 
 # Name of the html index files for different views.
-DIRECTORY_VIEW_INDEX_FILE = os.extsep.join(['directory_view_index', 'html'])
 COMPONENT_VIEW_INDEX_FILE = os.extsep.join(['component_view_index', 'html'])
+DIRECTORY_VIEW_INDEX_FILE = os.extsep.join(['directory_view_index', 'html'])
 FILE_VIEW_INDEX_FILE = os.extsep.join(['file_view_index', 'html'])
+INDEX_HTML_FILE = os.extsep.join(['index', 'html'])
+
+LOGS_DIR_NAME = 'logs'
 
 # Used to extract a mapping between directories and components.
 COMPONENT_MAPPING_URL = 'https://storage.googleapis.com/chromium-owners/component_map.json'
@@ -187,10 +193,10 @@
                         header. For example: 'Path', 'Component'.
     """
     css_file_name = os.extsep.join(['style', 'css'])
-    css_absolute_path = os.path.abspath(os.path.join(OUTPUT_DIR, css_file_name))
+    css_absolute_path = os.path.join(OUTPUT_DIR, css_file_name)
     assert os.path.exists(css_absolute_path), (
         'css file doesn\'t exit. Please make sure "llvm-cov show -format=html" '
-        'is called first, and the css file is generated at: "%s"' %
+        'is called first, and the css file is generated at: "%s".' %
         css_absolute_path)
 
     self._css_absolute_path = css_absolute_path
@@ -275,7 +281,7 @@
     if percentage == 100:
       return 'green'
 
-    assert False, 'Invalid coverage percentage: "%d"' % percentage
+    assert False, 'Invalid coverage percentage: "%d".' % percentage
 
   def WriteHtmlCoverageReport(self):
     """Writes html coverage report.
@@ -294,9 +300,10 @@
     self._table_entries = sorted(self._table_entries, cmp=EntryCmp)
 
     css_path = os.path.join(OUTPUT_DIR, os.extsep.join(['style', 'css']))
-    directory_view_path = os.path.join(OUTPUT_DIR, DIRECTORY_VIEW_INDEX_FILE)
-    component_view_path = os.path.join(OUTPUT_DIR, COMPONENT_VIEW_INDEX_FILE)
-    file_view_path = os.path.join(OUTPUT_DIR, FILE_VIEW_INDEX_FILE)
+
+    directory_view_path = _GetDirectoryViewPath()
+    component_view_path = _GetComponentViewPath()
+    file_view_path = _GetFileViewPath()
 
     html_header = self._header_template.render(
         css_path=_GetRelativePathToDirectoryOfFile(css_path, self._output_path),
@@ -339,7 +346,7 @@
     cmd.extend(['otool', '-L'])
     shared_library_re = re.compile(r'\s+(@rpath/.*\.dylib)\s.*')
   else:
-    assert False, ('Cannot detect shared libraries used by the given targets.')
+    assert False, 'Cannot detect shared libraries used by the given targets.'
 
   assert shared_library_re is not None
 
@@ -458,7 +465,7 @@
   try:
     clang_update.DownloadAndUnpack(coverage_tools_url,
                                    clang_update.LLVM_BUILD_DIR)
-    logging.info('Coverage tools %s unpacked', package_version)
+    logging.info('Coverage tools %s unpacked.', package_version)
     with open(coverage_revision_stamp_file, 'w') as file_handle:
       file_handle.write('%s,%s' % (package_version, host_platform))
       file_handle.write('\n')
@@ -485,7 +492,7 @@
   # NOTE: For object files, the first one is specified as a positional argument,
   # and the rest are specified as keyword argument.
   logging.debug('Generating per file line by line coverage reports using '
-                '"llvm-cov show" command')
+                '"llvm-cov show" command.')
   subprocess_cmd = [
       LLVM_COV_PATH, 'show', '-format=html',
       '-output-dir={}'.format(OUTPUT_DIR),
@@ -504,17 +511,15 @@
   # the platform name instead, as it simplifies the report dir structure when
   # the same report is generated for different platforms.
   default_report_subdir_path = os.path.join(OUTPUT_DIR, 'coverage')
-  platform_report_subdir_path = os.path.join(OUTPUT_DIR, _GetHostPlatform())
-  if os.path.exists(platform_report_subdir_path):
-    shutil.rmtree(platform_report_subdir_path)
-  os.rename(default_report_subdir_path, platform_report_subdir_path)
+  platform_report_subdir_path = _GetCoverageReportRootDirPath()
+  _MergeTwoDirectories(default_report_subdir_path, platform_report_subdir_path)
 
-  logging.debug('Finished running "llvm-cov show" command')
+  logging.debug('Finished running "llvm-cov show" command.')
 
 
 def _GenerateFileViewHtmlIndexFile(per_file_coverage_summary):
   """Generates html index file for file view."""
-  file_view_index_file_path = os.path.join(OUTPUT_DIR, FILE_VIEW_INDEX_FILE)
+  file_view_index_file_path = _GetFileViewPath()
   logging.debug('Generating file view html index file as: "%s".',
                 file_view_index_file_path)
   html_generator = _CoverageReportHtmlGenerator(file_view_index_file_path,
@@ -536,12 +541,13 @@
 
 def _CalculatePerDirectoryCoverageSummary(per_file_coverage_summary):
   """Calculates per directory coverage summary."""
-  logging.debug('Calculating per-directory coverage summary')
+  logging.debug('Calculating per-directory coverage summary.')
   per_directory_coverage_summary = defaultdict(lambda: _CoverageSummary())
 
   for file_path in per_file_coverage_summary:
     summary = per_file_coverage_summary[file_path]
     parent_dir = os.path.dirname(file_path)
+
     while True:
       per_directory_coverage_summary[parent_dir].AddSummary(summary)
 
@@ -549,19 +555,19 @@
         break
       parent_dir = os.path.dirname(parent_dir)
 
-  logging.debug('Finished calculating per-directory coverage summary')
+  logging.debug('Finished calculating per-directory coverage summary.')
   return per_directory_coverage_summary
 
 
 def _GeneratePerDirectoryCoverageInHtml(per_directory_coverage_summary,
                                         per_file_coverage_summary):
   """Generates per directory coverage breakdown in html."""
-  logging.debug('Writing per-directory coverage html reports')
+  logging.debug('Writing per-directory coverage html reports.')
   for dir_path in per_directory_coverage_summary:
     _GenerateCoverageInHtmlForDirectory(
         dir_path, per_directory_coverage_summary, per_file_coverage_summary)
 
-  logging.debug('Finished writing per-directory coverage html reports')
+  logging.debug('Finished writing per-directory coverage html reports.')
 
 
 def _GenerateCoverageInHtmlForDirectory(
@@ -600,8 +606,7 @@
   file simply redirects to it, and the reason of this extra layer is for
   structural consistency with other views.
   """
-  directory_view_index_file_path = os.path.join(OUTPUT_DIR,
-                                                DIRECTORY_VIEW_INDEX_FILE)
+  directory_view_index_file_path = _GetDirectoryViewPath()
   logging.debug('Generating directory view html index file as: "%s".',
                 directory_view_index_file_path)
   src_root_html_report_path = _GetCoverageHtmlReportPathForDirectory(
@@ -614,7 +619,7 @@
 def _CalculatePerComponentCoverageSummary(component_to_directories,
                                           per_directory_coverage_summary):
   """Calculates per component coverage summary."""
-  logging.debug('Calculating per-component coverage summary')
+  logging.debug('Calculating per-component coverage summary.')
   per_component_coverage_summary = defaultdict(lambda: _CoverageSummary())
 
   for component in component_to_directories:
@@ -624,7 +629,7 @@
         per_component_coverage_summary[component].AddSummary(
             per_directory_coverage_summary[absolute_directory_path])
 
-  logging.debug('Finished calculating per-component coverage summary')
+  logging.debug('Finished calculating per-component coverage summary.')
   return per_component_coverage_summary
 
 
@@ -686,8 +691,7 @@
 
 def _GenerateComponentViewHtmlIndexFile(per_component_coverage_summary):
   """Generates the html index file for component view."""
-  component_view_index_file_path = os.path.join(OUTPUT_DIR,
-                                                COMPONENT_VIEW_INDEX_FILE)
+  component_view_index_file_path = _GetComponentViewPath()
   logging.debug('Generating component view html index file as: "%s".',
                 component_view_index_file_path)
   html_generator = _CoverageReportHtmlGenerator(component_view_index_file_path,
@@ -707,12 +711,20 @@
   logging.debug('Finished generating component view html index file.')
 
 
+def _MergeTwoDirectories(src_path, dst_path):
+  """Merge src_path directory into dst_path directory."""
+  for filename in os.listdir(src_path):
+    dst_path = os.path.join(dst_path, filename)
+    if os.path.exists(dst_path):
+      shutil.rmtree(dst_path)
+    os.rename(os.path.join(src_path, filename), dst_path)
+  shutil.rmtree(src_path)
+
+
 def _OverwriteHtmlReportsIndexFile():
   """Overwrites the root index file to redirect to the default view."""
-  html_index_file_path = os.path.join(OUTPUT_DIR,
-                                      os.extsep.join(['index', 'html']))
-  directory_view_index_file_path = os.path.join(OUTPUT_DIR,
-                                                DIRECTORY_VIEW_INDEX_FILE)
+  html_index_file_path = _GetHtmlIndexPath()
+  directory_view_index_file_path = _GetDirectoryViewPath()
   _WriteRedirectHtmlFile(html_index_file_path, directory_view_index_file_path)
 
 
@@ -732,9 +744,17 @@
     f.write(content)
 
 
+def _CleanUpOutputDir():
+  """Perform a cleanup of the output dir."""
+  # Remove the default index.html file produced by llvm-cov.
+  index_path = os.path.join(OUTPUT_DIR, INDEX_HTML_FILE)
+  if os.path.exists(index_path):
+    os.remove(index_path)
+
+
 def _GetCoverageHtmlReportPathForFile(file_path):
   """Given a file path, returns the corresponding html report path."""
-  assert os.path.isfile(file_path), '"%s" is not a file' % file_path
+  assert os.path.isfile(file_path), '"%s" is not a file.' % file_path
   html_report_path = os.extsep.join([os.path.abspath(file_path), 'html'])
 
   # '+' is used instead of os.path.join because both of them are absolute paths
@@ -745,7 +765,7 @@
 
 def _GetCoverageHtmlReportPathForDirectory(dir_path):
   """Given a directory path, returns the corresponding html report path."""
-  assert os.path.isdir(dir_path), '"%s" is not a directory' % dir_path
+  assert os.path.isdir(dir_path), '"%s" is not a directory.' % dir_path
   html_report_path = os.path.join(
       os.path.abspath(dir_path), DIRECTORY_COVERAGE_HTML_REPORT_NAME)
 
@@ -765,7 +785,44 @@
 
 def _GetCoverageReportRootDirPath():
   """The root directory that contains all generated coverage html reports."""
-  return os.path.join(os.path.abspath(OUTPUT_DIR), _GetHostPlatform())
+  return os.path.join(OUTPUT_DIR, _GetHostPlatform())
+
+
+def _GetComponentViewPath():
+  """Path to the HTML file for the component view."""
+  return os.path.join(_GetCoverageReportRootDirPath(),
+                      COMPONENT_VIEW_INDEX_FILE)
+
+
+def _GetDirectoryViewPath():
+  """Path to the HTML file for the directory view."""
+  return os.path.join(_GetCoverageReportRootDirPath(),
+                      DIRECTORY_VIEW_INDEX_FILE)
+
+
+def _GetFileViewPath():
+  """Path to the HTML file for the file view."""
+  return os.path.join(_GetCoverageReportRootDirPath(), FILE_VIEW_INDEX_FILE)
+
+
+def _GetLogsDirectoryPath():
+  """Path to the logs directory."""
+  return os.path.join(_GetCoverageReportRootDirPath(), LOGS_DIR_NAME)
+
+
+def _GetHtmlIndexPath():
+  """Path to the main HTML index file."""
+  return os.path.join(_GetCoverageReportRootDirPath(), INDEX_HTML_FILE)
+
+
+def _GetProfdataFilePath():
+  """Path to the resulting .profdata file."""
+  return os.path.join(_GetCoverageReportRootDirPath(), PROFDATA_FILE_NAME)
+
+
+def _GetSummaryFilePath():
+  """The JSON file that contains coverage summary written by llvm-cov export."""
+  return os.path.join(_GetCoverageReportRootDirPath(), SUMMARY_FILE_NAME)
 
 
 def _CreateCoverageProfileDataForTargets(targets, commands, jobs_count=None):
@@ -813,7 +870,7 @@
     build_args = _GetBuildArgs()
     return 'use_goma' in build_args and build_args['use_goma'] == 'true'
 
-  logging.info('Building %s', str(targets))
+  logging.info('Building %s.', str(targets))
   if jobs_count is None and _IsGomaConfigured():
     jobs_count = DEFAULT_GOMA_JOBS
 
@@ -823,7 +880,7 @@
 
   subprocess_cmd.extend(targets)
   subprocess.check_call(subprocess_cmd)
-  logging.debug('Finished building %s', str(targets))
+  logging.debug('Finished building %s.', str(targets))
 
 
 def _GetTargetProfDataPathsByExecutingCommands(targets, commands):
@@ -836,23 +893,27 @@
   Returns:
     A list of relative paths to the generated profraw data files.
   """
-  logging.debug('Executing the test commands')
+  logging.debug('Executing the test commands.')
 
   # Remove existing profraw data files.
-  for file_or_dir in os.listdir(OUTPUT_DIR):
+  for file_or_dir in os.listdir(_GetCoverageReportRootDirPath()):
     if file_or_dir.endswith(PROFRAW_FILE_EXTENSION):
-      os.remove(os.path.join(OUTPUT_DIR, file_or_dir))
+      os.remove(os.path.join(_GetCoverageReportRootDirPath(), file_or_dir))
+
+  # Ensure that logs directory exists.
+  if not os.path.exists(_GetLogsDirectoryPath()):
+    os.makedirs(_GetLogsDirectoryPath())
 
   profdata_file_paths = []
 
   # Run all test targets to generate profraw data files.
   for target, command in zip(targets, commands):
-    output_file_name = os.extsep.join([target + '_output', 'txt'])
-    output_file_path = os.path.join(OUTPUT_DIR, output_file_name)
+    output_file_name = os.extsep.join([target + '_output', 'log'])
+    output_file_path = os.path.join(_GetLogsDirectoryPath(), output_file_name)
 
     profdata_file_path = None
     for _ in xrange(MERGE_RETRIES):
-      logging.info('Running command: "%s", the output is redirected to "%s"',
+      logging.info('Running command: "%s", the output is redirected to "%s".',
                    command, output_file_path)
 
       if _IsIOSCommand(command):
@@ -871,12 +932,13 @@
       if _IsIOS():
         profraw_file_paths = _GetProfrawDataFileByParsingOutput(output)
       else:
-        for file_or_dir in os.listdir(OUTPUT_DIR):
+        for file_or_dir in os.listdir(_GetCoverageReportRootDirPath()):
           if file_or_dir.endswith(PROFRAW_FILE_EXTENSION):
-            profraw_file_paths.append(os.path.join(OUTPUT_DIR, file_or_dir))
+            profraw_file_paths.append(
+                os.path.join(_GetCoverageReportRootDirPath(), file_or_dir))
 
       assert profraw_file_paths, (
-          'Running target %s failed to generate any profraw data file, '
+          'Running target "%s" failed to generate any profraw data file, '
           'please make sure the binary exists and is properly '
           'instrumented.' % target)
 
@@ -892,14 +954,14 @@
           os.remove(profraw_file_path)
 
     assert profdata_file_path, (
-        'Failed to merge target %s profraw files after %d retries. '
+        'Failed to merge target "%s" profraw files after %d retries. '
         'Please file a bug with command you used, commit position and args.gn '
         'config here: '
         'https://bugs.chromium.org/p/chromium/issues/entry?'
-        'components=Tools%%3ECodeCoverage'% (target, MERGE_RETRIES))
+        'components=Tools%%3ECodeCoverage' % (target, MERGE_RETRIES))
     profdata_file_paths.append(profdata_file_path)
 
-  logging.debug('Finished executing the test commands')
+  logging.debug('Finished executing the test commands.')
 
   return profdata_file_paths
 
@@ -929,16 +991,18 @@
   profile_pattern_string = '%1m' if _IsFuzzerTarget(target) else '%4m'
   expected_profraw_file_name = os.extsep.join(
       [target, profile_pattern_string, PROFRAW_FILE_EXTENSION])
-  expected_profraw_file_path = os.path.join(OUTPUT_DIR,
+  expected_profraw_file_path = os.path.join(_GetCoverageReportRootDirPath(),
                                             expected_profraw_file_name)
 
   try:
+    # Some fuzz targets or tests may write into stderr, redirect it as well.
     output = subprocess.check_output(
         shlex.split(command),
+        stderr=subprocess.STDOUT,
         env={'LLVM_PROFILE_FILE': expected_profraw_file_path})
   except subprocess.CalledProcessError as e:
     output = e.output
-    logging.warning('Command: "%s" exited with non-zero return code', command)
+    logging.warning('Command: "%s" exited with non-zero return code.', command)
 
   return output
 
@@ -1016,10 +1080,9 @@
   Raises:
     CalledProcessError: An error occurred merging profdata files.
   """
-  logging.info('Creating the coverage profile data file')
-  logging.debug(
-      'Merging target profdata files to create coverage profdata file')
-  profdata_file_path = os.path.join(OUTPUT_DIR, PROFDATA_FILE_NAME)
+  logging.info('Creating the coverage profile data file.')
+  logging.debug('Merging target profraw files to create target profdata file.')
+  profdata_file_path = _GetProfdataFilePath()
   try:
     subprocess_cmd = [
         LLVM_PROFDATA_PATH, 'merge', '-o', profdata_file_path, '-sparse=true'
@@ -1031,8 +1094,8 @@
           'Try again.')
     raise error
 
-  logging.debug('Finished merging target profdata files')
-  logging.info('Code coverage profile data is created as: %s',
+  logging.debug('Finished merging target profdata files.')
+  logging.info('Code coverage profile data is created as: "%s".',
                profdata_file_path)
   return profdata_file_path
 
@@ -1051,8 +1114,8 @@
   Raises:
     CalledProcessError: An error occurred merging profdata files.
   """
-  logging.info('Creating target profile data file')
-  logging.debug('Merging target profraw files to create target profdata file')
+  logging.info('Creating target profile data file.')
+  logging.debug('Merging target profraw files to create target profdata file.')
   profdata_file_path = os.path.join(OUTPUT_DIR, '%s.profdata' % target)
 
   try:
@@ -1065,8 +1128,8 @@
     print('Failed to merge target profraw files to create target profdata.')
     raise error
 
-  logging.debug('Finished merging target profraw files')
-  logging.info('Target %s profile data is created as: %s', target,
+  logging.debug('Finished merging target profraw files.')
+  logging.info('Target "%s" profile data is created as: "%s".', target,
                profdata_file_path)
   return profdata_file_path
 
@@ -1079,7 +1142,7 @@
   # NOTE: For object files, the first one is specified as a positional argument,
   # and the rest are specified as keyword argument.
   logging.debug('Generating per-file code coverage summary using "llvm-cov '
-                'export -summary-only" command')
+                'export -summary-only" command.')
   subprocess_cmd = [
       LLVM_COV_PATH, 'export', '-summary-only',
       '-instr-profile=' + profdata_file_path, binary_paths[0]
@@ -1091,15 +1154,24 @@
   if ignore_filename_regex:
     subprocess_cmd.append('-ignore-filename-regex=%s' % ignore_filename_regex)
 
-  json_output = json.loads(subprocess.check_output(subprocess_cmd))
+  export_output = subprocess.check_output(subprocess_cmd)
+
+  # Write output on the disk to be used by code coverage bot.
+  with open(_GetSummaryFilePath(), 'w') as f:
+    f.write(export_output)
+
+  json_output = json.loads(export_output)
   assert len(json_output['data']) == 1
   files_coverage_data = json_output['data'][0]['files']
 
   per_file_coverage_summary = {}
   for file_coverage_data in files_coverage_data:
     file_path = file_coverage_data['filename']
-    summary = file_coverage_data['summary']
+    assert file_path.startswith(SRC_ROOT_PATH + os.sep), (
+        'File path "%s" in coverage summary is outside source checkout.' %
+        file_path)
 
+    summary = file_coverage_data['summary']
     if summary['lines']['count'] == 0:
       continue
 
@@ -1111,7 +1183,7 @@
         lines_total=summary['lines']['count'],
         lines_covered=summary['lines']['covered'])
 
-  logging.debug('Finished generating per-file code coverage summary')
+  logging.debug('Finished generating per-file code coverage summary.')
   return per_file_coverage_summary
 
 
@@ -1151,7 +1223,7 @@
   command_parts = shlex.split(command)
   if os.path.basename(command_parts[0]) == 'python':
     assert os.path.basename(command_parts[1]) == xvfb_script_name, (
-        'This tool doesn\'t understand the command: "%s"' % command)
+        'This tool doesn\'t understand the command: "%s".' % command)
     return command_parts[2]
 
   if os.path.basename(command_parts[0]) == xvfb_script_name:
@@ -1178,7 +1250,7 @@
   for command in commands:
     binary_path = _GetBinaryPath(command)
     binary_absolute_path = os.path.abspath(os.path.normpath(binary_path))
-    assert binary_absolute_path.startswith(os.path.abspath(BUILD_DIR)), (
+    assert binary_absolute_path.startswith(BUILD_DIR), (
         'Target executable "%s" in command: "%s" is outside of '
         'the given build directory: "%s".' % (binary_path, command, BUILD_DIR))
 
@@ -1283,7 +1355,7 @@
       binary_paths.append(binary_path)
     else:
       logging.warning(
-          'Target binary %s not found in build directory, skipping.',
+          'Target binary "%s" not found in build directory, skipping.',
           os.path.basename(binary_path))
 
   return binary_paths
@@ -1391,9 +1463,9 @@
   _ConfigureLogging(args)
 
   global BUILD_DIR
-  BUILD_DIR = args.build_dir
+  BUILD_DIR = os.path.abspath(args.build_dir)
   global OUTPUT_DIR
-  OUTPUT_DIR = args.output_dir
+  OUTPUT_DIR = os.path.abspath(args.output_dir)
 
   assert args.command or args.profdata_file, (
       'Need to either provide commands to run using -c/--command option OR '
@@ -1403,8 +1475,8 @@
       'Number of targets must be equal to the number of test commands.')
 
   assert os.path.exists(BUILD_DIR), (
-      'Build directory: {} doesn\'t exist. '
-      'Please run "gn gen" to generate.').format(BUILD_DIR)
+      'Build directory: "%s" doesn\'t exist. '
+      'Please run "gn gen" to generate.' % BUILD_DIR)
 
   _ValidateCurrentPlatformIsSupported()
   _ValidateBuildingWithClangCoverage()
@@ -1413,8 +1485,8 @@
   if args.filters:
     absolute_filter_paths = _VerifyPathsAndReturnAbsolutes(args.filters)
 
-  if not os.path.exists(OUTPUT_DIR):
-    os.makedirs(OUTPUT_DIR)
+  if not os.path.exists(_GetCoverageReportRootDirPath()):
+    os.makedirs(_GetCoverageReportRootDirPath())
 
   # Get profdate file and list of binary paths.
   if args.command:
@@ -1430,7 +1502,7 @@
     binary_paths = _GetBinaryPathsFromTargets(args.targets, args.build_dir)
 
   logging.info('Generating code coverage report in html (this can take a while '
-               'depending on size of target!)')
+               'depending on size of target!).')
   binary_paths.extend(_GetSharedLibraries(binary_paths))
   per_file_coverage_summary = _GeneratePerFileCoverageSummary(
       binary_paths, profdata_file_path, absolute_filter_paths,
@@ -1457,10 +1529,10 @@
   # The default index file is generated only for the list of source files, needs
   # to overwrite it to display per directory coverage view by default.
   _OverwriteHtmlReportsIndexFile()
+  _CleanUpOutputDir()
 
-  html_index_file_path = 'file://' + os.path.abspath(
-      os.path.join(OUTPUT_DIR, 'index.html'))
-  logging.info('Index file for html report is generated as: %s',
+  html_index_file_path = 'file://' + os.path.abspath(_GetHtmlIndexPath())
+  logging.info('Index file for html report is generated as: "%s".',
                html_index_file_path)
 
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 3bb4fa96..d2cf623 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -6918,7 +6918,7 @@
 
 <enum name="ContentSuggestionsCategory">
   <int value="0" label="Experimental"/>
-  <int value="1" label="Recent Tabs"/>
+  <int value="1" label="Recent Tabs (obsolete)"/>
   <int value="2" label="Downloads"/>
   <int value="3" label="Bookmarks"/>
   <int value="4" label="Physical Web Pages (obsolete)"/>
@@ -48031,8 +48031,9 @@
 
 <enum name="WindowsNotificationActivationStatus">
   <int value="0" label="SUCCESS"/>
-  <int value="1" label="GET_PROFILE_ID_INVALID_LAUNCH_ID"/>
-  <int value="2" label="ACTIVATION_INVALID_LAUNCH_ID"/>
+  <int value="1" label="GET_PROFILE_ID_INVALID_LAUNCH_ID (deprecated)"/>
+  <int value="2" label="ACTIVATION_INVALID_LAUNCH_ID (deprecated)"/>
+  <int value="3" label="INVALID_LAUNCH_ID"/>
 </enum>
 
 <enum name="WindowsNotificationCloseStatus">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 3341fc2..8fd68f7 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -57329,6 +57329,7 @@
     enum="WindowsNotificationActivationStatus">
   <owner>finnur@chromium.org</owner>
   <owner>peter@chromium.org</owner>
+  <owner>chengx@chromium.org</owner>
   <summary>
     The status of Activation requests in NotificationPlatformBridgeWin (Windows
     only). Logged whenever an activation from a notification occurs.
diff --git a/ui/gl/gl_switches_util.cc b/ui/gl/gl_switches_util.cc
index df9e4f9a..cdf0932 100644
--- a/ui/gl/gl_switches_util.cc
+++ b/ui/gl/gl_switches_util.cc
@@ -13,7 +13,7 @@
 
 bool IsPresentationCallbackEnabled() {
 // TODO(peng): always enable once 776877 is fixed.
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_LINUX)
   return true;
 #else
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/ui/views/controls/webview/webview_unittest.cc b/ui/views/controls/webview/webview_unittest.cc
index 3e82c4f5..f1d0ce7 100644
--- a/ui/views/controls/webview/webview_unittest.cc
+++ b/ui/views/controls/webview/webview_unittest.cc
@@ -130,8 +130,8 @@
 
   std::unique_ptr<content::WebContents> CreateWebContentsForWebView(
       content::BrowserContext* browser_context) {
-    return base::WrapUnique(content::WebContentsTester::CreateTestWebContents(
-        browser_context, nullptr));
+    return content::WebContentsTester::CreateTestWebContents(browser_context,
+                                                             nullptr);
   }
 
   void SetUp() override {
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
index 349c3e7..772bc6d 100644
--- a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
+++ b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js
@@ -55,8 +55,15 @@
     this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
   },
 
-  /** @private */
-  disabledChanged_: function() {
+  /**
+   * @param {boolean} current
+   * @param {boolean} previous
+   * @private
+   */
+  disabledChanged_: function(current, previous) {
+    if (previous === undefined && !this.disabled)
+      return;
+
     this.setAttribute('tabindex', this.disabled ? -1 : 0);
     this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
   },
diff --git a/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html b/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
index 0ea8fbf..4b3f0bd 100644
--- a/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
+++ b/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
@@ -1,6 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
+<link rel="import" href="../shared_vars_css.html">
 
 <dom-module id="cr-toggle">
   <template>
@@ -13,6 +14,7 @@
 
       :host([disabled]) {
         cursor: initial;
+        opacity: 0.38;
         pointer-events: none;
       }
 
@@ -29,11 +31,11 @@
       }
 
       #bar {
-        background-color: var(--cr-toggle-unchecked-bar-color, black);
+        background-color:
+          var(--cr-toggle-unchecked-bar-color, var(--google-grey-400));
         border-radius: 8px;
         height: 12px;
         left: 3px;
-        opacity: 0.4;
         position: absolute;
         top: 2px;
         transition: background-color linear 80ms;
@@ -43,17 +45,12 @@
 
       :host([checked]) #bar {
         background-color: var(
-            --cr-toggle-checked-bar-color, var(--google-blue-500));
-      }
-
-      :host([disabled]) #bar {
-        background-color: black;
-        opacity: 0.12;
+            --cr-toggle-checked-bar-color, var(--google-blue-600));
+        opacity: 0.5;
       }
 
       #knob {
-        background-color: var(
-            --cr-toggle-unchecked-button-color, var(--paper-grey-50));
+        background-color: var(--cr-toggle-unchecked-button-color, white);
         border-radius: 50%;
         box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.4);
         display: block;
@@ -66,7 +63,7 @@
 
       :host([checked]) #knob {
         background-color: var(
-            --cr-toggle-checked-button-color, var(--google-blue-500));
+            --cr-toggle-checked-button-color, var(--google-blue-600));
         transform: translate3d(18px, 0, 0);
       }
 
@@ -74,11 +71,6 @@
         transform: translate3d(-18px, 0, 0);
       }
 
-      :host([disabled]) #knob {
-        background-color: #bdbdbd;
-        opacity: 1;
-      }
-
       paper-ripple {
         --paper-ripple-opacity: 0.125;
         color: var(--cr-toggle-unchecked-ink-color, var(--primary-text-color));
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index b201c750..30d9d45 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -120,6 +120,7 @@
 
     /** MD Refresh Styles */
     --google-blue-600: #1A73E8;
+    --google-grey-400: #BDC1C6;
     --cr-controls-background-grey: #2A3146;
   }
 </style>