diff --git a/DEPS b/DEPS
index 6274d39..86521ab2 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '8364706c02c6ad33637132ff126a48011e4d8b13',
+  'skia_revision': 'b423247bc2395e0f0172369078cdb227ae99c7a8',
   # 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': '2c1fd4018fcbc740b984f981b0d84c16d994c329',
+  'v8_revision': '6014ce844cec377c154605a0b848c8b2faf8b853',
   # 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.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'f22b4e2f6682fe26113c591a01139a8b5fa4e3bf',
+  'pdfium_revision': 'c15c0b3a1e9ab6292349402066b4c4b002a8e093',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -165,7 +165,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '26d6aff1b57b0a3b225515a18f359f35d2fa5a66',
+  'catapult_revision': 'c3318d5f367c021a5cebb24baeb04a9bc96a9ed5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -234,17 +234,6 @@
   'src/buildtools':
     Var('chromium_git') + '/chromium/buildtools.git' + '@' +  Var('buildtools_revision'),
 
-  'src/chrome/android/profiles': {
-      'packages': [
-          {
-              'package': 'chromium/afdo/profiles/android',
-              'version': 'version:3309',
-          },
-      ],
-      'condition': 'checkout_android',
-      'dep_type': 'cipd',
-  },
-
   'src/chrome/installer/mac/third_party/xz/xz': {
       'url': Var('chromium_git') + '/chromium/deps/xz.git' + '@' + 'eecaf55632ca72e90eb2641376bce7cdbc7284f7',
       'condition': 'checkout_mac',
@@ -565,7 +554,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '0eac64e18aba24402a21b7372b512a63830d71ec',
+      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'e0781f23b9e8f99f213b991bfb2e6bd2b50de82d',
       'condition': 'checkout_linux',
   },
 
@@ -575,7 +564,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f9afc77f283e5e9f7973ac0619a3cc5c18973a44',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2c984a03caff0f1c0f92d6b5ddbc3226393db5eb',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1079,7 +1068,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@664261cb3f4da3f552050400884b496a8737a363',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@bb5cc39baf68104adc6f4a857106d85ce04641b8',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index c86710e..9ea8673 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1882,8 +1882,7 @@
     'blink_scheduler': ['scheduler-bugs+blink@chromium.org'],
     'blink_screen_orientation': ['mlamouri+watch-blink@chromium.org'],
     'blink_script': ['kouhei+script@chromium.org',
-                     'hiroshige+script@chromium.org',
-                     'kochi+script@chromium.org'],
+                     'hiroshige+script@chromium.org'],
     'blink_scroll': ['bokan@chromium.org'],
     'blink_service_worker': ['falken+watch@chromium.org',
                              'horo+watch@chromium.org',
diff --git a/ash/keyboard/virtual_keyboard_controller.cc b/ash/keyboard/virtual_keyboard_controller.cc
index 0e3308af..47ebe93 100644
--- a/ash/keyboard/virtual_keyboard_controller.cc
+++ b/ash/keyboard/virtual_keyboard_controller.cc
@@ -303,7 +303,12 @@
       chromeos::input_method::mojom::ImeKeyset::kNone);
 }
 
-void VirtualKeyboardController::OnKeyboardHidden() {
+void VirtualKeyboardController::OnKeyboardHidden(bool is_temporary_hide) {
+  // The keyboard may temporarily hide (e.g. to change container behaviors).
+  // The keyset should not be reset in this case.
+  if (is_temporary_hide)
+    return;
+
   Shell::Get()->ime_controller()->OverrideKeyboardKeyset(
       chromeos::input_method::mojom::ImeKeyset::kNone);
 
diff --git a/ash/keyboard/virtual_keyboard_controller.h b/ash/keyboard/virtual_keyboard_controller.h
index 8a575fc..31d33c4 100644
--- a/ash/keyboard/virtual_keyboard_controller.h
+++ b/ash/keyboard/virtual_keyboard_controller.h
@@ -56,7 +56,7 @@
 
   // keyboard::KeyboardControllerObserver:
   void OnKeyboardDisabled() override;
-  void OnKeyboardHidden() override;
+  void OnKeyboardHidden(bool is_temporary_hide) override;
 
   // SessionObserver
   void OnActiveUserSessionChanged(const AccountId& account_id) override;
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index c81177b..38086d5 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -138,7 +138,8 @@
 
   // Simulate the keyboard hiding.
   if (GetKeyboardController()->HasObserver(GetVirtualKeyboardController())) {
-    GetVirtualKeyboardController()->OnKeyboardHidden();
+    GetVirtualKeyboardController()->OnKeyboardHidden(
+        false /* is_temporary_hide */);
   }
   base::RunLoop().RunUntilIdle();
 
@@ -182,7 +183,8 @@
 
   // Simulate the keyboard hiding.
   if (GetKeyboardController()->HasObserver(GetVirtualKeyboardController())) {
-    GetVirtualKeyboardController()->OnKeyboardHidden();
+    GetVirtualKeyboardController()->OnKeyboardHidden(
+        false /* is_temporary_hide */);
   }
   base::RunLoop().RunUntilIdle();
 
@@ -195,6 +197,47 @@
             client.last_keyset_);
 }
 
+TEST_F(VirtualKeyboardControllerTest,
+       ForceToShowKeyboardWithKeysetTemporaryHide) {
+  // TODO(mash): Turning on accessibility keyboard does not create a valid
+  // KeyboardController under MASH. See https://crbug.com/646565.
+  if (Shell::GetAshConfig() == Config::MASH_DEPRECATED)
+    return;
+
+  AccessibilityController* accessibility_controller =
+      Shell::Get()->accessibility_controller();
+  accessibility_controller->SetVirtualKeyboardEnabled(false);
+  ASSERT_FALSE(accessibility_controller->IsVirtualKeyboardEnabled());
+
+  // Set up a mock ImeControllerClient to test keyset changes.
+  TestImeControllerClient client;
+  Shell::Get()->ime_controller()->SetClient(client.CreateInterfacePtr());
+
+  // Should show the keyboard by turning on the accesibility keyboard.
+  GetVirtualKeyboardController()->ForceShowKeyboardWithKeyset(
+      chromeos::input_method::mojom::ImeKeyset::kEmoji);
+  Shell::Get()->ime_controller()->FlushMojoForTesting();
+  EXPECT_TRUE(accessibility_controller->IsVirtualKeyboardEnabled());
+
+  // Keyset should be emoji.
+  EXPECT_EQ(chromeos::input_method::mojom::ImeKeyset::kEmoji,
+            client.last_keyset_);
+
+  // Simulate the keyboard hiding temporarily.
+  if (GetKeyboardController()->HasObserver(GetVirtualKeyboardController())) {
+    GetVirtualKeyboardController()->OnKeyboardHidden(
+        true /* is_temporary_hide */);
+  }
+  base::RunLoop().RunUntilIdle();
+
+  // The keyboard should still be enabled.
+  EXPECT_TRUE(accessibility_controller->IsVirtualKeyboardEnabled());
+
+  // Keyset should still be emoji.
+  EXPECT_EQ(chromeos::input_method::mojom::ImeKeyset::kEmoji,
+            client.last_keyset_);
+}
+
 class VirtualKeyboardControllerAutoTest : public VirtualKeyboardControllerTest,
                                           public VirtualKeyboardObserver {
  public:
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index 34913c3..99a5f8b04 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -504,7 +504,7 @@
   HideBubbleWithView(bubble_view);
 }
 
-void ImeMenuTray::OnKeyboardHidden() {
+void ImeMenuTray::OnKeyboardHidden(bool is_temporary_hide) {
   if (show_bubble_after_keyboard_hidden_) {
     show_bubble_after_keyboard_hidden_ = false;
     auto* keyboard_controller = keyboard::KeyboardController::Get();
diff --git a/ash/system/ime_menu/ime_menu_tray.h b/ash/system/ime_menu/ime_menu_tray.h
index 115621c..4ccd986 100644
--- a/ash/system/ime_menu/ime_menu_tray.h
+++ b/ash/system/ime_menu/ime_menu_tray.h
@@ -73,7 +73,7 @@
   void HideBubble(const views::TrayBubbleView* bubble_view) override;
 
   // keyboard::KeyboardControllerObserver:
-  void OnKeyboardHidden() override;
+  void OnKeyboardHidden(bool is_temporary_hide) override;
 
   // VirtualKeyboardObserver:
   void OnKeyboardSuppressionChanged(bool suppressed) override;
diff --git a/ash/system/tray/tray_info_label.cc b/ash/system/tray/tray_info_label.cc
index 3af08f3..49844460 100644
--- a/ash/system/tray/tray_info_label.cc
+++ b/ash/system/tray/tray_info_label.cc
@@ -9,7 +9,6 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/layout/fill_layout.h"
-
 namespace ash {
 
 TrayInfoLabel::TrayInfoLabel(TrayInfoLabel::Delegate* delegate, int message_id)
@@ -30,6 +29,8 @@
   tri_view->AddView(TriView::Container::CENTER, label_);
 
   AddChildView(tri_view);
+  SetFocusBehavior(IsClickable() ? FocusBehavior::ALWAYS
+                                 : FocusBehavior::NEVER);
 
   Update(message_id);
 }
@@ -55,6 +56,8 @@
   base::string16 text = l10n_util::GetStringUTF16(message_id);
   label_->SetText(text);
   SetAccessibleName(text);
+  SetFocusBehavior(IsClickable() ? FocusBehavior::ALWAYS
+                                 : FocusBehavior::NEVER);
 }
 
 bool TrayInfoLabel::PerformAction(const ui::Event& event) {
diff --git a/ash/system/tray/tray_info_label_unittest.cc b/ash/system/tray/tray_info_label_unittest.cc
index ef25981..c5172034 100644
--- a/ash/system/tray/tray_info_label_unittest.cc
+++ b/ash/system/tray/tray_info_label_unittest.cc
@@ -50,6 +50,11 @@
 
 class TrayInfoLabelTest : public AshTestBase {
  public:
+  void SetUp() override {
+    AshTestBase::SetUp();
+    delegate_ = std::make_unique<TestDelegate>();
+  }
+
   void TearDown() override {
     AshTestBase::TearDown();
     label_.reset();
@@ -57,10 +62,9 @@
   }
 
   void CreateLabel(bool use_delegate, int message_id) {
-    if (use_delegate)
-      delegate_ = std::make_unique<TestDelegate>();
-
-    label_ = std::make_unique<TrayInfoLabel>(delegate_.get(), message_id);
+    label_ = std::make_unique<TrayInfoLabel>(
+        use_delegate ? delegate_.get() : nullptr, message_id);
+    use_delegate_ = use_delegate;
   }
 
   void ClickOnLabel(bool expect_click_was_handled) {
@@ -70,6 +74,9 @@
 
   void VerifyClickability(bool expected_clickable) {
     EXPECT_EQ(expected_clickable, label_->IsClickable());
+    EXPECT_EQ(expected_clickable ? views::View::FocusBehavior::ALWAYS
+                                 : views::View::FocusBehavior::NEVER,
+              label_->focus_behavior());
 
     ui::AXNodeData node_data;
     label_->GetAccessibleNodeData(&node_data);
@@ -81,7 +88,7 @@
   }
 
   void VerifyClicks(const std::vector<int>& expected_clicked_message_ids) {
-    if (!delegate_) {
+    if (!use_delegate_) {
       EXPECT_TRUE(expected_clicked_message_ids.empty());
       return;
     }
@@ -94,6 +101,7 @@
  protected:
   std::unique_ptr<TrayInfoLabel> label_;
   std::unique_ptr<TestDelegate> delegate_;
+  bool use_delegate_;
 };
 
 TEST_F(TrayInfoLabelTest, NoDelegate) {
@@ -119,9 +127,10 @@
   const int kClickableMessageId2 = IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED;
   const int kNonClickableMessageId = IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING;
 
-  CreateLabel(true /* use_delegate */, kClickableMessageId1);
   delegate_->AddClickableMessageId(kClickableMessageId1);
   delegate_->AddClickableMessageId(kClickableMessageId2);
+
+  CreateLabel(true /* use_delegate */, kClickableMessageId1);
   VerifyNoClicks();
 
   EXPECT_EQ(l10n_util::GetStringUTF16(kClickableMessageId1),
diff --git a/ash/system/unified/unified_slider_bubble_controller.cc b/ash/system/unified/unified_slider_bubble_controller.cc
index 963d19c..cfd5cb82 100644
--- a/ash/system/unified/unified_slider_bubble_controller.cc
+++ b/ash/system/unified/unified_slider_bubble_controller.cc
@@ -4,9 +4,12 @@
 
 #include "ash/system/unified/unified_slider_bubble_controller.h"
 
+#include "ash/root_window_controller.h"
+#include "ash/shell.h"
 #include "ash/system/audio/unified_volume_slider_controller.h"
 #include "ash/system/brightness/unified_brightness_slider_controller.h"
 #include "ash/system/keyboard_brightness/unified_keyboard_brightness_slider_controller.h"
+#include "ash/system/status_area_widget.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/unified/unified_system_tray.h"
 
@@ -14,6 +17,19 @@
 
 namespace ash {
 
+namespace {
+
+// Return true if a system tray bubble is shown in any display.
+bool IsAnyMainBubbleShown() {
+  for (RootWindowController* root : Shell::GetAllRootWindowControllers()) {
+    if (root->GetStatusAreaWidget()->unified_system_tray()->IsBubbleShown())
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
 UnifiedSliderBubbleController::UnifiedSliderBubbleController(
     UnifiedSystemTray* tray)
     : tray_(tray) {
@@ -83,7 +99,7 @@
 }
 
 void UnifiedSliderBubbleController::ShowBubble(SliderType slider_type) {
-  if (tray_->IsBubbleShown()) {
+  if (IsAnyMainBubbleShown()) {
     tray_->EnsureBubbleExpanded();
     return;
   }
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index dfa25165..88a0fdb 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -12,9 +12,13 @@
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/system/unified/unified_system_tray_controller.h"
 #include "ash/system/unified/unified_system_tray_view.h"
+#include "ash/wm/container_finder.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/widget_finder.h"
 #include "base/metrics/histogram_macros.h"
 #include "ui/aura/window.h"
+#include "ui/wm/core/window_util.h"
+#include "ui/wm/public/activation_client.h"
 
 namespace ash {
 
@@ -67,7 +71,7 @@
     time_shown_by_click_ = base::TimeTicks::Now();
 
   views::TrayBubbleView::InitParams init_params;
-  init_params.anchor_alignment = views::TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
+  init_params.anchor_alignment = tray_->GetAnchorAlignment();
   init_params.min_width = kTrayMenuWidth;
   init_params.max_width = kTrayMenuWidth;
   init_params.delegate = tray;
@@ -107,9 +111,11 @@
 
   tray->tray_event_filter()->AddBubble(this);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
+  Shell::Get()->activation_client()->AddObserver(this);
 }
 
 UnifiedSystemTrayBubble::~UnifiedSystemTrayBubble() {
+  Shell::Get()->activation_client()->RemoveObserver(this);
   if (Shell::Get()->tablet_mode_controller())
     Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
   tray_->tray_event_filter()->RemoveBubble(this);
@@ -229,6 +235,25 @@
   tray_->CloseBubble();
 }
 
+void UnifiedSystemTrayBubble::OnWindowActivated(ActivationReason reason,
+                                                aura::Window* gained_active,
+                                                aura::Window* lost_active) {
+  if (!gained_active)
+    return;
+
+  // Don't close the bubble if a transient child is gaining or losing
+  // activation.
+  if (bubble_widget_ == GetInternalWidgetForWindow(gained_active) ||
+      ::wm::HasTransientAncestor(gained_active,
+                                 bubble_widget_->GetNativeWindow()) ||
+      (lost_active && ::wm::HasTransientAncestor(
+                          lost_active, bubble_widget_->GetNativeWindow()))) {
+    return;
+  }
+
+  tray_->CloseBubble();
+}
+
 void UnifiedSystemTrayBubble::RecordTimeToClick() {
   // Ignore if the tray bubble is not opened by click.
   if (!time_shown_by_click_)
diff --git a/ash/system/unified/unified_system_tray_bubble.h b/ash/system/unified/unified_system_tray_bubble.h
index c2ce0e9..63fc5614 100644
--- a/ash/system/unified/unified_system_tray_bubble.h
+++ b/ash/system/unified/unified_system_tray_bubble.h
@@ -15,6 +15,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "ui/views/widget/widget_observer.h"
+#include "ui/wm/public/activation_change_observer.h"
 
 namespace ui {
 class LayerOwner;
@@ -35,8 +36,9 @@
 // It is possible that the bubble widget is closed on deactivation. In such
 // case, this class calls UnifiedSystemTray::CloseBubble() to delete itself.
 class UnifiedSystemTrayBubble : public TrayBubbleBase,
-                                public views::WidgetObserver,
                                 public ash::ScreenLayoutObserver,
+                                public views::WidgetObserver,
+                                public ::wm::ActivationChangeObserver,
                                 public TimeToClickRecorder::Delegate,
                                 public TabletModeObserver {
  public:
@@ -75,6 +77,11 @@
   // views::WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
 
+  // ::wm::ActivationChangeObserver:
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
+                         aura::Window* lost_active) override;
+
   // TimeToClickRecorder::Delegate:
   void RecordTimeToClick() override;
 
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index b445343..ba85976 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -128,13 +128,13 @@
 void UnifiedSystemTrayController::HandleSettingsAction() {
   Shell::Get()->metrics()->RecordUserMetricsAction(UMA_TRAY_SETTINGS);
   Shell::Get()->system_tray_model()->client_ptr()->ShowSettings();
-  CloseBubble();
 }
 
 void UnifiedSystemTrayController::HandlePowerAction() {
   Shell::Get()->metrics()->RecordUserMetricsAction(UMA_TRAY_SHUT_DOWN);
   Shell::Get()->lock_state_controller()->RequestShutdown(
       ShutdownReason::TRAY_SHUT_DOWN_BUTTON);
+  CloseBubble();
 }
 
 void UnifiedSystemTrayController::HandleOpenDateTimeSettingsAction() {
@@ -142,7 +142,6 @@
 
   if (Shell::Get()->session_controller()->ShouldEnableSettings()) {
     model->ShowDateSettings();
-    CloseBubble();
   } else if (model->can_set_time()) {
     model->ShowSetTimeDialog();
   }
@@ -150,7 +149,6 @@
 
 void UnifiedSystemTrayController::HandleEnterpriseInfoAction() {
   Shell::Get()->system_tray_model()->client_ptr()->ShowEnterpriseInfo();
-  CloseBubble();
 }
 
 void UnifiedSystemTrayController::ToggleExpanded() {
diff --git a/ash/window_manager_unittest.cc b/ash/window_manager_unittest.cc
index 46cc854..d69ea5af 100644
--- a/ash/window_manager_unittest.cc
+++ b/ash/window_manager_unittest.cc
@@ -94,9 +94,11 @@
 }
 
 #if defined(ADDRESS_SANITIZER)
+// See https://crbug.com/838520.
 #define MAYBE_OpenWindow DISABLED_OpenWindow
 #else
-#define MAYBE_OpenWindow OpenWindow
+// See https://crbug.com/865316.
+#define MAYBE_OpenWindow DISABLED_OpenWindow
 #endif
 TEST_F(WindowManagerServiceTest, MAYBE_OpenWindow) {
   display::ScreenBase screen;
diff --git a/build/config/fuchsia/build_manifest.py b/build/config/fuchsia/build_manifest.py
index bc3df01..4896c1e 100644
--- a/build/config/fuchsia/build_manifest.py
+++ b/build/config/fuchsia/build_manifest.py
@@ -36,9 +36,13 @@
     if match:
       lib = match.group('lib')
 
+      # libc.so is an alias for ld.so.1 .
+      if lib == 'libc.so':
+        lib = 'ld.so.1'
+
       # Skip libzircon.so, as it is supplied by the OS loader.
       if lib != 'libzircon.so':
-        libs.append(match.group('lib'))
+        libs.append(lib)
 
   return libs
 
@@ -198,13 +202,6 @@
       manifest.write('%s=%s\n' % (in_package_path,
                                   os.path.relpath(current_file, out_dir)))
 
-      # Use libc.so's dynamic linker by aliasing libc.so to ld.so.1.
-      # Fuchsia always looks for the linker implementation in ld.so.1.
-      if os.path.basename(in_package_path) == 'libc.so':
-        manifest.write(
-            '%s=%s\n' % (os.path.dirname(in_package_path) + '/ld.so.1',
-                         os.path.relpath(current_file, out_dir)))
-
     if not app_found:
       raise Exception('Could not locate executable inside runtime_deps.')
 
diff --git a/build/fuchsia/sdk.sha1 b/build/fuchsia/sdk.sha1
index 61271a91..f440306 100644
--- a/build/fuchsia/sdk.sha1
+++ b/build/fuchsia/sdk.sha1
@@ -1 +1 @@
-c9b6deebf8ef0d85134dfee4806f1a7bc2df3193
+7524a90f78ba1ba27c4b9ab38c3bf418afd210ef
diff --git a/chrome/VERSION b/chrome/VERSION
index 12ead7d..6e0a42a8 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=69
 MINOR=0
-BUILD=3496
+BUILD=3497
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java
index bf72126..f00bbe01d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerCoordinatorImpl.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.download.home;
 
 import android.app.Activity;
+import android.content.Intent;
 import android.support.graphics.drawable.VectorDrawableCompat;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.Toolbar;
@@ -15,6 +16,7 @@
 import android.widget.TextView;
 
 import org.chromium.base.ObserverList;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -25,9 +27,13 @@
 import org.chromium.chrome.browser.download.home.snackbars.DeleteUndoCoordinator;
 import org.chromium.chrome.browser.download.home.toolbar.DownloadHomeToolbar;
 import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory;
+import org.chromium.chrome.browser.download.ui.DownloadManagerUi;
+import org.chromium.chrome.browser.preferences.PreferencesLauncher;
+import org.chromium.chrome.browser.preferences.download.DownloadPreferences;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.widget.selection.SelectableListLayout;
+import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
 
 import java.io.Closeable;
@@ -54,6 +60,20 @@
 
     private SelectionDelegate<ListItem> mSelectionDelegate;
 
+    private SelectableListToolbar.SearchDelegate mSearchDelegate =
+            new SelectableListToolbar.SearchDelegate() {
+                @Override
+                public void onSearchTextChanged(String query) {
+                    mListCoordinator.setSearchQuery(query);
+                }
+
+                @Override
+                public void onEndSearch() {
+                    mSelectableListLayout.onEndSearch();
+                    mListCoordinator.setSearchQuery(null);
+                }
+            };
+
     /** Builds a {@link DownloadManagerCoordinatorImpl} instance. */
     @SuppressWarnings({"unchecked"}) // mSelectableListLayout
     public DownloadManagerCoordinatorImpl(Profile profile, Activity activity, boolean offTheRecord,
@@ -89,7 +109,7 @@
                 isSeparateActivity);
         mToolbar.getMenu().setGroupVisible(normalGroupId, true);
         mToolbar.initializeSearchView(
-                /* searchDelegate = */ null, R.string.download_manager_search, mSearchMenuId);
+                mSearchDelegate, R.string.download_manager_search, mSearchMenuId);
 
         mIsSeparateActivity = isSeparateActivity;
         if (!mIsSeparateActivity) mToolbar.removeCloseButton();
@@ -147,7 +167,49 @@
 
     @Override
     public boolean onMenuItemClick(MenuItem item) {
-        // TODO(shaktisahu): Handle menu items.
+        if ((item.getItemId() == R.id.close_menu_id
+                    || item.getItemId() == R.id.with_settings_close_menu_id)
+                && mIsSeparateActivity) {
+            DownloadManagerUi.recordMenuActionHistogram(DownloadManagerUi.MENU_ACTION_CLOSE);
+            mActivity.finish();
+            return true;
+        } else if (item.getItemId() == R.id.selection_mode_delete_menu_id) {
+            DownloadManagerUi.recordMenuActionHistogram(DownloadManagerUi.MENU_ACTION_MULTI_DELETE);
+            RecordHistogram.recordCount100Histogram(
+                    "Android.DownloadManager.Menu.Delete.SelectedCount",
+                    mSelectionDelegate.getSelectedItems().size());
+            mListCoordinator.onDeletionRequested(mSelectionDelegate.getSelectedItems());
+            mSelectionDelegate.clearSelection();
+            return true;
+        } else if (item.getItemId() == R.id.selection_mode_share_menu_id) {
+            // TODO(twellington): ideally the intent chooser would be started with
+            //                    startActivityForResult() and the selection would only be cleared
+            //                    after receiving an OK response. See https://crbug.com/638916.
+
+            DownloadManagerUi.recordMenuActionHistogram(DownloadManagerUi.MENU_ACTION_MULTI_SHARE);
+            RecordHistogram.recordCount100Histogram(
+                    "Android.DownloadManager.Menu.Share.SelectedCount",
+                    mSelectionDelegate.getSelectedItems().size());
+
+            // TODO(shaktisahu): Share selected items.
+            mSelectionDelegate.clearSelection();
+            return true;
+        } else if (item.getItemId() == mSearchMenuId) {
+            // The header should be removed as soon as a search is started. Also it should be added
+            // back when the search is ended.
+            // TODO(shaktisahu): Check with UX and remove header.
+            mSelectableListLayout.onStartSearch();
+            mToolbar.showSearchView();
+            DownloadManagerUi.recordMenuActionHistogram(DownloadManagerUi.MENU_ACTION_SEARCH);
+            RecordUserAction.record("Android.DownloadManager.Search");
+            return true;
+        } else if (item.getItemId() == R.id.settings_menu_id) {
+            Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                    mActivity, DownloadPreferences.class.getName());
+            mActivity.startActivity(intent);
+            RecordUserAction.record("Android.DownloadManager.Settings");
+            return true;
+        }
         return false;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java
index 6f2f7fd4..c2d33cc5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListCoordinator.java
@@ -93,4 +93,9 @@
     public void setSelectedFilter(@FilterType int filter) {
         mFilterCoordinator.setSelectedFilter(filter);
     }
+
+    /** Called to delete a list of items specified by {@code items}. */
+    public void onDeletionRequested(List<ListItem> items) {
+        mMediator.onDeletionRequested(items);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
index 95bef20..a689c0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -28,6 +28,7 @@
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.io.Closeable;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
@@ -124,6 +125,11 @@
         }
     }
 
+    /** Called to delete a list of items specified by {@code items}. */
+    public void onDeletionRequested(List<ListItem> items) {
+        onDeleteItems(getOfflineItems(items));
+    }
+
     /**
      * @return The {@link OfflineItemFilterSource} that should be used to determine which filter
      *         options are available.
@@ -170,6 +176,16 @@
         return () -> mThumbnailProvider.cancelRetrieval(request);
     }
 
+    private List<OfflineItem> getOfflineItems(List<ListItem> items) {
+        List<OfflineItem> offlineItems = new ArrayList<>();
+        for (ListItem item : items) {
+            if (item instanceof ListItem.OfflineItemListItem) {
+                offlineItems.add(((ListItem.OfflineItemListItem) item).item);
+            }
+        }
+        return offlineItems;
+    }
+
     /** Helper class to disable animations for certain list changes. */
     private class AnimationDisableClosable implements Closeable {
         AnimationDisableClosable() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
index cf16810..8ce85868 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -168,13 +168,14 @@
             MENU_ACTION_SHOW_INFO, MENU_ACTION_HIDE_INFO, MENU_ACTION_SEARCH})
     public @interface MenuAction {}
 
-    private static final int MENU_ACTION_CLOSE = 0;
-    private static final int MENU_ACTION_MULTI_DELETE = 1;
-    private static final int MENU_ACTION_MULTI_SHARE = 2;
-    private static final int MENU_ACTION_SHOW_INFO = 3;
-    private static final int MENU_ACTION_HIDE_INFO = 4;
-    private static final int MENU_ACTION_SEARCH = 5;
-    private static final int MENU_ACTION_BOUNDARY = 6;
+    // TODO(shaktisahu): Move these to new download home and make them private.
+    public static final int MENU_ACTION_CLOSE = 0;
+    public static final int MENU_ACTION_MULTI_DELETE = 1;
+    public static final int MENU_ACTION_MULTI_SHARE = 2;
+    public static final int MENU_ACTION_SHOW_INFO = 3;
+    public static final int MENU_ACTION_HIDE_INFO = 4;
+    public static final int MENU_ACTION_SEARCH = 5;
+    public static final int MENU_ACTION_BOUNDARY = 6;
 
     private static final int PREFETCH_BUNDLE_OPEN_DELAY_MS = 500;
 
@@ -618,7 +619,7 @@
         sProviderForTests = provider;
     }
 
-    private static void recordMenuActionHistogram(@MenuAction int action) {
+    public static void recordMenuActionHistogram(@MenuAction int action) {
         RecordHistogram.recordEnumeratedHistogram(
                 "Android.DownloadManager.Menu.Action", action, MENU_ACTION_BOUNDARY);
     }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index e936dc20..1381bf0 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -332,7 +332,7 @@
         Autocomplete searches and URLs
       </message>
       <message name="IDS_AUTOCOMPLETE_SEARCHES_AND_URLS_SUMMARY" desc="Summary for a checkbox in Settings that controls URL and search autocompletion and informs the user about the data shared by this feature.">
-        Sends searches from the address bar and search box, and some cookies to your default search engine
+        Sends some cookies and searches from the address bar and search box to your default search engine
       </message>
       <message name="IDS_PRELOAD_PAGES_TITLE" desc="Title for a checkbox in Settings that controls pages preloading and informs the user about the data shared by this feature.">
         Preload pages for faster browsing and searching
@@ -341,7 +341,7 @@
         Uses cookies to remember your preferences, even if you don't visit those pages
       </message>
       <message name="IDS_NAVIGATION_ERROR_SUGGESTIONS_TITLE" desc="Title for a checkbox in Settings that controls pages suggestions on navigation errors and informs the user about the data shared by this feature.">
-        Shows suggestions for similar pages when a page can't be found
+        Show suggestions for similar pages when a page can't be found
       </message>
       <message name="IDS_NAVIGATION_ERROR_SUGGESTIONS_SUMMARY" desc="Summary for a checkbox in Settings that controls pages suggestions on navigation errors and informs the user about the data shared by this feature.">
         Sends the URL of a page you're trying to reach to Google
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index a94134d..cc0fd502 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -457,6 +457,28 @@
   <message name="IDS_FILE_BROWSER_TASK_LISTEN" desc="Title of the action to play an audio file.">
     Listen
   </message>
+  <message name="IDS_FILE_BROWSER_TASK_INSTALL_LINUX_PACKAGE" desc="Title of the action to install a Linux package.">
+    Install with Linux (Beta)
+  </message>
+
+  <message name="IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_TITLE" desc="In the File Manager, the title shown in the dialog for installing a Linux application.">
+    Install app with Linux (Beta)
+  </message>
+  <message name="IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_DESCRIPTION" desc="In the File Manager, the message shown in the dialog for installing a Linux application.">
+    The Linux application will be available within your Terminal and may also show an icon in your Launcher.
+  </message>
+  <message name="IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_INSTALL_BUTTON" desc="In the File Manager, the label on the button to begin installing a Linux application. ">
+    Install
+  </message>
+  <message name="IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_INSTALLATION_STARTED" desc="In the File Manager, the dialog message when a Linux application installation successfully starts.">
+    Installation successfully started.
+  </message>
+  <message name="IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_ERROR_TITLE" desc="In the File Manager, the title shown in the dialog for installing a Linux application when an error occurs.">
+    Error installing Linux application
+  </message>
+  <message name="IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_ERROR_DESCRIPTION" desc="In the File Manager, the dialog message when a Linux application installation fails.">
+    An error occured during installation of your Linux application.
+  </message>
 
   <message name="IDS_FILE_BROWSER_GALLERY_NO_IMAGES" desc="In the Gallery, the message that there are no images in this directory.">
     No images in this directory.
@@ -5072,7 +5094,7 @@
     The Linux container didn't start. Please try again.
   </message>
   <message name="IDS_CROSTINI_UNINSTALLER_TITLE" desc="Title of the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files.">
-    Delete Linux
+    Delete Linux (Beta)
   </message>
   <message name="IDS_CROSTINI_UNINSTALLER_BODY" desc="Description for the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files.">
     Delete all Linux applications and data in your Linux Files folder from this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>?
@@ -5087,7 +5109,31 @@
     Error uninstalling Linux. Please try again.
   </message>
   <message name="IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM" desc="Text shown in the context menu for the Linux terminal app, allowing users to shut down the Linux virtual machine.">
-    Shut Down Linux
+    Shut Down Linux (Beta)
+  </message>
+  <message name="IDS_CROSTINI_TERMINA_UPDATE_REQUIRED" desc="Text shown in the Crostini update dialog when the VM component needs updating.">
+    Linux (Beta) update required
+  </message>
+  <message name="IDS_CROSTINI_TERMINA_UPDATE_OFFLINE" desc="Text shown in the Crostini update dialog when the VM component needs updating but the user is offline.">
+    Please connect to the internet and try again.
+  </message>
+  <message name="IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_DISPLAY_SOURCE" desc="Source of the Notification for Linux package installation.">
+    Linux installer
+  </message>
+  <message name="IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_IN_PROGRESS_TITLE" desc="Title of the Notification for an in-progress Linux package installation.">
+    Installation in progress
+  </message>
+  <message name="IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_COMPLETED_TITLE" desc="Title of the Notification for Linux package installation once installation has completed successfully.">
+    Installation complete
+  </message>
+  <message name="IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_COMPLETED_MESSAGE" desc="Message in the Notification for Linux package installation once installation has completed successfully.">
+    App is available in your terminal. There may also be an icon in your Launcher.
+  </message>
+  <message name="IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_ERROR_TITLE" desc="Title of the Notification for Linux package installation when there is an error during installation.">
+    Error while installing
+  </message>
+  <message name="IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_ERROR_MESSAGE" desc="Message in the Notification for Linux package installation when there is an error during installation.">
+    An error occurred during installation of your Linux application.
   </message>
 
   <!-- Time limit notification -->
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 590138c..a714512 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8279,6 +8279,9 @@
           <message name="IDS_APP_LIST_OEM_DEFAULT_FOLDER_NAME" desc="The default name for OEM folders in the App Launcher">
             OEM folder
           </message>
+          <message name="IDS_APP_LIST_CROSTINI_DEFAULT_FOLDER_NAME" desc="The default name for the Linux (Crostini) apps folder in the App Launcher">
+            Linux apps
+          </message>
         </if>
         <if expr="use_titlecase">
           <message name="IDS_APP_LIST_CONTEXT_MENU_NEW_TAB" desc="Title text for the 'open new' context menu item of an app list item configured to open in a tab">
@@ -8313,6 +8316,9 @@
           <message name="IDS_APP_LIST_OEM_DEFAULT_FOLDER_NAME" desc="The default name for OEM folders in the App Launcher">
             OEM Folder
           </message>
+          <message name="IDS_APP_LIST_CROSTINI_DEFAULT_FOLDER_NAME" desc="The default name for the Linux (Crostini) apps folder in the App Launcher">
+            Linux Apps
+          </message>
         </if>
       </if>
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index fe3779e..b3179cd8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -96,6 +96,8 @@
     "autocomplete/chrome_autocomplete_scheme_classifier.h",
     "autocomplete/contextual_suggestions_service_factory.cc",
     "autocomplete/contextual_suggestions_service_factory.h",
+    "autocomplete/document_suggestions_service_factory.cc",
+    "autocomplete/document_suggestions_service_factory.h",
     "autocomplete/in_memory_url_index_factory.cc",
     "autocomplete/in_memory_url_index_factory.h",
     "autocomplete/shortcuts_backend_factory.cc",
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
index 3c460ef..a6b58c5 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -12,6 +12,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/autocomplete/contextual_suggestions_service_factory.h"
+#include "chrome/browser/autocomplete/document_suggestions_service_factory.h"
 #include "chrome/browser/autocomplete/in_memory_url_index_factory.h"
 #include "chrome/browser/autocomplete/shortcuts_backend_factory.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h"
@@ -146,6 +147,13 @@
       profile_, create_if_necessary);
 }
 
+DocumentSuggestionsService*
+ChromeAutocompleteProviderClient::GetDocumentSuggestionsService(
+    bool create_if_necessary) const {
+  return DocumentSuggestionsServiceFactory::GetForProfile(profile_,
+                                                          create_if_necessary);
+}
+
 const
 SearchTermsData& ChromeAutocompleteProviderClient::GetSearchTermsData() const {
   return search_terms_data_;
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
index cb1a41e..1e873be8 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -35,6 +35,8 @@
   const TemplateURLService* GetTemplateURLService() const override;
   ContextualSuggestionsService* GetContextualSuggestionsService(
       bool create_if_necessary) const override;
+  DocumentSuggestionsService* GetDocumentSuggestionsService(
+      bool create_if_necessary) const override;
   const SearchTermsData& GetSearchTermsData() const override;
   scoped_refptr<ShortcutsBackend> GetShortcutsBackend() override;
   scoped_refptr<ShortcutsBackend> GetShortcutsBackendIfExists() override;
diff --git a/chrome/browser/autocomplete/document_suggestions_service_factory.cc b/chrome/browser/autocomplete/document_suggestions_service_factory.cc
new file mode 100644
index 0000000..2b44881
--- /dev/null
+++ b/chrome/browser/autocomplete/document_suggestions_service_factory.cc
@@ -0,0 +1,47 @@
+// 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/autocomplete/document_suggestions_service_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/omnibox/browser/document_suggestions_service.h"
+#include "content/public/browser/storage_partition.h"
+
+// static
+DocumentSuggestionsService* DocumentSuggestionsServiceFactory::GetForProfile(
+    Profile* profile,
+    bool create_if_necessary) {
+  return static_cast<DocumentSuggestionsService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, create_if_necessary));
+}
+
+// static
+DocumentSuggestionsServiceFactory*
+DocumentSuggestionsServiceFactory::GetInstance() {
+  return base::Singleton<DocumentSuggestionsServiceFactory>::get();
+}
+
+KeyedService* DocumentSuggestionsServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+
+  identity::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile);
+  return new DocumentSuggestionsService(
+      identity_manager,
+      content::BrowserContext::GetDefaultStoragePartition(profile)
+          ->GetURLLoaderFactoryForBrowserProcess());
+}
+
+DocumentSuggestionsServiceFactory::DocumentSuggestionsServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "DocumentSuggestionsService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(IdentityManagerFactory::GetInstance());
+}
+
+DocumentSuggestionsServiceFactory::~DocumentSuggestionsServiceFactory() {}
diff --git a/chrome/browser/autocomplete/document_suggestions_service_factory.h b/chrome/browser/autocomplete/document_suggestions_service_factory.h
new file mode 100644
index 0000000..d6baa11e
--- /dev/null
+++ b/chrome/browser/autocomplete/document_suggestions_service_factory.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOCOMPLETE_DOCUMENT_SUGGESTIONS_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_AUTOCOMPLETE_DOCUMENT_SUGGESTIONS_SERVICE_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class DocumentSuggestionsService;
+class Profile;
+
+class DocumentSuggestionsServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static DocumentSuggestionsService* GetForProfile(Profile* profile,
+                                                   bool create_if_necessary);
+  static DocumentSuggestionsServiceFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<DocumentSuggestionsServiceFactory>;
+
+  DocumentSuggestionsServiceFactory();
+  ~DocumentSuggestionsServiceFactory() override;
+
+  // Overrides from BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(DocumentSuggestionsServiceFactory);
+};
+
+#endif  // CHROME_BROWSER_AUTOCOMPLETE_DOCUMENT_SUGGESTIONS_SERVICE_FACTORY_H_
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index ff0e110..5c0a339 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -347,6 +347,10 @@
       <include name="IDR_MOST_VISITED_SINGLE_CSS" file="resources\local_ntp\most_visited_single.css" type="BINDATA" />
       <include name="IDR_MOST_VISITED_SINGLE_JS" file="resources\local_ntp\most_visited_single.js" type="BINDATA" />
       <include name="IDR_MOST_VISITED_UTIL_JS" file="resources\local_ntp\most_visited_util.js" type="BINDATA" flattenhtml="true" />
+      <include name="IDR_CUSTOM_LINKS_EDIT_HTML" file="resources\local_ntp\custom_links_edit.html" type="BINDATA" />
+      <include name="IDR_CUSTOM_LINKS_EDIT_CSS" file="resources\local_ntp\custom_links_edit.css" type="BINDATA" />
+      <include name="IDR_CUSTOM_LINKS_EDIT_JS" file="resources\local_ntp\custom_links_edit.js" type="BINDATA" />
+      <include name="IDR_CUSTOM_LINKS_ADD_SVG" file="resources\local_ntp\icons\add_link.svg" type="BINDATA" />
       <include name="IDR_OMNIBOX_HTML" file="resources\omnibox\omnibox.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
       <include name="IDR_OMNIBOX_CSS" file="resources\omnibox\omnibox.css" type="BINDATA" compress="gzip" />
       <include name="IDR_OMNIBOX_JS" file="resources\omnibox\omnibox.js" type="BINDATA" compress="gzip" />
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index de765b95..3c687cf 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -108,6 +108,7 @@
 #include "chrome/browser/android/webapps/webapp_registry.h"
 #include "chrome/browser/media/android/cdm/media_drm_license_manager.h"
 #include "chrome/browser/offline_pages/offline_page_model_factory.h"
+#include "components/feed/buildflags.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_model.h"
 #include "sql/connection.h"
@@ -412,11 +413,13 @@
     }
 
 #if defined(OS_ANDROID)
+#if BUILDFLAG(ENABLE_FEED_IN_CHROME)
     feed::FeedHostService* feed_host_service =
         feed::FeedHostServiceFactory::GetForBrowserContext(profile_);
     if (feed_host_service) {
       feed_host_service->GetSchedulerHost()->OnHistoryCleared();
     }
+#endif  // BUILDFLAG(ENABLE_FEED_IN_CHROME)
 #endif  // defined(OS_ANDROID)
 
     language::UrlLanguageHistogram* language_histogram =
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index fbe5506f9..39c460c7 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -96,6 +96,7 @@
 #include "chrome/browser/android/customtabs/origin_verifier.h"
 #include "chrome/browser/android/search_permissions/search_permissions_service.h"
 #include "chrome/browser/android/webapps/webapp_registry.h"
+#include "components/feed/buildflags.h"
 #else  // !defined(OS_ANDROID)
 #include "components/safe_browsing/password_protection/mock_password_protection_service.h"
 #include "content/public/browser/host_zoom_map.h"
@@ -2958,6 +2959,7 @@
       customtabs::OriginVerifier::GetClearBrowsingDataCallCountForTesting());
 }
 
+#if BUILDFLAG(ENABLE_FEED_IN_CHROME)
 TEST_F(ChromeBrowsingDataRemoverDelegateTest, FeedClearsLastFetchAttempt) {
   PrefService* prefs = GetProfile()->GetPrefs();
   prefs->SetTime(feed::prefs::kLastFetchAttemptTime, base::Time::Now());
@@ -2968,4 +2970,5 @@
 
   EXPECT_EQ(base::Time(), prefs->GetTime(feed::prefs::kLastFetchAttemptTime));
 }
+#endif  // BUILDFLAG(ENABLE_FEED_IN_CHROME)
 #endif  // defined(OS_ANDROID)
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 6662124..43e6916 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -26,6 +26,7 @@
     "//chrome:resources",
     "//chrome:strings",
     "//chrome/app/resources:platform_locale_settings",
+    "//chrome/app/theme:chrome_unscaled_resources",
     "//chrome/app/theme:theme_resources",
     "//chromeos:cicerone_proto",
     "//chromeos:concierge_proto",
@@ -56,6 +57,7 @@
     "//chrome/app:command_ids",
     "//chrome/app/vector_icons",
     "//chrome/browser:rlz",
+    "//chrome/browser/apps/foundation/app_service:lib",
     "//chrome/browser/devtools",
     "//chrome/browser/extensions",
     "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
@@ -310,6 +312,8 @@
     "apps/intent_helper/apps_navigation_throttle.h",
     "apps/intent_helper/apps_navigation_types.cc",
     "apps/intent_helper/apps_navigation_types.h",
+    "apps/intent_helper/page_transition_util.cc",
+    "apps/intent_helper/page_transition_util.h",
     "arc/accessibility/arc_accessibility_helper_bridge.cc",
     "arc/accessibility/arc_accessibility_helper_bridge.h",
     "arc/accessibility/arc_accessibility_util.cc",
@@ -532,6 +536,10 @@
     "chrome_service_name.h",
     "crostini/crostini_manager.cc",
     "crostini/crostini_manager.h",
+    "crostini/crostini_package_installer_notification.cc",
+    "crostini/crostini_package_installer_notification.h",
+    "crostini/crostini_package_installer_service.cc",
+    "crostini/crostini_package_installer_service.h",
     "crostini/crostini_pref_names.cc",
     "crostini/crostini_pref_names.h",
     "crostini/crostini_registry_service.cc",
@@ -1900,6 +1908,7 @@
     "accessibility/select_to_speak_event_handler_unittest.cc",
     "app_mode/startup_app_launcher_unittest.cc",
     "apps/intent_helper/apps_navigation_throttle_unittest.cc",
+    "apps/intent_helper/page_transition_util_unittest.cc",
     "arc/accessibility/arc_accessibility_helper_bridge_unittest.cc",
     "arc/accessibility/ax_tree_source_arc_unittest.cc",
     "arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc",
diff --git a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.cc
index 32d48d5..20bd1698 100644
--- a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.cc
@@ -10,7 +10,9 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
+#include "chrome/browser/apps/foundation/app_service/public/mojom/types.mojom.h"
 #include "chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h"
+#include "chrome/browser/chromeos/apps/intent_helper/page_transition_util.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/arc_web_contents_data.h"
 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h"
@@ -24,7 +26,6 @@
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/common/chrome_features.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
-#include "components/arc/intent_helper/page_transition_util.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
@@ -62,7 +63,7 @@
 }
 
 // Compares the host name of the referrer and target URL to decide whether
-// the navigation needs to be overriden.
+// the navigation needs to be overridden.
 bool ShouldOverrideUrlLoading(const GURL& previous_url,
                               const GURL& current_url) {
   // When the navigation is initiated in a web page where sending a referrer
@@ -174,13 +175,13 @@
     content::WebContents* web_contents,
     const GURL& url,
     const std::string& launch_name,
-    AppType app_type,
+    apps::mojom::AppType app_type,
     IntentPickerCloseReason close_reason,
     bool should_persist) {
   const bool should_launch_app =
       close_reason == IntentPickerCloseReason::OPEN_APP;
   switch (app_type) {
-    case AppType::PWA:
+    case apps::mojom::AppType::kWeb:
       if (should_launch_app) {
         const extensions::Extension* extension =
             extensions::ExtensionRegistry::Get(
@@ -191,7 +192,7 @@
         ReparentWebContentsIntoAppBrowser(web_contents, extension);
       }
       break;
-    case AppType::ARC:
+    case apps::mojom::AppType::kArc:
       if (arc::ArcNavigationThrottle::MaybeLaunchOrPersistArcApp(
               url, launch_name, should_launch_app, should_persist)) {
         CloseOrGoBack(web_contents);
@@ -199,7 +200,7 @@
         close_reason = IntentPickerCloseReason::ERROR;
       }
       break;
-    case AppType::INVALID:
+    case apps::mojom::AppType::kUnknown:
       // TODO(crbug.com/826982): This workaround can be removed when preferences
       // are no longer persisted within the ARC container, it was necessary
       // since chrome browser is neither a PWA or ARC app.
@@ -212,13 +213,15 @@
       // We reach here if the picker was closed without an app being chosen,
       // e.g. due to the tab being closed. We don't want to do anything.
       break;
+    case apps::mojom::AppType::kCrostini:
+      NOTREACHED();
   }
   RecordUma(launch_name, app_type, close_reason, should_persist);
 }
 
 // static
 void AppsNavigationThrottle::RecordUma(const std::string& selected_app_package,
-                                       AppType app_type,
+                                       apps::mojom::AppType app_type,
                                        IntentPickerCloseReason close_reason,
                                        bool should_persist) {
   PickerAction action = GetPickerAction(app_type, close_reason, should_persist);
@@ -316,7 +319,7 @@
 
 // static
 AppsNavigationThrottle::PickerAction AppsNavigationThrottle::GetPickerAction(
-    AppType app_type,
+    apps::mojom::AppType app_type,
     IntentPickerCloseReason close_reason,
     bool should_persist) {
   switch (close_reason) {
@@ -331,13 +334,15 @@
                             : PickerAction::CHROME_PRESSED;
     case IntentPickerCloseReason::OPEN_APP:
       switch (app_type) {
-        case AppType::INVALID:
+        case apps::mojom::AppType::kUnknown:
           return PickerAction::INVALID;
-        case AppType::ARC:
+        case apps::mojom::AppType::kArc:
           return should_persist ? PickerAction::ARC_APP_PREFERRED_PRESSED
                                 : PickerAction::ARC_APP_PRESSED;
-        case AppType::PWA:
+        case apps::mojom::AppType::kWeb:
           return PickerAction::PWA_APP_PRESSED;
+        case apps::mojom::AppType::kCrostini:
+          NOTREACHED();
       }
   }
 
@@ -375,7 +380,7 @@
 
       // Prefer the web and place apps of type PWA before apps of type ARC.
       // TODO(crbug.com/824598): deterministically sort this list.
-      apps.emplace(apps.begin(), AppType::PWA,
+      apps.emplace(apps.begin(), apps::mojom::AppType::kWeb,
                    menu_manager->GetIconForExtension(extension->id()),
                    extension->id(), extension->name());
     }
@@ -455,7 +460,7 @@
   // available to persist "Remember my choice" for PWAs.
   if (std::all_of(apps_for_picker.begin(), apps_for_picker.end(),
                   [](const IntentPickerAppInfo& app_info) {
-                    return app_info.type == AppType::PWA;
+                    return app_info.type == apps::mojom::AppType::kWeb;
                   })) {
     ui_displayed_ = false;
     Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
@@ -492,8 +497,8 @@
   ui::PageTransition page_transition = handle->GetPageTransition();
   content::WebContents* web_contents = handle->GetWebContents();
   const GURL& url = handle->GetURL();
-  if (arc::ShouldIgnoreNavigation(page_transition, kAllowFormSubmit,
-                                  kAllowClientRedirect)) {
+  if (ShouldIgnoreNavigation(page_transition, kAllowFormSubmit,
+                             kAllowClientRedirect)) {
     if ((page_transition & ui::PAGE_TRANSITION_FORWARD_BACK) ||
         (page_transition & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)) {
       // This enforces that whether we ignore the navigation or not, we make
diff --git a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.h b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.h
index 6c47e41..68c5c3b 100644
--- a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.h
+++ b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.h
@@ -13,6 +13,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/apps/foundation/app_service/public/mojom/types.mojom.h"
 #include "chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "url/gurl.h"
@@ -52,12 +53,12 @@
   static void OnIntentPickerClosed(content::WebContents* web_contents,
                                    const GURL& url,
                                    const std::string& launch_name,
-                                   AppType app_type,
+                                   apps::mojom::AppType app_type,
                                    IntentPickerCloseReason close_reason,
                                    bool should_persist);
 
   static void RecordUma(const std::string& selected_app_package,
-                        AppType app_type,
+                        apps::mojom::AppType app_type,
                         IntentPickerCloseReason close_reason,
                         bool should_persist);
 
@@ -128,7 +129,7 @@
 
   // Converts the provided |app_type|, |close_reason| and |should_persist|
   // boolean to a PickerAction value for recording in UMA.
-  static PickerAction GetPickerAction(AppType app_type,
+  static PickerAction GetPickerAction(apps::mojom::AppType app_type,
                                       IntentPickerCloseReason close_reason,
                                       bool should_persist);
 
diff --git a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle_unittest.cc b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle_unittest.cc
index 7b7ca451..3cc228a 100644
--- a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle_unittest.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle_unittest.cc
@@ -87,110 +87,124 @@
   // Expect PickerAction::ERROR if the close_reason is ERROR.
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::ERROR,
+                apps::mojom::AppType::kUnknown, IntentPickerCloseReason::ERROR,
                 /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::ERROR,
+                apps::mojom::AppType::kArc, IntentPickerCloseReason::ERROR,
                 /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::ERROR,
+                apps::mojom::AppType::kUnknown, IntentPickerCloseReason::ERROR,
                 /*should_persist=*/false));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::ERROR,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::ERROR,
+                apps::mojom::AppType::kArc, IntentPickerCloseReason::ERROR,
                 /*should_persist=*/false));
 
   // Expect PickerAction::DIALOG_DEACTIVATED if the close_reason is
   // DIALOG_DEACTIVATED.
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::DIALOG_DEACTIVATED,
+                apps::mojom::AppType::kUnknown,
+                IntentPickerCloseReason::DIALOG_DEACTIVATED,
                 /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::DIALOG_DEACTIVATED,
+                apps::mojom::AppType::kArc,
+                IntentPickerCloseReason::DIALOG_DEACTIVATED,
                 /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::DIALOG_DEACTIVATED,
+                apps::mojom::AppType::kUnknown,
+                IntentPickerCloseReason::DIALOG_DEACTIVATED,
                 /*should_persist=*/false));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::DIALOG_DEACTIVATED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::DIALOG_DEACTIVATED,
+                apps::mojom::AppType::kArc,
+                IntentPickerCloseReason::DIALOG_DEACTIVATED,
                 /*should_persist=*/false));
 
   // Expect PickerAction::PREFERRED_ACTIVITY_FOUND if the close_reason is
   // PREFERRED_APP_FOUND.
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::PREFERRED_APP_FOUND,
+                apps::mojom::AppType::kUnknown,
+                IntentPickerCloseReason::PREFERRED_APP_FOUND,
                 /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::PREFERRED_APP_FOUND,
+                apps::mojom::AppType::kArc,
+                IntentPickerCloseReason::PREFERRED_APP_FOUND,
                 /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::PREFERRED_APP_FOUND,
+                apps::mojom::AppType::kUnknown,
+                IntentPickerCloseReason::PREFERRED_APP_FOUND,
                 /*should_persist=*/false));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::PREFERRED_ACTIVITY_FOUND,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::PREFERRED_APP_FOUND,
+                apps::mojom::AppType::kArc,
+                IntentPickerCloseReason::PREFERRED_APP_FOUND,
                 /*should_persist=*/false));
 
   // Expect PREFERRED depending on the value of |should_persist|, and |app_type|
   // to be ignored if reason is STAY_IN_CHROME.
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::STAY_IN_CHROME,
+                apps::mojom::AppType::kUnknown,
+                IntentPickerCloseReason::STAY_IN_CHROME,
                 /*should_persist=*/true));
 
-  EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED,
-            AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::STAY_IN_CHROME,
-                /*should_persist=*/true));
+  EXPECT_EQ(
+      AppsNavigationThrottle::PickerAction::CHROME_PREFERRED_PRESSED,
+      AppsNavigationThrottle::GetPickerAction(
+          apps::mojom::AppType::kArc, IntentPickerCloseReason::STAY_IN_CHROME,
+          /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PRESSED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::STAY_IN_CHROME,
+                apps::mojom::AppType::kUnknown,
+                IntentPickerCloseReason::STAY_IN_CHROME,
                 /*should_persist=*/false));
 
-  EXPECT_EQ(AppsNavigationThrottle::PickerAction::CHROME_PRESSED,
-            AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::STAY_IN_CHROME,
-                /*should_persist=*/false));
+  EXPECT_EQ(
+      AppsNavigationThrottle::PickerAction::CHROME_PRESSED,
+      AppsNavigationThrottle::GetPickerAction(
+          apps::mojom::AppType::kArc, IntentPickerCloseReason::STAY_IN_CHROME,
+          /*should_persist=*/false));
 
   // Expect PREFERRED depending on the value of |should_persist|, and
   // INVALID/ARC to be chosen if reason is OPEN_APP.
-  EXPECT_EQ(AppsNavigationThrottle::PickerAction::INVALID,
-            AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::OPEN_APP,
-                /*should_persist=*/true));
+  EXPECT_EQ(
+      AppsNavigationThrottle::PickerAction::INVALID,
+      AppsNavigationThrottle::GetPickerAction(apps::mojom::AppType::kUnknown,
+                                              IntentPickerCloseReason::OPEN_APP,
+                                              /*should_persist=*/true));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::ARC_APP_PREFERRED_PRESSED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::OPEN_APP,
+                apps::mojom::AppType::kArc, IntentPickerCloseReason::OPEN_APP,
                 /*should_persist=*/true));
 
-  EXPECT_EQ(AppsNavigationThrottle::PickerAction::INVALID,
-            AppsNavigationThrottle::GetPickerAction(
-                AppType::INVALID, IntentPickerCloseReason::OPEN_APP,
-                /*should_persist=*/false));
+  EXPECT_EQ(
+      AppsNavigationThrottle::PickerAction::INVALID,
+      AppsNavigationThrottle::GetPickerAction(apps::mojom::AppType::kUnknown,
+                                              IntentPickerCloseReason::OPEN_APP,
+                                              /*should_persist=*/false));
 
   EXPECT_EQ(AppsNavigationThrottle::PickerAction::ARC_APP_PRESSED,
             AppsNavigationThrottle::GetPickerAction(
-                AppType::ARC, IntentPickerCloseReason::OPEN_APP,
+                apps::mojom::AppType::kArc, IntentPickerCloseReason::OPEN_APP,
                 /*should_persist=*/false));
 }
 
diff --git a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.cc b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.cc
index ac7e4459..62d6401 100644
--- a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.cc
@@ -6,7 +6,7 @@
 
 namespace chromeos {
 
-IntentPickerAppInfo::IntentPickerAppInfo(AppType type,
+IntentPickerAppInfo::IntentPickerAppInfo(apps::mojom::AppType type,
                                          const gfx::Image& icon,
                                          const std::string& launch_name,
                                          const std::string& display_name)
diff --git a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h
index 9404e6c..f3d67fa 100644
--- a/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h
+++ b/chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h
@@ -10,22 +10,11 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "chrome/browser/apps/foundation/app_service/public/mojom/types.mojom.h"
 #include "ui/gfx/image/image.h"
 
 namespace chromeos {
 
-enum class AppType {
-  // Used for error scenarios and other cases where the app type isn't going to
-  // be used (e.g. not launching an app).
-  INVALID,
-
-  // An Android app.
-  ARC,
-
-  // A Progressive Web App.
-  PWA,
-};
-
 // Describes the possible ways for the intent picker to be closed.
 enum class IntentPickerCloseReason {
   // There was an error in showing the intent picker.
@@ -70,7 +59,7 @@
 
 // Represents the data required to display an app in a picker to the user.
 struct IntentPickerAppInfo {
-  IntentPickerAppInfo(AppType type,
+  IntentPickerAppInfo(apps::mojom::AppType type,
                       const gfx::Image& icon,
                       const std::string& launch_name,
                       const std::string& display_name);
@@ -80,7 +69,7 @@
   IntentPickerAppInfo& operator=(IntentPickerAppInfo&& other);
 
   // The type of app that this object represents.
-  AppType type;
+  apps::mojom::AppType type;
 
   // The icon to be displayed for this app in the picker.
   gfx::Image icon;
@@ -109,4 +98,14 @@
 
 }  // namespace chromeos
 
+// Callback to pass the launch name and type of the app selected by the user,
+// along with the reason why the Bubble was closed and whether the decision
+// should be persisted. When the reason is ERROR or DIALOG_DEACTIVATED, the
+// values of the launch name, app type, and persistence boolean are all ignored.
+using IntentPickerResponse =
+    base::OnceCallback<void(const std::string& launch_name,
+                            apps::mojom::AppType app_type,
+                            chromeos::IntentPickerCloseReason close_reason,
+                            bool should_persist)>;
+
 #endif  // CHROME_BROWSER_CHROMEOS_APPS_INTENT_HELPER_APPS_NAVIGATION_TYPES_H_
diff --git a/components/arc/intent_helper/page_transition_util.cc b/chrome/browser/chromeos/apps/intent_helper/page_transition_util.cc
similarity index 92%
rename from components/arc/intent_helper/page_transition_util.cc
rename to chrome/browser/chromeos/apps/intent_helper/page_transition_util.cc
index e4cc29db..c6d24a7 100644
--- a/components/arc/intent_helper/page_transition_util.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/page_transition_util.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/arc/intent_helper/page_transition_util.h"
+#include "chrome/browser/chromeos/apps//intent_helper/page_transition_util.h"
 
-namespace arc {
+namespace chromeos {
 
 bool ShouldIgnoreNavigation(ui::PageTransition page_transition,
                             bool allow_form_submit,
@@ -42,4 +42,4 @@
   return ui::PageTransitionFromInt(page_transition & ~mask);
 }
 
-}  // namespace arc
+}  // namespace chromeos
diff --git a/components/arc/intent_helper/page_transition_util.h b/chrome/browser/chromeos/apps/intent_helper/page_transition_util.h
similarity index 71%
rename from components/arc/intent_helper/page_transition_util.h
rename to chrome/browser/chromeos/apps/intent_helper/page_transition_util.h
index d7e726af..0da3b281 100644
--- a/components/arc/intent_helper/page_transition_util.h
+++ b/chrome/browser/chromeos/apps/intent_helper/page_transition_util.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_ARC_INTENT_HELPER_PAGE_TRANSITION_UTIL_H_
-#define COMPONENTS_ARC_INTENT_HELPER_PAGE_TRANSITION_UTIL_H_
+#ifndef CHROME_BROWSER_CHROMEOS_APPS_INTENT_HELPER_PAGE_TRANSITION_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_APPS_INTENT_HELPER_PAGE_TRANSITION_UTIL_H_
 
 #include "base/macros.h"
 #include "ui/base/page_transition_types.h"
 
-namespace arc {
+namespace chromeos {
 
 // Returns true if ARC should ignore the navigation with the |page_transition|.
 bool ShouldIgnoreNavigation(ui::PageTransition page_transition,
@@ -19,6 +19,6 @@
 ui::PageTransition MaskOutPageTransition(ui::PageTransition page_transition,
                                          ui::PageTransition mask);
 
-}  // namespace arc
+}  // namespace chromeos
 
-#endif  // COMPONENTS_ARC_INTENT_HELPER_PAGE_TRANSITION_UTIL_H_
+#endif  // CHROME_BROWSER_CHROMEOS_APPS_INTENT_HELPER_PAGE_TRANSITION_UTIL_H_
diff --git a/components/arc/intent_helper/page_transition_util_unittest.cc b/chrome/browser/chromeos/apps/intent_helper/page_transition_util_unittest.cc
similarity index 98%
rename from components/arc/intent_helper/page_transition_util_unittest.cc
rename to chrome/browser/chromeos/apps/intent_helper/page_transition_util_unittest.cc
index 8c1aeb1..362ec7d 100644
--- a/components/arc/intent_helper/page_transition_util_unittest.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/page_transition_util_unittest.cc
@@ -2,13 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <utility>
-
-#include "components/arc/intent_helper/page_transition_util.h"
+#include "chrome/browser/chromeos/apps/intent_helper/page_transition_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/page_transition_types.h"
 
-namespace arc {
+namespace chromeos {
 
 // Tests that ShouldIgnoreNavigation returns false only for
 // PAGE_TRANSITION_LINK.
@@ -215,4 +213,4 @@
       false, true));
 }
 
-}  // namespace arc
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
index 9f92722..bad48493 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/strings/string_split.h"
 #include "chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
@@ -108,6 +109,7 @@
 
 void ArcInputMethodManagerService::OnImeInfoChanged(
     std::vector<mojom::ImeInfoPtr> ime_info_array) {
+  using chromeos::input_method::InputMethodDescriptor;
   using chromeos::input_method::InputMethodDescriptors;
   using chromeos::input_method::InputMethodManager;
 
@@ -121,8 +123,14 @@
 
   // Convert ime_info_array to InputMethodDescriptors.
   InputMethodDescriptors descriptors;
-  for (const auto& ime_info : ime_info_array)
-    descriptors.push_back(BuildInputMethodDescriptor(ime_info.get()));
+  std::vector<std::string> enabled_input_method_ids;
+  for (const auto& ime_info : ime_info_array) {
+    const InputMethodDescriptor& descriptor =
+        BuildInputMethodDescriptor(ime_info.get());
+    descriptors.push_back(descriptor);
+    if (ime_info->enabled)
+      enabled_input_method_ids.push_back(descriptor.id());
+  }
   if (descriptors.empty()) {
     // If no ARC IME is installed, remove ARC IME entry from preferences.
     RemoveArcIMEFromPrefs();
@@ -131,6 +139,22 @@
   // Add the proxy IME entry to InputMethodManager if any ARC IME is installed.
   state->AddInputMethodExtension(proxy_ime_extension_id_, descriptors,
                                  proxy_ime_engine_.get());
+
+  // Enabled IMEs that are already enabled in the container.
+  const std::string active_ime_ids =
+      profile_->GetPrefs()->GetString(prefs::kLanguageEnabledImes);
+  std::vector<std::string> active_ime_list = base::SplitString(
+      active_ime_ids, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  // TODO(crbug.com/845079): We should keep the order of the IMEs as same as in
+  // chrome://settings
+  for (const auto& input_method_id : enabled_input_method_ids) {
+    if (std::find(active_ime_list.begin(), active_ime_list.end(),
+                  input_method_id) == active_ime_list.end()) {
+      active_ime_list.push_back(input_method_id);
+    }
+  }
+  profile_->GetPrefs()->SetString(prefs::kLanguageEnabledImes,
+                                  base::JoinString(active_ime_list, ","));
 }
 
 void ArcInputMethodManagerService::ImeMenuListChanged() {
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
index b32e43e8..2a8724e 100644
--- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
@@ -342,7 +342,7 @@
   }
 
   {
-    // Adding two ARC IMEs.
+    // Adding two ARC IMEs. One is already enabled.
     std::vector<mojom::ImeInfoPtr> info_array;
     info_array.push_back(info1.Clone());
     info_array.push_back(info2.Clone());
@@ -356,6 +356,12 @@
     EXPECT_EQ(android_ime_id2, ceiu::GetComponentIDByInputMethodID(
                                    std::get<1>(added_extensions[0])[1].id()));
     EXPECT_EQ(display_name2, std::get<1>(added_extensions[0])[1].name());
+
+    // Already enabled IME should be added to the pref automatically.
+    const std::string& arc_ime_id2 = std::get<1>(added_extensions[0])[1].id();
+    EXPECT_EQ(arc_ime_id2,
+              profile()->GetPrefs()->GetString(prefs::kLanguageEnabledImes));
+
     added_extensions.clear();
   }
 }
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
index a13d8a1..8ebdc4ce 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
@@ -10,6 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/chromeos/apps/intent_helper/apps_navigation_throttle.h"
 #include "chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h"
+#include "chrome/browser/chromeos/apps/intent_helper/page_transition_util.h"
 #include "chrome/browser/chromeos/arc/arc_web_contents_data.h"
 #include "chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.h"
 #include "chrome/browser/chromeos/external_protocol_dialog.h"
@@ -19,7 +20,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_service_manager.h"
-#include "components/arc/intent_helper/page_transition_util.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/page_navigator.h"
@@ -350,7 +350,7 @@
                           bool safe_to_bypass_ui,
                           std::vector<mojom::IntentHandlerInfoPtr> handlers,
                           const std::string& selected_app_package,
-                          chromeos::AppType app_type,
+                          apps::mojom::AppType app_type,
                           chromeos::IntentPickerCloseReason reason,
                           bool should_persist) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -395,7 +395,7 @@
     case chromeos::IntentPickerCloseReason::OPEN_APP:
       // Only ARC apps are offered in the external protocol intent picker, so if
       // the user decided to open in app the type must be ARC.
-      DCHECK_EQ(chromeos::AppType::ARC, app_type);
+      DCHECK_EQ(apps::mojom::AppType::kArc, app_type);
       DCHECK(arc_service_manager);
 
       if (should_persist) {
@@ -453,7 +453,7 @@
     const ArcIntentHelperBridge::ActivityName activity(handler->package_name,
                                                        handler->activity_name);
     const auto it = icons->find(activity);
-    app_info.emplace_back(chromeos::AppType::ARC,
+    app_info.emplace_back(apps::mojom::AppType::kArc,
                           it != icons->end() ? it->second.icon16 : gfx::Image(),
                           handler->package_name, handler->name);
   }
@@ -510,7 +510,7 @@
                 handlers.size(), &result, safe_to_bypass_ui)) {
     if (result == GetActionResult::HANDLE_URL_IN_ARC) {
       chromeos::AppsNavigationThrottle::RecordUma(
-          std::string(), chromeos::AppType::ARC,
+          std::string(), apps::mojom::AppType::kArc,
           chromeos::IntentPickerCloseReason::PREFERRED_APP_FOUND,
           /*should_persist=*/false);
     }
@@ -542,11 +542,12 @@
 
   // For external protocol navigation, always ignore the FROM_API qualifier.
   const ui::PageTransition masked_page_transition =
-      MaskOutPageTransition(page_transition, ui::PAGE_TRANSITION_FROM_API);
+      chromeos::MaskOutPageTransition(page_transition,
+                                      ui::PAGE_TRANSITION_FROM_API);
 
-  if (ShouldIgnoreNavigation(masked_page_transition,
-                             /*allow_form_submit=*/true,
-                             /*allow_client_redirect=*/true)) {
+  if (chromeos::ShouldIgnoreNavigation(masked_page_transition,
+                                       /*allow_form_submit=*/true,
+                                       /*allow_client_redirect=*/true)) {
     LOG(WARNING) << "RunArcExternalProtocolDialog: ignoring " << url
                  << " with PageTransition=" << masked_page_transition;
     return false;
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog_unittest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog_unittest.cc
index dd0190b..0ed28c25 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog_unittest.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog_unittest.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/chromeos/arc/arc_web_contents_data.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
-#include "components/arc/intent_helper/page_transition_util.h"
 #include "url/gurl.h"
 
 namespace arc {
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
index 592114b..ced1e8d7 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
@@ -224,7 +224,7 @@
     // iff there are ARC apps which can actually handle the given URL.
     DVLOG(1) << "There are no app candidates for this URL: " << url;
     chromeos::AppsNavigationThrottle::RecordUma(
-        std::string(), chromeos::AppType::INVALID,
+        std::string(), apps::mojom::AppType::kUnknown,
         chromeos::IntentPickerCloseReason::ERROR, /*should_persist=*/false);
     std::move(callback).Run(chromeos::AppsNavigationAction::RESUME, {});
     return;
@@ -281,7 +281,7 @@
 
   chromeos::PreferredPlatform preferred_platform =
       chromeos::PreferredPlatform::NONE;
-  chromeos::AppType app_type = chromeos::AppType::INVALID;
+  apps::mojom::AppType app_type = apps::mojom::AppType::kUnknown;
   const size_t index = FindPreferredApp(app_candidates, url);
 
   if (index != app_candidates.size()) {
@@ -307,7 +307,7 @@
     } else {
       instance->HandleUrl(url.spec(), package_name);
       preferred_platform = chromeos::PreferredPlatform::ARC;
-      app_type = chromeos::AppType::ARC;
+      app_type = apps::mojom::AppType::kArc;
     }
     chromeos::AppsNavigationThrottle::RecordUma(
         package_name, app_type, close_reason, /*should_persist=*/false);
@@ -328,7 +328,7 @@
   if (!intent_helper_bridge) {
     LOG(ERROR) << "Cannot get an instance of ArcIntentHelperBridge";
     chromeos::AppsNavigationThrottle::RecordUma(
-        std::string(), chromeos::AppType::INVALID,
+        std::string(), apps::mojom::AppType::kUnknown,
         chromeos::IntentPickerCloseReason::ERROR, /*should_persist=*/false);
     std::move(callback).Run({});
     return;
@@ -361,7 +361,7 @@
         candidate->package_name, candidate->activity_name);
     const auto it = icons->find(activity);
 
-    app_info.emplace_back(chromeos::AppType::ARC,
+    app_info.emplace_back(apps::mojom::AppType::kArc,
                           it != icons->end() ? it->second.icon16 : gfx::Image(),
                           candidate->package_name, candidate->name);
   }
diff --git a/chrome/browser/chromeos/crostini/crostini_package_installer_notification.cc b/chrome/browser/chromeos/crostini/crostini_package_installer_notification.cc
new file mode 100644
index 0000000..2e8a4a7
--- /dev/null
+++ b/chrome/browser/chromeos/crostini/crostini_package_installer_notification.cc
@@ -0,0 +1,110 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/crostini/crostini_package_installer_notification.h"
+
+#include "chrome/browser/chromeos/crostini/crostini_package_installer_service.h"
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/grit/chrome_unscaled_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/public/cpp/message_center_constants.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notification_delegate.h"
+
+namespace crostini {
+
+namespace {
+
+constexpr char kNotifierCrostiniPackageInstaller[] =
+    "crostini.package_installer";
+
+}  // namespace
+
+CrostiniPackageInstallerNotification::CrostiniPackageInstallerNotification(
+    Profile* profile,
+    const std::string& notification_id,
+    CrostiniPackageInstallerService* installer_service)
+    : installer_service_(installer_service),
+      profile_(profile),
+      weak_ptr_factory_(this) {
+  message_center::RichNotificationData rich_notification_data;
+  // TODO(timloh): This is probably not the right icon...
+  rich_notification_data.small_image =
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+          IDR_LOGO_CROSTINI_DEFAULT);
+  rich_notification_data.never_timeout = true;
+  rich_notification_data.accent_color =
+      message_center::kSystemNotificationColorNormal;
+
+  notification_ = std::make_unique<message_center::Notification>(
+      message_center::NOTIFICATION_TYPE_PROGRESS, notification_id,
+      l10n_util::GetStringUTF16(
+          IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_IN_PROGRESS_TITLE),
+      base::string16(),  // body
+      gfx::Image(),      // icon
+      l10n_util::GetStringUTF16(
+          IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_DISPLAY_SOURCE),
+      GURL(),  // origin_url
+      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
+                                 kNotifierCrostiniPackageInstaller),
+      rich_notification_data,
+      base::MakeRefCounted<message_center::ThunkNotificationDelegate>(
+          weak_ptr_factory_.GetWeakPtr()));
+
+  UpdateDisplayedNotification();
+}
+
+CrostiniPackageInstallerNotification::~CrostiniPackageInstallerNotification() =
+    default;
+
+// TODO(timloh): This doesn't get called if the user shuts down Crostini, so
+// the notification will be stuck at whatever percentage it is at.
+void CrostiniPackageInstallerNotification::UpdateProgress(
+    InstallLinuxPackageProgressStatus result,
+    int progress_percent,
+    const std::string& failure_reason) {
+  if (result == InstallLinuxPackageProgressStatus::SUCCEEDED ||
+      result == InstallLinuxPackageProgressStatus::FAILED) {
+    // The package installer service will stop sending us updates after this.
+    int title_id = IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_COMPLETED_TITLE;
+    int message_id =
+        IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_COMPLETED_MESSAGE;
+    if (result != InstallLinuxPackageProgressStatus::SUCCEEDED) {
+      title_id = IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_ERROR_TITLE;
+      message_id = IDS_CROSTINI_PACKAGE_INSTALL_NOTIFICATION_ERROR_MESSAGE;
+      notification_->set_accent_color(
+          message_center::kSystemNotificationColorCriticalWarning);
+    }
+    notification_->set_title(l10n_util::GetStringUTF16(title_id));
+    notification_->set_message(l10n_util::GetStringUTF16(message_id));
+    notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
+    notification_->set_never_timeout(false);
+  } else {
+    int display_progress = progress_percent / 2;
+    if (result == InstallLinuxPackageProgressStatus::INSTALLING)
+      display_progress += 50;
+    else
+      DCHECK_EQ(InstallLinuxPackageProgressStatus::DOWNLOADING, result);
+
+    notification_->set_progress(display_progress);
+  }
+
+  UpdateDisplayedNotification();
+}
+
+void CrostiniPackageInstallerNotification::Close(bool by_user) {
+  // This call deletes us.
+  installer_service_->NotificationClosed(this);
+}
+
+void CrostiniPackageInstallerNotification::UpdateDisplayedNotification() {
+  NotificationDisplayService* display_service =
+      NotificationDisplayService::GetForProfile(profile_);
+  display_service->Display(NotificationHandler::Type::TRANSIENT,
+                           *notification_);
+}
+
+}  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_package_installer_notification.h b/chrome/browser/chromeos/crostini/crostini_package_installer_notification.h
new file mode 100644
index 0000000..d95f98c
--- /dev/null
+++ b/chrome/browser/chromeos/crostini/crostini_package_installer_notification.h
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_INSTALLER_NOTIFICATION_H_
+#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_INSTALLER_NOTIFICATION_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "ui/message_center/public/cpp/notification_delegate.h"
+
+namespace message_center {
+class Notification;
+}
+
+namespace crostini {
+
+class CrostiniPackageInstallerService;
+
+class CrostiniPackageInstallerNotification
+    : public message_center::NotificationObserver {
+ public:
+  CrostiniPackageInstallerNotification(
+      Profile* profile,
+      const std::string& notification_id,
+      CrostiniPackageInstallerService* installer_service);
+  virtual ~CrostiniPackageInstallerNotification();
+
+  void UpdateProgress(InstallLinuxPackageProgressStatus result,
+                      int progress_percent,
+                      const std::string& failure_reason);
+
+  // message_center::NotificationObserver:
+  void Close(bool by_user) override;
+
+ private:
+  void UpdateDisplayedNotification();
+
+  // These notifications are owned by the installer service.
+  CrostiniPackageInstallerService* installer_service_;
+  Profile* profile_;
+
+  std::unique_ptr<message_center::Notification> notification_;
+
+  base::WeakPtrFactory<CrostiniPackageInstallerNotification> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrostiniPackageInstallerNotification);
+};
+
+}  // namespace crostini
+
+#endif  // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_INSTALLER_NOTIFICATION_H_
diff --git a/chrome/browser/chromeos/crostini/crostini_package_installer_service.cc b/chrome/browser/chromeos/crostini/crostini_package_installer_service.cc
new file mode 100644
index 0000000..9af3055
--- /dev/null
+++ b/chrome/browser/chromeos/crostini/crostini_package_installer_service.cc
@@ -0,0 +1,148 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/crostini/crostini_package_installer_service.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/no_destructor.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace crostini {
+
+namespace {
+
+class CrostiniPackageInstallerServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static CrostiniPackageInstallerService* GetForProfile(Profile* profile) {
+    return static_cast<CrostiniPackageInstallerService*>(
+        GetInstance()->GetServiceForBrowserContext(profile, true));
+  }
+
+  static CrostiniPackageInstallerServiceFactory* GetInstance() {
+    static base::NoDestructor<CrostiniPackageInstallerServiceFactory> factory;
+    return factory.get();
+  }
+
+ private:
+  friend class base::NoDestructor<CrostiniPackageInstallerServiceFactory>;
+
+  CrostiniPackageInstallerServiceFactory()
+      : BrowserContextKeyedServiceFactory(
+            "CrostiniPackageInstallerService",
+            BrowserContextDependencyManager::GetInstance()) {}
+  ~CrostiniPackageInstallerServiceFactory() override = default;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override {
+    Profile* profile = Profile::FromBrowserContext(context);
+    return new CrostiniPackageInstallerService(profile);
+  }
+};
+
+}  // namespace
+
+CrostiniPackageInstallerService* CrostiniPackageInstallerService::GetForProfile(
+    Profile* profile) {
+  return CrostiniPackageInstallerServiceFactory::GetForProfile(profile);
+}
+
+CrostiniPackageInstallerService::CrostiniPackageInstallerService(
+    Profile* profile)
+    : profile_(profile), weak_ptr_factory_(this) {
+  CrostiniManager::GetInstance()->AddInstallLinuxPackageProgressObserver(
+      profile, this);
+}
+
+CrostiniPackageInstallerService::~CrostiniPackageInstallerService() {
+  CrostiniManager::GetInstance()->RemoveInstallLinuxPackageProgressObserver(
+      profile_, this);
+}
+
+void CrostiniPackageInstallerService::NotificationClosed(
+    CrostiniPackageInstallerNotification* notification) {
+  for (auto it = running_notifications_.begin();
+       it != running_notifications_.end(); ++it) {
+    if (it->second.get() == notification) {
+      running_notifications_.erase(it);
+      return;
+    }
+  }
+
+  for (auto it = finished_notifications_.begin();
+       it != finished_notifications_.end(); ++it) {
+    if (it->get() == notification) {
+      finished_notifications_.erase(it);
+      return;
+    }
+  }
+
+  NOTREACHED();
+}
+
+void CrostiniPackageInstallerService::InstallLinuxPackage(
+    const std::string& vm_name,
+    const std::string& container_name,
+    const std::string& package_path,
+    CrostiniManager::InstallLinuxPackageCallback callback) {
+  CrostiniManager::GetInstance()->InstallLinuxPackage(
+      profile_, vm_name, container_name, package_path,
+      base::BindOnce(&CrostiniPackageInstallerService::OnInstallLinuxPackage,
+                     weak_ptr_factory_.GetWeakPtr(), vm_name, container_name,
+                     std::move(callback)));
+}
+
+void CrostiniPackageInstallerService::OnInstallLinuxPackageProgress(
+    const std::string& vm_name,
+    const std::string& container_name,
+    InstallLinuxPackageProgressStatus result,
+    int progress_percent,
+    const std::string& failure_reason) {
+  auto it =
+      running_notifications_.find(std::make_pair(vm_name, container_name));
+  if (it == running_notifications_.end())
+    return;
+  it->second->UpdateProgress(result, progress_percent, failure_reason);
+
+  if (result == InstallLinuxPackageProgressStatus::SUCCEEDED ||
+      result == InstallLinuxPackageProgressStatus::FAILED) {
+    finished_notifications_.emplace_back(std::move(it->second));
+    running_notifications_.erase(it);
+  }
+}
+
+void CrostiniPackageInstallerService::OnInstallLinuxPackage(
+    const std::string& vm_name,
+    const std::string& container_name,
+    CrostiniManager::InstallLinuxPackageCallback callback,
+    ConciergeClientResult result,
+    const std::string& failure_reason) {
+  std::move(callback).Run(result, failure_reason);
+  if (result != ConciergeClientResult::SUCCESS)
+    return;
+
+  std::unique_ptr<CrostiniPackageInstallerNotification>& notification =
+      running_notifications_[std::make_pair(vm_name, container_name)];
+  if (notification) {
+    // We could reach this if the final progress update signal from a previous
+    // package install doesn't get sent, so we wouldn't end up moving the
+    // previous notification out of running_notifications_.
+    LOG(ERROR) << "Notification for package install already exists.";
+    return;
+  }
+
+  notification = std::make_unique<CrostiniPackageInstallerNotification>(
+      profile_, GetUniqueNotificationId(), this);
+}
+
+std::string CrostiniPackageInstallerService::GetUniqueNotificationId() {
+  return base::StringPrintf("crostini_package_install_%d",
+                            next_notification_id++);
+}
+
+}  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_package_installer_service.h b/chrome/browser/chromeos/crostini/crostini_package_installer_service.h
new file mode 100644
index 0000000..ff5b487
--- /dev/null
+++ b/chrome/browser/chromeos/crostini/crostini_package_installer_service.h
@@ -0,0 +1,77 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_INSTALLER_SERVICE_H_
+#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_INSTALLER_SERVICE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "chrome/browser/chromeos/crostini/crostini_package_installer_notification.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace crostini {
+
+class CrostiniPackageInstallerService
+    : public KeyedService,
+      public InstallLinuxPackageProgressObserver {
+ public:
+  static CrostiniPackageInstallerService* GetForProfile(Profile* profile);
+
+  explicit CrostiniPackageInstallerService(Profile* profile);
+  ~CrostiniPackageInstallerService() override;
+
+  void NotificationClosed(CrostiniPackageInstallerNotification* notification);
+
+  // Install a Linux package. If successfully started, a system notification
+  // will be used to display further updates.
+  void InstallLinuxPackage(
+      const std::string& vm_name,
+      const std::string& container_name,
+      const std::string& package_path,
+      CrostiniManager::InstallLinuxPackageCallback callback);
+
+  // InstallLinuxPackageProgressObserver:
+  void OnInstallLinuxPackageProgress(
+      const std::string& vm_name,
+      const std::string& container_name,
+      InstallLinuxPackageProgressStatus result,
+      int progress_percent,
+      const std::string& failure_reason) override;
+
+ private:
+  // Wraps the callback provided in InstallLinuxPackage().
+  void OnInstallLinuxPackage(
+      const std::string& vm_name,
+      const std::string& container_name,
+      CrostiniManager::InstallLinuxPackageCallback callback,
+      ConciergeClientResult result,
+      const std::string& failure_reason);
+
+  std::string GetUniqueNotificationId();
+
+  Profile* profile_;
+
+  // Keyed on <vm_name, container_name>. A container can only have one install
+  // running at a time, but we need to keep notifications around until they're
+  // dismissed.
+  std::map<std::pair<std::string, std::string>,
+           std::unique_ptr<CrostiniPackageInstallerNotification>>
+      running_notifications_;
+  std::vector<std::unique_ptr<CrostiniPackageInstallerNotification>>
+      finished_notifications_;
+
+  int next_notification_id = 0;
+
+  base::WeakPtrFactory<CrostiniPackageInstallerService> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrostiniPackageInstallerService);
+};
+
+}  // namespace crostini
+
+#endif  // CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_PACKAGE_INSTALLER_SERVICE_H_
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.cc b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
index e959bdb..c7d4e3d0c 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
@@ -334,6 +334,10 @@
 
 CrostiniRegistryService::~CrostiniRegistryService() = default;
 
+base::WeakPtr<CrostiniRegistryService> CrostiniRegistryService::GetWeakPtr() {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
 // The code follows these steps to identify apps and returns the first match:
 // 1) Ignore windows if the App Id is prefixed by org.chromium.arc.
 // 2) If the Startup Id is set, look for a matching desktop file id.
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.h b/chrome/browser/chromeos/crostini/crostini_registry_service.h
index 2fed86f5..5466b8d 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.h
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.h
@@ -124,6 +124,8 @@
   explicit CrostiniRegistryService(Profile* profile);
   ~CrostiniRegistryService() override;
 
+  base::WeakPtr<CrostiniRegistryService> GetWeakPtr();
+
   // Returns a shelf app id for an exo window startup id or app id.
   //
   // First try to return a desktop file id matching the |window_startup_id|.
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index 6fdcda5..0ad99da 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -9,6 +9,9 @@
 #include "base/files/file_path.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/string_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chromeos/crostini/crostini_app_launch_observer.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
@@ -17,6 +20,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/virtual_machines/virtual_machines_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/crostini/crostini_app_icon.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/shelf_spinner_controller.h"
 #include "chrome/browser/ui/ash/launcher/shelf_spinner_item_controller.h"
@@ -116,6 +120,96 @@
       base::BindOnce(OnContainerApplicationLaunched, app_id));
 }
 
+// Helper class for loading icons. The callback is called when all icons have
+// been loaded, or after a provided timeout. The waiter deletes itself after
+// all icons have been loaded, or a longer timeout. This longer timeout allows
+// icons that were loading to finish and save to disk if they retrieved an icon
+// from the container, while also ensuring these do not leak if the icons fail
+// to be retrieved.
+// TODO(timloh): This feels like a hack. We should consider having a service,
+// so multiple requests for the same icon won't load the same image multiple
+// times.
+class IconLoadWaiter : public CrostiniAppIcon::Observer {
+ public:
+  static void LoadIcons(
+      Profile* profile,
+      const std::vector<std::string>& app_ids,
+      int resource_size_in_dip,
+      ui::ScaleFactor scale_factor,
+      base::TimeDelta timeout,
+      base::OnceCallback<void(const std::vector<gfx::ImageSkia>&)> callback) {
+    new IconLoadWaiter(profile, app_ids, resource_size_in_dip, scale_factor,
+                       timeout, std::move(callback));
+  }
+
+ private:
+  IconLoadWaiter(
+      Profile* profile,
+      const std::vector<std::string>& app_ids,
+      int resource_size_in_dip,
+      ui::ScaleFactor scale_factor,
+      base::TimeDelta timeout,
+      base::OnceCallback<void(const std::vector<gfx::ImageSkia>&)> callback)
+      : callback_(std::move(callback)) {
+    for (const std::string& app_id : app_ids) {
+      icons_.push_back(std::make_unique<CrostiniAppIcon>(
+          profile, app_id, resource_size_in_dip, this));
+      icons_.back()->LoadForScaleFactor(scale_factor);
+    }
+
+    timeout_timer_.Start(FROM_HERE, timeout, this,
+                         &IconLoadWaiter::RunCallback);
+  }
+
+  void OnIconUpdated(CrostiniAppIcon* icon) override {
+    loaded_icons_++;
+    if (!FinishedLoading())
+      return;
+
+    timeout_timer_.AbandonAndStop();
+    deletion_timer_.AbandonAndStop();
+    if (callback_)
+      RunCallback();
+    // Don't immediately delete as it would destroy the CrostiniAppIcon which is
+    // calling into us right now.
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&IconLoadWaiter::Delete, base::Unretained(this)));
+  }
+
+  bool FinishedLoading() { return loaded_icons_ == icons_.size(); }
+
+  void Delete() {
+    DCHECK(!timeout_timer_.IsRunning());
+    DCHECK(!deletion_timer_.IsRunning());
+    delete this;
+  }
+
+  void RunCallback() {
+    std::vector<gfx::ImageSkia> result;
+    for (const auto& icon : icons_)
+      result.emplace_back(icon->image_skia());
+    std::move(callback_).Run(result);
+
+    if (!FinishedLoading()) {
+      // Leave this object alive for a bit longer so we can finish up requests.
+      deletion_timer_.Start(
+          FROM_HERE, base::TimeDelta::FromSeconds(kDeletionTimeoutInSeconds),
+          this, &IconLoadWaiter::Delete);
+    }
+  }
+
+  static constexpr int kDeletionTimeoutInSeconds = 10;
+
+  std::vector<std::unique_ptr<CrostiniAppIcon>> icons_;
+  size_t loaded_icons_ = 0;
+
+  base::OneShotTimer timeout_timer_;
+  base::OneShotTimer deletion_timer_;
+
+  base::OnceCallback<void(const std::vector<gfx::ImageSkia>&)> callback_;
+};
+
 }  // namespace
 
 void SetCrostiniUIAllowedForTesting(bool enabled) {
@@ -236,6 +330,18 @@
                      std::move(launch_closure)));
 }
 
+void LoadIcons(Profile* profile,
+               const std::vector<std::string>& app_ids,
+               int resource_size_in_dip,
+               ui::ScaleFactor scale_factor,
+               base::TimeDelta timeout,
+               base::OnceCallback<void(const std::vector<gfx::ImageSkia>&)>
+                   icons_loaded_callback) {
+  IconLoadWaiter::LoadIcons(profile, app_ids, resource_size_in_dip,
+                            scale_factor, timeout,
+                            std::move(icons_loaded_callback));
+}
+
 std::string CryptohomeIdForProfile(Profile* profile) {
   std::string id = chromeos::ProfileHelper::GetUserIdHashFromProfile(profile);
   // Empty id means we're running in a test.
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index 971ffdd..124feae1 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -8,11 +8,17 @@
 #include <string>
 
 #include "base/optional.h"
+#include "ui/base/resource/scale_factor.h"
 
 namespace base {
 class FilePath;
+class TimeDelta;
 }  // namespace base
 
+namespace gfx {
+class ImageSkia;
+}  // namespace gfx
+
 class Profile;
 
 // Enables/disables overriding IsCrostiniUIAllowedForProfile's normal
@@ -49,6 +55,17 @@
                        int64_t display_id,
                        const std::vector<std::string>& files);
 
+// Convenience wrapper around CrostiniAppIconLoader. As requesting icons from
+// the container can be slow, we just use the default (penguin) icons after the
+// timeout elapses. Subsequent calls would get the correct icons once loaded.
+void LoadIcons(Profile* profile,
+               const std::vector<std::string>& app_ids,
+               int resource_size_in_dip,
+               ui::ScaleFactor scale_factor,
+               base::TimeDelta timeout,
+               base::OnceCallback<void(const std::vector<gfx::ImageSkia>&)>
+                   icons_loaded_callback);
+
 // Retrieves cryptohome_id from profile.
 std::string CryptohomeIdForProfile(Profile* profile);
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index c963b70..f780021 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -20,6 +20,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "chrome/browser/chromeos/crostini/crostini_package_installer_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
@@ -766,6 +767,56 @@
   Respond(NoArguments());
 }
 
+ExtensionFunction::ResponseAction
+FileManagerPrivateInternalInstallLinuxPackageFunction::Run() {
+  using extensions::api::file_manager_private_internal::InstallLinuxPackage::
+      Params;
+  const std::unique_ptr<Params> params(Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  Profile* profile = Profile::FromBrowserContext(browser_context());
+  const scoped_refptr<storage::FileSystemContext> file_system_context =
+      file_manager::util::GetFileSystemContextForRenderFrameHost(
+          profile, render_frame_host());
+
+  std::string url =
+      file_manager::util::ConvertFileSystemURLToPathInsideCrostini(
+          profile, file_system_context->CrackURL(GURL(params->url)));
+  crostini::CrostiniPackageInstallerService::GetForProfile(profile)
+      ->InstallLinuxPackage(
+          kCrostiniDefaultVmName, kCrostiniDefaultContainerName, url,
+          base::BindOnce(
+              &FileManagerPrivateInternalInstallLinuxPackageFunction::
+                  OnInstallLinuxPackage,
+              this));
+  return RespondLater();
+}
+
+void FileManagerPrivateInternalInstallLinuxPackageFunction::
+    OnInstallLinuxPackage(crostini::ConciergeClientResult result,
+                          const std::string& failure_reason) {
+  extensions::api::file_manager_private::InstallLinuxPackageResponse response;
+  switch (result) {
+    case crostini::ConciergeClientResult::SUCCESS:
+      response = extensions::api::file_manager_private::
+          INSTALL_LINUX_PACKAGE_RESPONSE_STARTED;
+      break;
+    case crostini::ConciergeClientResult::INSTALL_LINUX_PACKAGE_FAILED:
+      response = extensions::api::file_manager_private::
+          INSTALL_LINUX_PACKAGE_RESPONSE_FAILED;
+      break;
+    case crostini::ConciergeClientResult::INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE:
+      response = extensions::api::file_manager_private::
+          INSTALL_LINUX_PACKAGE_RESPONSE_INSTALL_ALREADY_ACTIVE;
+      break;
+    default:
+      NOTREACHED();
+  }
+  Respond(ArgumentList(
+      extensions::api::file_manager_private_internal::InstallLinuxPackage::
+          Results::Create(response, failure_reason)));
+}
+
 FileManagerPrivateInternalGetCustomActionsFunction::
     FileManagerPrivateInternalGetCustomActionsFunction()
     : chrome_details_(this) {}
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
index f9b1146b..05d65f3 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -313,6 +313,23 @@
   scoped_refptr<FileManagerPrivateMountCrostiniContainerFunction> self_;
 };
 
+// Implements the chrome.fileManagerPrivate.installLinuxPackage method.
+// Starts installation of a Linux package.
+class FileManagerPrivateInternalInstallLinuxPackageFunction
+    : public UIThreadExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("fileManagerPrivateInternal.installLinuxPackage",
+                             FILEMANAGERPRIVATEINTERNAL_INSTALLLINUXPACKAGE)
+
+ protected:
+  ~FileManagerPrivateInternalInstallLinuxPackageFunction() override = default;
+
+ private:
+  ResponseAction Run() override;
+  void OnInstallLinuxPackage(crostini::ConciergeClientResult result,
+                             const std::string& failure_reason);
+};
+
 // Implements the chrome.fileManagerPrivate.getCustomActions method.
 class FileManagerPrivateInternalGetCustomActionsFunction
     : public UIThreadExtensionFunction {
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 6134a90..4b742ac 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -558,6 +558,18 @@
   SET_STRING("HOSTED_OFFLINE_MESSAGE", IDS_FILE_BROWSER_HOSTED_OFFLINE_MESSAGE);
   SET_STRING("HOSTED_OFFLINE_MESSAGE_PLURAL",
              IDS_FILE_BROWSER_HOSTED_OFFLINE_MESSAGE_PLURAL);
+  SET_STRING("INSTALL_LINUX_PACKAGE_TITLE",
+             IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_TITLE);
+  SET_STRING("INSTALL_LINUX_PACKAGE_DESCRIPTION",
+             IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_DESCRIPTION);
+  SET_STRING("INSTALL_LINUX_PACKAGE_INSTALL_BUTTON",
+             IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_INSTALL_BUTTON);
+  SET_STRING("INSTALL_LINUX_PACKAGE_INSTALLATION_STARTED",
+             IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_INSTALLATION_STARTED);
+  SET_STRING("INSTALL_LINUX_PACKAGE_ERROR_TITLE",
+             IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_ERROR_TITLE);
+  SET_STRING("INSTALL_LINUX_PACKAGE_ERROR_DESCRIPTION",
+             IDS_FILE_BROWSER_INSTALL_LINUX_PACKAGE_ERROR_DESCRIPTION);
   SET_STRING("INSTALL_NEW_EXTENSION_LABEL",
              IDS_FILE_BROWSER_INSTALL_NEW_EXTENSION_LABEL);
   SET_STRING("MANY_DIRECTORIES_SELECTED",
@@ -754,6 +766,8 @@
              IDS_WEBSTORE_WIDGET_LOADING_SPINNER_ALT);
   SET_STRING("SUGGEST_DIALOG_INSTALLING_SPINNER_ALT",
              IDS_WEBSTORE_WIDGET_INSTALLING_SPINNER_ALT);
+  SET_STRING("TASK_INSTALL_LINUX_PACKAGE",
+             IDS_FILE_BROWSER_TASK_INSTALL_LINUX_PACKAGE);
   SET_STRING("TASK_LISTEN", IDS_FILE_BROWSER_TASK_LISTEN);
   SET_STRING("TASK_OPEN", IDS_FILE_BROWSER_TASK_OPEN);
   SET_STRING("TASK_OPEN_GDOC", IDS_FILE_BROWSER_TASK_OPEN_GDOC);
diff --git a/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc b/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc
index 32a988c2..ee4219a 100644
--- a/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/crostini_file_tasks.cc
@@ -31,6 +31,52 @@
 namespace file_manager {
 namespace file_tasks {
 
+namespace {
+
+constexpr base::TimeDelta kIconLoadTimeout =
+    base::TimeDelta::FromMilliseconds(100);
+constexpr size_t kIconSizeInDip = 16;
+
+GURL GeneratePNGDataUrl(const SkBitmap& sk_bitmap) {
+  std::vector<unsigned char> output;
+  gfx::PNGCodec::EncodeBGRASkBitmap(sk_bitmap, false /* discard_transparency */,
+                                    &output);
+  std::string encoded;
+  base::Base64Encode(
+      base::StringPiece(reinterpret_cast<const char*>(output.data()),
+                        output.size()),
+      &encoded);
+  return GURL("data:image/png;base64," + encoded);
+}
+
+void OnAppIconsLoaded(Profile* profile,
+                      const std::vector<std::string>& app_ids,
+                      ui::ScaleFactor scale_factor,
+                      std::vector<FullTaskDescriptor>* result_list,
+                      base::OnceClosure completion_closure,
+                      const std::vector<gfx::ImageSkia>& icons) {
+  DCHECK(!app_ids.empty());
+  DCHECK_EQ(app_ids.size(), icons.size());
+
+  float scale = ui::GetScaleForScaleFactor(scale_factor);
+
+  crostini::CrostiniRegistryService* registry_service =
+      crostini::CrostiniRegistryServiceFactory::GetForProfile(profile);
+  for (size_t i = 0; i < app_ids.size(); ++i) {
+    result_list->push_back(FullTaskDescriptor(
+        TaskDescriptor(app_ids[i], TASK_TYPE_CROSTINI_APP,
+                       kCrostiniAppActionID),
+        registry_service->GetRegistration(app_ids[i])->Name(),
+        extensions::api::file_manager_private::Verb::VERB_OPEN_WITH,
+        GeneratePNGDataUrl(icons[i].GetRepresentation(scale).sk_bitmap()),
+        false /* is_default */, false /* is_generic */));
+  }
+
+  std::move(completion_closure).Run();
+}
+
+}  // namespace
+
 void FindCrostiniTasks(Profile* profile,
                        const std::vector<extensions::EntryInfo>& entries,
                        std::vector<FullTaskDescriptor>* result_list,
@@ -44,6 +90,8 @@
   for (const extensions::EntryInfo& entry : entries)
     target_mime_types.insert(entry.mime_type);
 
+  std::vector<std::string> result_app_ids;
+
   crostini::CrostiniRegistryService* registry_service =
       crostini::CrostiniRegistryServiceFactory::GetForProfile(profile);
   for (const std::string& app_id : registry_service->GetRegisteredAppIds()) {
@@ -62,16 +110,20 @@
     }
     if (had_unsupported_mime_type)
       continue;
-
-    // TODO(timloh): Add support for Crostini icons
-    result_list->push_back(FullTaskDescriptor(
-        TaskDescriptor(app_id, TASK_TYPE_CROSTINI_APP, kCrostiniAppActionID),
-        registration.Name(),
-        extensions::api::file_manager_private::Verb::VERB_OPEN_WITH, GURL(),
-        false /* is_default */, false /* is_generic */));
+    result_app_ids.push_back(app_id);
   }
 
-  std::move(completion_closure).Run();
+  if (result_app_ids.empty()) {
+    std::move(completion_closure).Run();
+    return;
+  }
+
+  ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactors().back();
+
+  LoadIcons(
+      profile, result_app_ids, kIconSizeInDip, scale_factor, kIconLoadTimeout,
+      base::BindOnce(OnAppIconsLoaded, profile, result_app_ids, scale_factor,
+                     result_list, std::move(completion_closure)));
 }
 
 void ExecuteCrostiniTask(
@@ -81,21 +133,10 @@
     const FileTaskFinishedCallback& done) {
   DCHECK(IsCrostiniUIAllowedForProfile(profile));
 
-  base::FilePath folder(util::GetCrostiniMountPointName(profile));
-
   std::vector<std::string> files;
   for (const storage::FileSystemURL& file_system_url : file_system_urls) {
-    DCHECK(file_system_url.mount_type() == storage::kFileSystemTypeExternal);
-    DCHECK(file_system_url.type() == storage::kFileSystemTypeNativeLocal);
-
-    // Reformat virtual_path()
-    // from <mount_label>/path/to/file
-    // to   /<home-directory>/path/to/file
-    base::FilePath result = HomeDirectoryForProfile(profile);
-    bool success =
-        folder.AppendRelativePath(file_system_url.virtual_path(), &result);
-    DCHECK(success);
-    files.emplace_back(result.AsUTF8Unsafe());
+    files.emplace_back(util::ConvertFileSystemURLToPathInsideCrostini(
+        profile, file_system_url));
   }
 
   LaunchCrostiniApp(profile, task.app_id, display::kInvalidDisplayId, files);
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index 5254ea4..3250d9a 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -132,6 +132,23 @@
   return base::FilePath("/media/fuse/" + GetCrostiniMountPointName(profile));
 }
 
+std::string ConvertFileSystemURLToPathInsideCrostini(
+    Profile* profile,
+    const storage::FileSystemURL& file_system_url) {
+  DCHECK(file_system_url.mount_type() == storage::kFileSystemTypeExternal);
+  DCHECK(file_system_url.type() == storage::kFileSystemTypeNativeLocal);
+
+  // Reformat virtual_path()
+  // from <mount_label>/path/to/file
+  // to   /<home-directory>/path/to/file
+  base::FilePath folder(util::GetCrostiniMountPointName(profile));
+  base::FilePath result = HomeDirectoryForProfile(profile);
+  bool success =
+      folder.AppendRelativePath(file_system_url.virtual_path(), &result);
+  DCHECK(success);
+  return result.AsUTF8Unsafe();
+}
+
 bool ConvertPathToArcUrl(const base::FilePath& path, GURL* arc_url_out) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/chromeos/file_manager/path_util.h b/chrome/browser/chromeos/file_manager/path_util.h
index 6a3d8dc..9a8811b 100644
--- a/chrome/browser/chromeos/file_manager/path_util.h
+++ b/chrome/browser/chromeos/file_manager/path_util.h
@@ -52,6 +52,11 @@
 // The actual directory the crostini "Linux Files" folder is mounted.
 base::FilePath GetCrostiniMountDirectory(Profile* profile);
 
+// Convert a cracked url to a path inside the Crostini VM.
+std::string ConvertFileSystemURLToPathInsideCrostini(
+    Profile* profile,
+    const storage::FileSystemURL& file_system_url);
+
 // DEPRECATED. Use |ConvertToContentUrls| instead.
 // While this function can convert paths under Downloads, /media/removable
 // and /special/drive, this CANNOT convert paths under ARC media directories
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index c29d2add9..71073c2 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -2889,6 +2889,7 @@
       new net::test_server::BasicHttpResponse());
   response->set_code(net::HTTP_OK);
   response->set_content_type("text/plain");
+  response->AddCustomHeader("Content-Disposition", "attachment");
   auto referrer_header = request.headers.find(kReferrerHeader);
   if (referrer_header != request.headers.end())
     response->set_content(referrer_header->second);
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 453a243..90f36646 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -192,6 +192,7 @@
       NOTREACHED();
       FALLTHROUGH;
     case download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT:
     case download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
     case download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH:
       string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
@@ -284,6 +285,7 @@
       FALLTHROUGH;
     // fallthrough
     case download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT:
     case download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
     case download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH:
       string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc
index ab3ebe3..bd201e3 100644
--- a/chrome/browser/download/download_item_model_unittest.cc
+++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -172,6 +172,8 @@
        "Failed - Server unreachable"},
       {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH,
        "Failed - File incomplete"},
+      {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT,
+       "Failed - Download error"},
       {download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, "Canceled"},
       {download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN, "Failed - Shutdown"},
       {download::DOWNLOAD_INTERRUPT_REASON_CRASH, "Failed - Crash"},
@@ -250,6 +252,8 @@
        "foo.bar\nServer unreachable"},
       {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH,
        "foo.bar\nFile incomplete"},
+      {download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT,
+       "foo.bar\nDownload error"},
       {download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED, "foo.bar"},
       {download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN, "foo.bar\nShutdown"},
       {download::DOWNLOAD_INTERRUPT_REASON_CRASH, "foo.bar\nCrash"},
diff --git a/chrome/browser/extensions/error_console/error_console.cc b/chrome/browser/extensions/error_console/error_console.cc
index 81b85ef..c5bae28 100644
--- a/chrome/browser/extensions/error_console/error_console.cc
+++ b/chrome/browser/extensions/error_console/error_console.cc
@@ -175,15 +175,7 @@
 }
 
 bool ErrorConsole::IsEnabledForChromeExtensionsPage() const {
-  if (!profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode)) {
-    return false;  // Only enabled in developer mode.
-  }
-  // If there is a command line switch or override, respect that.
-  if (FeatureSwitch::error_console()->HasValue()) {
-    return FeatureSwitch::error_console()->IsEnabled();
-  }
-  // Enable by default on dev channel, disabled on other channels.
-  return GetCurrentChannel() <= version_info::Channel::DEV;
+  return profile_->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
 }
 
 bool ErrorConsole::IsEnabledForAppsDeveloperTools() const {
diff --git a/chrome/browser/extensions/error_console/error_console_unittest.cc b/chrome/browser/extensions/error_console/error_console_unittest.cc
index b0f4a7b..5ed94e6 100644
--- a/chrome/browser/extensions/error_console/error_console_unittest.cc
+++ b/chrome/browser/extensions/error_console/error_console_unittest.cc
@@ -57,12 +57,6 @@
 
 // Test that the error console is enabled/disabled appropriately.
 TEST_F(ErrorConsoleUnitTest, EnableAndDisableErrorConsole) {
-  // Start in Dev Channel, without the feature switch.
-  std::unique_ptr<ScopedCurrentChannel> channel_override(
-      new ScopedCurrentChannel(version_info::Channel::DEV));
-  ASSERT_EQ(version_info::Channel::DEV, GetCurrentChannel());
-  FeatureSwitch::error_console()->SetOverrideValue(
-      FeatureSwitch::OVERRIDE_DISABLED);
   profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false);
 
   // At the start, the error console should be disabled because the user is not
@@ -72,8 +66,6 @@
   EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
 
   // Switch the error_console on.
-  FeatureSwitch::error_console()->SetOverrideValue(
-      FeatureSwitch::OVERRIDE_ENABLED);
   profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
 
   // The error console should now be enabled, and specifically enabled for the
@@ -88,36 +80,8 @@
   EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
   EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
 
-  // Similarly, if we change the current to less fun than Dev, ErrorConsole
-  // should be disabled.
-  channel_override.reset();
-  channel_override.reset(
-      new ScopedCurrentChannel(version_info::Channel::BETA));
-  FeatureSwitch::error_console()->SetOverrideValue(
-      FeatureSwitch::OVERRIDE_NONE);
-  profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
-  EXPECT_FALSE(error_console_->enabled());
-  EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
-  EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
-
-  // If we add the feature switch, that should override the channel.
-  FeatureSwitch::error_console()->SetOverrideValue(
-      FeatureSwitch::OVERRIDE_ENABLED);
-  ASSERT_TRUE(FeatureSwitch::error_console()->IsEnabled());
-  // We use a pref mod to "poke" the ErrorConsole, because it needs an
-  // indication that something changed (FeatureSwitches don't change in a real
-  // environment, so ErrorConsole doesn't listen for them).
-  profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false);
-  profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
-  EXPECT_TRUE(error_console_->enabled());
-  EXPECT_TRUE(error_console_->IsEnabledForChromeExtensionsPage());
-  EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
-
-  // Next, remove the feature switch (turning error console off), and install
-  // the Apps Developer Tools. If we have Apps Developer Tools, Error Console
-  // should be enabled by default.
-  FeatureSwitch::error_console()->SetOverrideValue(
-      FeatureSwitch::OVERRIDE_DISABLED);
+  // Installing the Chrome Apps and Extensions Developer Tools should enable
+  // the ErrorConsole, same as if the profile were in developer mode.
   const char kAppsDeveloperToolsExtensionId[] =
       "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
   scoped_refptr<Extension> adt =
@@ -144,6 +108,26 @@
   EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
 }
 
+// Test that the error console is enabled for all channels.
+TEST_F(ErrorConsoleUnitTest, EnabledForAllChannels) {
+  version_info::Channel channels[] = {
+      version_info::Channel::UNKNOWN, version_info::Channel::CANARY,
+      version_info::Channel::DEV, version_info::Channel::BETA,
+      version_info::Channel::STABLE};
+  for (const version_info::Channel channel : channels) {
+    ScopedCurrentChannel channel_override(channel);
+    ASSERT_EQ(channel, GetCurrentChannel());
+
+    profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false);
+    EXPECT_FALSE(error_console_->enabled());
+    EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
+
+    profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
+    EXPECT_TRUE(error_console_->enabled());
+    EXPECT_TRUE(error_console_->IsEnabledForChromeExtensionsPage());
+  }
+}
+
 // Test that errors are successfully reported. This is a simple test, since it
 // is tested more thoroughly in extensions/browser/error_map_unittest.cc
 TEST_F(ErrorConsoleUnitTest, ReportErrors) {
diff --git a/chrome/browser/net/reporting_browsertest.cc b/chrome/browser/net/reporting_browsertest.cc
index 45130ae..28c3fe85 100644
--- a/chrome/browser/net/reporting_browsertest.cc
+++ b/chrome/browser/net/reporting_browsertest.cc
@@ -152,13 +152,12 @@
               "status_code": 204,
               "phase": "application",
               "type": "ok",
-              "uri": "https://example.com:%d/original",
             },
             "type": "network-error",
             "url": "https://example.com:%d/original",
           },
         ]
       )json",
-      port(), port()));
+      port()));
   EXPECT_EQ(*expected, *actual);
 }
diff --git a/chrome/browser/ntp_tiles/chrome_custom_links_manager_factory.cc b/chrome/browser/ntp_tiles/chrome_custom_links_manager_factory.cc
index 666db8f..23905e5 100644
--- a/chrome/browser/ntp_tiles/chrome_custom_links_manager_factory.cc
+++ b/chrome/browser/ntp_tiles/chrome_custom_links_manager_factory.cc
@@ -10,7 +10,7 @@
 
 std::unique_ptr<ntp_tiles::CustomLinksManager>
 ChromeCustomLinksManagerFactory::NewForProfile(Profile* profile) {
-  if (!ntp_tiles::IsMDCustomLinksEnabled()) {
+  if (!ntp_tiles::IsCustomLinksEnabled()) {
     return nullptr;
   }
   return std::make_unique<ntp_tiles::CustomLinksManagerImpl>(
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 81f00a3..269cf63f 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -208,6 +208,44 @@
                 .WaitAndGetTitle());
 }
 
+// Tests that when a custom control is clicked on a Picture-in-Picture window
+// an event is sent to the caller.
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       PictureInPictureControlEventFired) {
+  GURL test_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(
+          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
+  ui_test_utils::NavigateToURL(browser(), test_page_url);
+
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(active_web_contents);
+
+  SetUpWindowController(active_web_contents);
+  ASSERT_TRUE(window_controller());
+
+  content::OverlayWindow* overlay_window =
+      window_controller()->GetWindowForTesting();
+  ASSERT_TRUE(overlay_window);
+  ASSERT_FALSE(overlay_window->IsVisible());
+
+  bool result = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      active_web_contents, "enterPictureInPicture();", &result));
+  EXPECT_TRUE(result);
+
+  std::string control_id = "Test custom control ID";
+  base::string16 expected_title = base::ASCIIToUTF16(control_id);
+
+  static_cast<OverlayWindowViews*>(overlay_window)
+      ->ClickCustomControl(control_id);
+
+  EXPECT_EQ(expected_title,
+            content::TitleWatcher(active_web_contents, expected_title)
+                .WaitAndGetTitle());
+}
+
 #endif  // !defined(OS_ANDROID)
 
 // Tests that when closing a Picture-in-Picture window, the video element is
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index 7cabe64..b5fea3d 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -9,7 +9,6 @@
 #include "chrome/common/pref_names.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
-#include "components/browsing_data/core/pref_names.h"
 #include "components/certificate_transparency/pref_names.h"
 #include "components/component_updater/pref_names.h"
 #include "components/consent_auditor/pref_names.h"
@@ -50,6 +49,7 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/android/contextual_suggestions/contextual_suggestions_prefs.h"
+#include "components/feed/buildflags.h"
 #include "components/feed/core/pref_names.h"
 #endif  // defined(OS_ANDROID)
 
@@ -82,7 +82,6 @@
 // storage default, from on disk to in memory. All items in this list will be
 // audited and checked with owners and removed from whitelist.
 const char* incognito_whitelist[] = {
-
 // ash/public/cpp/ash_pref_names.h
 #if defined(OS_CHROMEOS)
     ash::prefs::kAccessibilityLargeCursorEnabled,
@@ -838,7 +837,7 @@
 
 #if !defined(OS_ANDROID)
     prefs::kAutoplayAllowed, prefs::kAutoplayWhitelist,
-    prefs::kNTPCustomBackgroundURL,
+    prefs::kNtpCustomBackgroundDict,
 #endif
 
 // chromeos/chromeos_pref_names.h
@@ -918,25 +917,6 @@
     bookmarks::prefs::kShowManagedBookmarksInBookmarkBar,
     bookmarks::prefs::kShowBookmarkBar,
 
-    // components/browsing_data/core/pref_names.h
-    browsing_data::prefs::kDeleteTimePeriod,
-    browsing_data::prefs::kDeleteTimePeriodBasic,
-    browsing_data::prefs::kDeleteBrowsingHistory,
-    browsing_data::prefs::kDeleteBrowsingHistoryBasic,
-    browsing_data::prefs::kDeleteDownloadHistory,
-    browsing_data::prefs::kDeleteCache, browsing_data::prefs::kDeleteCacheBasic,
-    browsing_data::prefs::kDeleteCookies,
-    browsing_data::prefs::kDeleteCookiesBasic,
-    browsing_data::prefs::kDeletePasswords,
-    browsing_data::prefs::kDeleteFormData,
-    browsing_data::prefs::kDeleteHostedAppsData,
-    browsing_data::prefs::kDeleteMediaLicenses,
-    browsing_data::prefs::kDeleteSiteSettings,
-    browsing_data::prefs::kLastClearBrowsingDataTime,
-    browsing_data::prefs::kClearBrowsingDataHistoryNoticeShownTimes,
-    browsing_data::prefs::kLastClearBrowsingDataTab,
-    browsing_data::prefs::kPreferencesMigratedToBasic,
-
     // components/certificate_transparency/pref_names.h
     certificate_transparency::prefs::kCTRequiredHosts,
     certificate_transparency::prefs::kCTExcludedHosts,
@@ -1082,11 +1062,13 @@
 
 // components/feed/core/pref_names.h
 #if defined(OS_ANDROID)
+#if BUILDFLAG(ENABLE_FEED_IN_CHROME)
     feed::prefs::kBackgroundRefreshPeriod, feed::prefs::kLastFetchAttemptTime,
     feed::prefs::kUserClassifierAverageNTPOpenedPerHour,
     feed::prefs::kUserClassifierAverageSuggestionsUsedPerHour,
     feed::prefs::kUserClassifierLastTimeToOpenNTP,
     feed::prefs::kUserClassifierLastTimeToUseSuggestions,
+#endif  // BUILDFLAG(ENABLE_FEED_IN_CHROME)
 #endif  // defined(OS_ANDROID)
 
     // components/flags_ui/flags_ui_pref_names.h
diff --git a/chrome/browser/prefs/pref_service_syncable_util.cc b/chrome/browser/prefs/pref_service_syncable_util.cc
index 6e1755d..824f18a8 100644
--- a/chrome/browser/prefs/pref_service_syncable_util.cc
+++ b/chrome/browser/prefs/pref_service_syncable_util.cc
@@ -34,7 +34,7 @@
 
   // TODO(https://crbug.com/861722): Remove |GetIncognitoWhitelist| and its
   // file. This list is ONLY added for transition of code from blacklist to
-  // whitelist. All whitelisted prefs can be added here to
+  // whitelist. All whitelisted prefs should be added here to
   // |persistent_pref_names|.
   prefs::GetIncognitoWhitelist(&persistent_pref_names);
 
diff --git a/chrome/browser/resources/PRESUBMIT.py b/chrome/browser/resources/PRESUBMIT.py
index 4544007..b57bdba 100644
--- a/chrome/browser/resources/PRESUBMIT.py
+++ b/chrome/browser/resources/PRESUBMIT.py
@@ -138,12 +138,3 @@
 
 def CheckChangeOnCommit(input_api, output_api):
   return _CheckChangeOnUploadOrCommit(input_api, output_api)
-
-
-def PostUploadHook(cl, change, output_api):
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:closure_compilation',
-    ],
-    'Automatically added optional Closure bots to run on CQ.')
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js b/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js
index 918b985..a7f19e8 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_welcome.js
@@ -23,24 +23,13 @@
     decorate: function() {
       var welcomeScreen = $('oobe-welcome-md');
       welcomeScreen.screen = this;
-      welcomeScreen.enabled = true;
-
-      var languageList = loadTimeData.getValue('languageList');
-      welcomeScreen.languages = languageList;
-
-      var inputMethodsList = loadTimeData.getValue('inputMethodsList');
-      welcomeScreen.keyboards = inputMethodsList;
-
-      var timezoneList = loadTimeData.getValue('timezoneList');
-      welcomeScreen.timezones = timezoneList;
-
-      welcomeScreen.highlightStrength =
-          loadTimeData.getValue('highlightStrength');
 
       this.context.addObserver(
           CONTEXT_KEY_INPUT_METHOD, function(inputMethodId) {
             $('oobe-welcome-md').setSelectedKeyboard(inputMethodId);
           });
+
+      this.updateLocalizedContent();
     },
 
     onLanguageSelected_: function(languageId) {
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.html b/chrome/browser/resources/chromeos/login/oobe_welcome.html
index f73a042a..79ea4645 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.html
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.html
@@ -75,34 +75,32 @@
       </hd-iron-icon>
       <h1 slot="title">[[i18nDynamic(locale, 'languageSectionTitle')]]</h1>
       <div slot="footer" class="layout vertical">
-        <template is="dom-if" if="[[enabled]]">
-          <div id="languageDropdownContainer"
-              class="flex layout center horizontal justified
-                  language-selection-entry">
-            <div class=
-                "language-selection-title layout vertical center-justified">
-              [[i18nDynamic(locale, 'languageDropdownTitle')]]
-            </div>
-            <oobe-i18n-dropdown id="languageSelect" items="[[languages]]"
-                on-select-item="onLanguageSelected_" class="focus-on-show"
-                label-for-aria=
-                    "[[i18nDynamic(locale, 'languageDropdownLabel')]]">
-            </oobe-i18n-dropdown>
+        <div id="languageDropdownContainer"
+            class="flex layout center horizontal justified
+                language-selection-entry">
+          <div class=
+              "language-selection-title layout vertical center-justified">
+            [[i18nDynamic(locale, 'languageDropdownTitle')]]
           </div>
-          <div id="keyboardDropdownContainer"
-              class="flex layout center horizontal justified
-                 language-selection-entry">
-            <div class=
-                "language-selection-title layout vertical center-justified">
-              [[i18nDynamic(locale, 'keyboardDropdownTitle')]]
-            </div>
-            <oobe-i18n-dropdown id="keyboardSelect" items="[[keyboards]]"
-                on-select-item="onKeyboardSelected_"
-                label-for-aria=
-                    "[[i18nDynamic(locale, 'keyboardDropdownLabel')]]">
-            </oobe-i18n-dropdown>
+          <oobe-i18n-dropdown id="languageSelect" items="[[languages]]"
+              on-select-item="onLanguageSelected_" class="focus-on-show"
+              label-for-aria=
+                  "[[i18nDynamic(locale, 'languageDropdownLabel')]]">
+          </oobe-i18n-dropdown>
+        </div>
+        <div id="keyboardDropdownContainer"
+            class="flex layout center horizontal justified
+               language-selection-entry">
+          <div class=
+              "language-selection-title layout vertical center-justified">
+            [[i18nDynamic(locale, 'keyboardDropdownTitle')]]
           </div>
-        </template>
+          <oobe-i18n-dropdown id="keyboardSelect" items="[[keyboards]]"
+              on-select-item="onKeyboardSelected_"
+              label-for-aria=
+                  "[[i18nDynamic(locale, 'keyboardDropdownLabel')]]">
+          </oobe-i18n-dropdown>
+        </div>
       </div>
       <div slot="bottom-buttons" class="layout horizontal end-justified">
         <oobe-text-button inverse on-tap="closeLanguageSection_">
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index a4983db..4342c357 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -47,14 +47,6 @@
     },
 
     /**
-     * Flag that enables MD-OOBE.
-     */
-    enabled: {
-      type: Boolean,
-      value: false,
-    },
-
-    /**
      * Accessibility options status.
      * @type {!OobeTypes.A11yStatuses}
      */
@@ -111,6 +103,11 @@
    * This is called when UI strings are changed.
    */
   updateLocalizedContent: function() {
+    this.languages = loadTimeData.getValue('languageList');
+    this.keyboards = loadTimeData.getValue('inputMethodsList');
+    this.timezones = loadTimeData.getValue('timezoneList');
+    this.highlightStrength = loadTimeData.getValue('highlightStrength');
+
     this.$.networkSelectionScreen.i18nUpdateLocale();
     this.$.welcomeScreen.i18nUpdateLocale();
     this.i18nUpdateLocale();
diff --git a/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn b/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
index 74f4bc54..ec431466 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
+++ b/chrome/browser/resources/chromeos/select_to_speak/BUILD.gn
@@ -35,6 +35,7 @@
     "closure_shim.js",
     "earcons/null_selection.ogg",
     "input_handler.js",
+    "metrics_utils.js",
     "node_utils.js",
     "options.css",
     "options.html",
@@ -171,6 +172,7 @@
     ":../chromevox/cvox2/background/tree_walker",
     ":closure_shim",
     ":input_handler",
+    ":metrics_utils",
     ":node_utils",
     ":paragraph_utils",
     ":rect_utils",
@@ -185,6 +187,7 @@
     ":../chromevox/cvox2/background/automation_util",
     ":../chromevox/cvox2/background/constants",
     ":input_handler",
+    ":metrics_utils",
     ":node_utils",
     ":paragraph_utils",
     ":rect_utils",
@@ -196,7 +199,6 @@
     "$externs_path/chrome_extensions.js",
     "$externs_path/clipboard.js",
     "$externs_path/command_line_private.js",
-    "$externs_path/metrics_private.js",
     "externs.js",
   ]
 }
@@ -250,6 +252,10 @@
 js_library("rect_utils") {
 }
 
+js_library("metrics_utils") {
+  externs_list = [ "$externs_path/metrics_private.js" ]
+}
+
 js_library("../chromevox/cvox2/background/automation_util") {
   deps = [
     ":../chromevox/cvox2/background/automation_predicate",
diff --git a/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2 b/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2
index 10bf747c..4b13056 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/select_to_speak/manifest.json.jinja2
@@ -17,6 +17,7 @@
       "tree_walker.js",
       "automation_util.js",
       "input_handler.js",
+      "metrics_utils.js",
       "node_utils.js",
       "paragraph_utils.js",
       "word_utils.js",
diff --git a/chrome/browser/resources/chromeos/select_to_speak/metrics_utils.js b/chrome/browser/resources/chromeos/select_to_speak/metrics_utils.js
new file mode 100644
index 0000000..582c56e
--- /dev/null
+++ b/chrome/browser/resources/chromeos/select_to_speak/metrics_utils.js
@@ -0,0 +1,176 @@
+// 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.
+
+// Utilities for UMA metrics.
+
+/**
+ * @constructor
+ */
+let MetricsUtils = function() {};
+
+/**
+ * Defines an enumeration metric. The |EVENT_COUNT| must be kept in sync
+ * with the number of enum values for each metric in
+ * tools/metrics/histograms/enums.xml.
+ * @typedef {{EVENT_COUNT: number, METRIC_NAME: string}}
+ */
+MetricsUtils.EnumerationMetric;
+
+/**
+ * CrosSelectToSpeakStartSpeechMethod enums.
+ * These values are persisted to logs and should not be renumbered or re-used.
+ * See tools/metrics/histograms/enums.xml.
+ * @enum {number}
+ */
+MetricsUtils.StartSpeechMethod = {
+  MOUSE: 0,
+  KEYSTROKE: 1,
+};
+
+/**
+ * Constants for the start speech method metric,
+ * CrosSelectToSpeakStartSpeechMethod.
+ * @type {MetricsUtils.EnumerationMetric}
+ */
+MetricsUtils.START_SPEECH_METHOD_METRIC = {
+  EVENT_COUNT: Object.keys(MetricsUtils.StartSpeechMethod).length,
+  METRIC_NAME: 'Accessibility.CrosSelectToSpeak.StartSpeechMethod'
+};
+
+/**
+ * CrosSelectToSpeakStateChangeEvent enums.
+ * These values are persisted to logs and should not be renumbered or re-used.
+ * See tools/metrics/histograms/enums.xml.
+ * @enum {number}
+ */
+MetricsUtils.StateChangeEvent = {
+  START_SELECTION: 0,
+  CANCEL_SPEECH: 1,
+  CANCEL_SELECTION: 2,
+};
+
+/**
+ * Constants for the state change metric, CrosSelectToSpeakStateChangeEvent.
+ * @type {MetricsUtils.EnumerationMetric}
+ */
+MetricsUtils.STATE_CHANGE_METRIC = {
+  EVENT_COUNT: Object.keys(MetricsUtils.StateChangeEvent).length,
+  METRIC_NAME: 'Accessibility.CrosSelectToSpeak.StateChangeEvent'
+};
+
+/**
+ * The start speech metric name.
+ * @type {string}
+ */
+MetricsUtils.START_SPEECH_METRIC =
+    'Accessibility.CrosSelectToSpeak.StartSpeech';
+
+/**
+ * The cancel speech metric name.
+ * @type {string}
+ */
+MetricsUtils.CANCEL_SPEECH_METRIC =
+    'Accessibility.CrosSelectToSpeak.CancelSpeech';
+
+/**
+ * The speech pitch histogram metric name.
+ * @type {string}
+ */
+MetricsUtils.SPEECH_PITCH_METRIC =
+    'Accessibility.CrosSelectToSpeak.SpeechPitch';
+
+/**
+ * The speech rate histogram metric name.
+ * @type {string}
+ */
+MetricsUtils.SPEECH_RATE_METRIC = 'Accessibility.CrosSelectToSpeak.SpeechRate';
+
+/**
+ * The word highlighting metric name.
+ * @type {string}
+ */
+MetricsUtils.WORD_HIGHLIGHTING_METRIC =
+    'Accessibility.CrosSelectToSpeak.WordHighlighting';
+
+
+/**
+ * Records a cancel event if speech was in progress.
+ * @param {boolean} speaking Whether speech was in progress
+ * @public
+ */
+MetricsUtils.recordCancelIfSpeaking = function(speaking) {
+  if (speaking) {
+    MetricsUtils.recordCancelEvent_();
+  }
+};
+
+/**
+ * Converts the speech rate into an enum based on
+ * tools/metrics/histograms/enums.xml.
+ * These values are persisted to logs. Entries should not be
+ * renumbered and numeric values should never be reused.
+ * @param {number} speechRate The current speech rate.
+ * @return {number} The current speech rate as an int for metrics.
+ * @private
+ */
+MetricsUtils.speechRateToSparceHistogramInt_ = function(speechRate) {
+  return speechRate * 100;
+};
+
+/**
+ * Converts the speech pitch into an enum based on
+ * tools/metrics/histograms/enums.xml.
+ * These values are persisted to logs. Entries should not be
+ * renumbered and numeric values should never be reused.
+ * @param {number} speechPitch The current speech pitch.
+ * @return {number} The current speech pitch as an int for metrics.
+ * @private
+ */
+MetricsUtils.speechPitchToSparceHistogramInt_ = function(speechPitch) {
+  return speechPitch * 100;
+};
+
+/**
+ * Records an event that Select-to-Speak has begun speaking.
+ * @param {number} method The CrosSelectToSpeakStartSpeechMethod enum
+ *    that reflects how this event was triggered by the user.
+ * @param {number} speechRate The current speech rate.
+ * @param {number} speechPitch The current speech pitch.
+ * @param {boolean} wordHighlightingEnabled If word highlighting is enabled.
+ * @public
+ */
+MetricsUtils.recordStartEvent = function(
+    method, speechRate, speechPitch, wordHighlightingEnabled) {
+  chrome.metricsPrivate.recordUserAction(MetricsUtils.START_SPEECH_METRIC);
+  chrome.metricsPrivate.recordSparseValue(
+      MetricsUtils.SPEECH_RATE_METRIC,
+      MetricsUtils.speechRateToSparceHistogramInt_(speechRate));
+  chrome.metricsPrivate.recordSparseValue(
+      MetricsUtils.SPEECH_PITCH_METRIC,
+      MetricsUtils.speechPitchToSparceHistogramInt_(speechPitch));
+  chrome.metricsPrivate.recordBoolean(
+      MetricsUtils.WORD_HIGHLIGHTING_METRIC, wordHighlightingEnabled);
+  chrome.metricsPrivate.recordEnumerationValue(
+      MetricsUtils.START_SPEECH_METHOD_METRIC.METRIC_NAME, method,
+      MetricsUtils.START_SPEECH_METHOD_METRIC.EVENT_COUNT);
+};
+
+/**
+ * Records an event that Select-to-Speak speech has been canceled.
+ * @private
+ */
+MetricsUtils.recordCancelEvent_ = function() {
+  chrome.metricsPrivate.recordUserAction(MetricsUtils.CANCEL_SPEECH_METRIC);
+};
+
+/**
+ * Records a user-requested state change event from a given state.
+ * @param {number} changeType
+ * @public
+ */
+MetricsUtils.recordSelectToSpeakStateChangeEvent = function(changeType) {
+  chrome.metricsPrivate.recordEnumerationValue(
+      MetricsUtils.STATE_CHANGE_METRIC.METRIC_NAME, changeType,
+      MetricsUtils.STATE_CHANGE_METRIC.EVENT_COUNT);
+};
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
index 11fc9b8..de550f9 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
@@ -6,50 +6,6 @@
 var EventType = chrome.automation.EventType;
 var RoleType = chrome.automation.RoleType;
 
-/**
- * CrosSelectToSpeakStartSpeechMethod enums.
- * These values are persisted to logs and should not be renumbered or re-used.
- * See tools/metrics/histograms/enums.xml.
- * @enum {number}
- */
-const StartSpeechMethod = {
-  MOUSE: 0,
-  KEYSTROKE: 1,
-};
-
-/**
- * The number of enum values in CrosSelectToSpeakStartSpeechMethod. This should
- * be kept in sync with the enum count in tools/metrics/histograms/enums.xml.
- * @type {number}
- */
-const START_SPEECH_METHOD_COUNT = Object.keys(StartSpeechMethod).length;
-
-/**
- * CrosSelectToSpeakStateChangeEvent enums.
- * These values are persisted to logs and should not be renumbered or re-used.
- * See tools/metrics/histograms/enums.xml.
- * @enum {number}
- */
-const StateChangeEvent = {
-  START_SELECTION: 0,
-  CANCEL_SPEECH: 1,
-  CANCEL_SELECTION: 2,
-};
-
-/**
- * The number of enum values in CrosSelectToSpeakStateChangeEvent. This should
- * be kept in sync with the enum count in tools/metrics/histograms/enums.xml.
- * @type {number}
- */
-const STATE_CHANGE_EVENT_COUNT = Object.keys(StateChangeEvent).length;
-
-/**
- * The name of the state change request metric.
- * @type {string}
- */
-const STATE_CHANGE_EVENT_METRIC_NAME =
-    'Accessibility.CrosSelectToSpeak.StateChangeEvent';
-
 // This must be the same as in ash/system/accessibility/select_to_speak_tray.cc:
 // ash::kSelectToSpeakTrayClassName.
 const SELECT_TO_SPEAK_TRAY_CLASS_NAME =
@@ -237,7 +193,9 @@
         return;
       }
       this.startSpeechQueue_(nodes);
-      this.recordStartEvent_(StartSpeechMethod.MOUSE);
+      MetricsUtils.recordStartEvent(
+          MetricsUtils.StartSpeechMethod.MOUSE, this.speechRate_,
+          this.speechPitch_, this.wordHighlight_);
     }.bind(this));
   },
 
@@ -391,7 +349,9 @@
       return;
     }
     this.initializeScrollingToOffscreenNodes_(focusedNode.root);
-    this.recordStartEvent_(StartSpeechMethod.KEYSTROKE);
+    MetricsUtils.recordStartEvent(
+        MetricsUtils.StartSpeechMethod.KEYSTROKE, this.speechRate_,
+        this.speechPitch_, this.wordHighlight_);
   },
 
   /**
@@ -527,21 +487,21 @@
         // Start selection.
         this.inputHandler_.setTrackingMouse(true);
         this.onStateChanged_(SelectToSpeakState.SELECTING);
-        this.recordSelectToSpeakStateChangeEvent_(
-            StateChangeEvent.START_SELECTION);
+        MetricsUtils.recordSelectToSpeakStateChangeEvent(
+            MetricsUtils.StateChangeEvent.START_SELECTION);
         break;
       case SelectToSpeakState.SPEAKING:
         // Stop speaking.
         this.cancelIfSpeaking_(true /* clear the focus ring */);
-        this.recordSelectToSpeakStateChangeEvent_(
-            StateChangeEvent.CANCEL_SPEECH);
+        MetricsUtils.recordSelectToSpeakStateChangeEvent(
+            MetricsUtils.StateChangeEvent.CANCEL_SPEECH);
         break;
       case SelectToSpeakState.SELECTING:
         // Cancelled selection.
         this.inputHandler_.setTrackingMouse(false);
         this.onStateChanged_(SelectToSpeakState.INACTIVE);
-        this.recordSelectToSpeakStateChangeEvent_(
-            StateChangeEvent.CANCEL_SELECTION);
+        MetricsUtils.recordSelectToSpeakStateChangeEvent(
+            MetricsUtils.StateChangeEvent.CANCEL_SELECTION);
     }
     this.onStateChangeRequestedCallbackForTest_ &&
         this.onStateChangeRequestedCallbackForTest_();
@@ -769,7 +729,7 @@
    *    as well.
    */
   cancelIfSpeaking_: function(clearFocusRing) {
-    chrome.tts.isSpeaking(this.recordCancelIfSpeaking_.bind(this));
+    chrome.tts.isSpeaking(MetricsUtils.recordCancelIfSpeaking);
     if (clearFocusRing) {
       this.stopAll_();
     } else {
@@ -779,77 +739,6 @@
   },
 
   /**
-   * Records a cancel event if speech was in progress.
-   * @param {boolean} speaking Whether speech was in progress
-   */
-  recordCancelIfSpeaking_: function(speaking) {
-    if (speaking) {
-      this.recordCancelEvent_();
-    }
-  },
-
-  /**
-   * Converts the speech rate into an enum based on
-   * tools/metrics/histograms/enums.xml.
-   * These values are persisted to logs. Entries should not be
-   * renumbered and numeric values should never be reused.
-   * @return {number} the current speech rate as an int for metrics.
-   */
-  speechRateToSparceHistogramInt_: function() {
-    return this.speechRate_ * 100;
-  },
-
-  /**
-   * Converts the speech pitch into an enum based on
-   * tools/metrics/histograms/enums.xml.
-   * These values are persisted to logs. Entries should not be
-   * renumbered and numeric values should never be reused.
-   * @return {number} the current speech pitch as an int for metrics.
-   */
-  speechPitchToSparceHistogramInt_: function() {
-    return this.speechPitch_ * 100;
-  },
-
-  /**
-   * Records an event that Select-to-Speak has begun speaking.
-   * @param {number} method The CrosSelectToSpeakStartSpeechMethod enum
-   *    that reflects how this event was triggered by the user.
-   */
-  recordStartEvent_: function(method) {
-    chrome.metricsPrivate.recordUserAction(
-        'Accessibility.CrosSelectToSpeak.StartSpeech');
-    chrome.metricsPrivate.recordSparseValue(
-        'Accessibility.CrosSelectToSpeak.SpeechRate',
-        this.speechRateToSparceHistogramInt_());
-    chrome.metricsPrivate.recordSparseValue(
-        'Accessibility.CrosSelectToSpeak.SpeechPitch',
-        this.speechPitchToSparceHistogramInt_());
-    chrome.metricsPrivate.recordBoolean(
-        'Accessibility.CrosSelectToSpeak.WordHighlighting',
-        this.wordHighlight_);
-    chrome.metricsPrivate.recordEnumerationValue(
-        'Accessibility.CrosSelectToSpeak.StartSpeechMethod', method,
-        START_SPEECH_METHOD_COUNT);
-  },
-
-  /**
-   * Records an event that Select-to-Speak speech has been canceled.
-   */
-  recordCancelEvent_: function() {
-    chrome.metricsPrivate.recordUserAction(
-        'Accessibility.CrosSelectToSpeak.CancelSpeech');
-  },
-
-  /**
-   * Records a user-requested state change event from a given state.
-   * @param {number} changeType
-   */
-  recordSelectToSpeakStateChangeEvent_: function(changeType) {
-    chrome.metricsPrivate.recordEnumerationValue(
-        STATE_CHANGE_EVENT_METRIC_NAME, changeType, STATE_CHANGE_EVENT_COUNT);
-  },
-
-  /**
    * Loads preferences from chrome.storage, sets default values if
    * necessary, and registers a listener to update prefs when they
    * change.
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
index 8352aafe..ddb3f64d8 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/css/wallpaper_manager.css
@@ -423,10 +423,6 @@
   display: none;
 }
 
-.v2 .image-picker {
-  height: 100%;
-}
-
 .v2 #category-container {
   overflow-y: hidden;
 }
@@ -478,6 +474,7 @@
 .v2 .image-picker {
   -webkit-padding-end: unset;
   -webkit-padding-start: unset;
+  height: 100%;
   padding-bottom: unset;
   padding-top: unset;
 }
@@ -505,10 +502,6 @@
   box-sizing: border-box;
 }
 
-.v2 .image-picker [role=listitem].daily-refresh-item {
-  pointer-events: none;
-}
-
 .v2 .image-picker:not([disabled]) [role=listitem]:hover {
   outline: none;
   z-index: unset;
@@ -526,6 +519,7 @@
 
 .v2 .image-picker [role=listitem][selected]:not(.daily-refresh-item) img {
   border-radius: 4px;
+  box-shadow: 0 4px 8px rgba(32, 33, 36, 0.17);
   transform: scale(0.8);
 }
 
@@ -541,6 +535,15 @@
   top: 8px;
 }
 
+.v2 .image-picker::-webkit-scrollbar-thumb {
+  background: #888;
+  display: none;
+}
+
+.v2 .image-picker.show-scroll-bar::-webkit-scrollbar-thumb {
+  display: block;
+}
+
 .v2 #window-close-button {
   display: none;
 }
@@ -572,6 +575,7 @@
   -webkit-app-region: no-drag;
   background-color: #fff;
   border-radius: 0 0 24px 24px;
+  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.24), 0 0 24px rgba(0, 0, 0, 0.12);
   display: flex;
   height: 48px;
   position: absolute;
@@ -675,7 +679,7 @@
 
 .v2 .top-header-contents .more-options > div {
   background-color: #fff;
-  color: rgb(66, 133, 244);
+  color: rgb(26, 115, 232);
   display: none;
   margin-top: -8px;
   padding: 8px 24px;
@@ -697,8 +701,8 @@
 
 .v2 .top-header-contents .more-options .center-button.disabled,
 .v2 .top-header-contents .more-options .center-cropped-button.disabled {
-  background-color: rgb(232,240,254);
-  color: rgb(66, 133, 244);
+  background-color: rgb(232, 240, 254);
+  color: rgb(26, 115, 232);
   pointer-events: none;
   z-index: 1;
 }
@@ -711,31 +715,26 @@
   -webkit-margin-start: -24px;
 }
 
-.v2 .top-header-contents .center-button.disabled .icon,
+.v2 .top-header-contents .center-button .icon,
 .v2 #current-wallpaper-more-options #center .icon {
   background-image: url(../images/ui/center_layout.svg);
 }
 
-.v2 .top-header-contents .center-button .icon,
+.v2 .top-header-contents .center-button.disabled .icon,
 .v2 #current-wallpaper-more-options #center.disabled .icon {
   background-image: url(../images/ui/center_layout_disabled.svg);
 }
 
-.v2 .top-header-contents .center-cropped-button.disabled .icon,
+.v2 .top-header-contents .center-cropped-button .icon,
 .v2 #current-wallpaper-more-options #center-cropped .icon {
   background-image: url(../images/ui/center_cropped_layout.svg);
 }
 
-.v2 .top-header-contents .center-cropped-button .icon,
+.v2 .top-header-contents .center-cropped-button.disabled .icon,
 .v2 #current-wallpaper-more-options #center-cropped.disabled .icon {
   background-image: url(../images/ui/center_cropped_layout_disabled.svg);
 }
 
-.v2 #current-wallpaper-more-options .disabled {
-  color: rgb(128, 134, 139);
-  pointer-events: none;
-}
-
 .v2 .top-header-contents #confirm-preview-wallpaper {
   -webkit-margin-start: 96px;
 }
@@ -825,6 +824,10 @@
   pointer-events: none;
 }
 
+.v2 .image-picker-offline img.slide-show {
+  -webkit-filter: grayscale(1);
+}
+
 .v2 .daily-refresh-slider::before {
   background-color: #fff;
   border-radius: 50%;
@@ -837,16 +840,16 @@
   width: 16px;
 }
 
-.v2 .daily-refresh-slider.checked  {
-  background-color: rgb(66, 133, 244, 0.6);
+.v2 .daily-refresh-item.checked .daily-refresh-slider  {
+  background-color: rgb(26, 115, 232, 0.6);
 }
 
-.v2 .daily-refresh-slider.checked::before {
-  background-color: rgb(66, 133, 244);
+.v2 .daily-refresh-item.checked .daily-refresh-slider::before {
+  background-color: rgb(26, 115, 232);
   transform: translateX(16px);
 }
 
-.v2 .daily-refresh-slider .ripple-circle {
+.v2 .daily-refresh-item .daily-refresh-slider .ripple-circle {
   background: #000;
   border-radius: 50%;
   height: 36px;
@@ -858,22 +861,22 @@
   width: 36px;
 }
 
-.v2 .daily-refresh-slider.checked .ripple-circle {
+.v2 .daily-refresh-item.checked .daily-refresh-slider .ripple-circle {
   background-color: rgb(30, 144, 255);
   left: 4px;
 }
 
-.v2 .daily-refresh-slider.ripple-animation .ripple-circle {
+.v2 .daily-refresh-item.ripple-animation .daily-refresh-slider .ripple-circle {
   animation: ripple 240ms;
   animation-delay: 120ms;
 }
 
-.v2 .daily-refresh-slider:focus:not(.ripple-animation) .ripple-circle {
+.v2 .daily-refresh-item:not(.ripple-animation) .daily-refresh-slider:focus .ripple-circle {
   transform: scale(1);
 }
 
 .v2 .daily-refresh-label {
-  color: rgb(66, 133, 244);
+  color: rgb(26, 115, 232);
   font-family: 'Roboto';
   font-size: 13px;
   font-weight: 500;
@@ -941,7 +944,7 @@
 }
 
 .v2 #current-wallpaper-more-options {
-  color: rgb(66, 133, 244);
+  color: rgb(26, 115, 232);
   display: flex;
   flex-direction: column;
   font-size: 12px;
@@ -955,16 +958,25 @@
 
 .v2 #current-wallpaper-more-options > div {
   display: flex;
-  padding: 8px 4px;
+  padding: 8px 0;
+}
+
+.v2 #current-wallpaper-more-options #center,
+.v2 #current-wallpaper-more-options #center-cropped {
+  color: rgb(128, 134, 139);
+}
+
+.v2 #current-wallpaper-more-options #center.disabled,
+.v2 #current-wallpaper-more-options #center-cropped.disabled {
+  color: rgb(26, 115, 232);
+  pointer-events: none;
 }
 
 .v2 #current-wallpaper-more-options .text {
-  -webkit-margin-end: 16px;
   padding-top: 1px;
 }
 
 .v2 #current-wallpaper-more-options .icon {
-  -webkit-margin-start: 16px;
   -webkit-padding-end: 8px;
   background-repeat: no-repeat;
   height: 16px;
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout.svg b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout.svg
index 876456a..6e34b46 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout.svg
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout.svg
@@ -1,3 +1,3 @@
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="#1A73E8" fill-rule="evenodd" d="M2,11 L14,11 L14,5 L2,5 L2,11 Z M1,12 L15,12 L15,4 L1,4 L1,12 Z M10,3 L12,3 L12,1 L10,1 L10,3 Z M10,15 L12,15 L12,13 L10,13 L10,15 Z M13,15 C14.1,15 15,14.1 15,13 L13,13 L13,15 Z M7,15 L9,15 L9,13 L7,13 L7,15 Z M4,3 L6,3 L6,1 L4,1 L4,3 Z M3,15 L3,13 L1,13 C1,14.1 1.9,15 3,15 L3,15 Z M13,1 L13,3 L15,3 C15,1.9 14.1,1 13,1 L13,1 Z M7,3 L9,3 L9,1 L7,1 L7,3 Z M4,15 L6,15 L6,13 L4,13 L4,15 Z M1,3 L3,3 L3,1 C1.9,1 1,1.9 1,3 L1,3 Z"/>
+  <path fill="#80868B" fill-rule="evenodd" d="M2,11 L14,11 L14,5 L2,5 L2,11 Z M1,12 L15,12 L15,4 L1,4 L1,12 Z M10,3 L12,3 L12,1 L10,1 L10,3 Z M10,15 L12,15 L12,13 L10,13 L10,15 Z M13,15 C14.1,15 15,14.1 15,13 L13,13 L13,15 Z M7,15 L9,15 L9,13 L7,13 L7,15 Z M4,3 L6,3 L6,1 L4,1 L4,3 Z M3,15 L3,13 L1,13 C1,14.1 1.9,15 3,15 L3,15 Z M13,1 L13,3 L15,3 C15,1.9 14.1,1 13,1 L13,1 Z M7,3 L9,3 L9,1 L7,1 L7,3 Z M4,15 L6,15 L6,13 L4,13 L4,15 Z M1,3 L3,3 L3,1 C1.9,1 1,1.9 1,3 L1,3 Z"/>
 </svg>
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout_disabled.svg b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout_disabled.svg
index 6e34b46..876456a 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout_disabled.svg
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_cropped_layout_disabled.svg
@@ -1,3 +1,3 @@
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="#80868B" fill-rule="evenodd" d="M2,11 L14,11 L14,5 L2,5 L2,11 Z M1,12 L15,12 L15,4 L1,4 L1,12 Z M10,3 L12,3 L12,1 L10,1 L10,3 Z M10,15 L12,15 L12,13 L10,13 L10,15 Z M13,15 C14.1,15 15,14.1 15,13 L13,13 L13,15 Z M7,15 L9,15 L9,13 L7,13 L7,15 Z M4,3 L6,3 L6,1 L4,1 L4,3 Z M3,15 L3,13 L1,13 C1,14.1 1.9,15 3,15 L3,15 Z M13,1 L13,3 L15,3 C15,1.9 14.1,1 13,1 L13,1 Z M7,3 L9,3 L9,1 L7,1 L7,3 Z M4,15 L6,15 L6,13 L4,13 L4,15 Z M1,3 L3,3 L3,1 C1.9,1 1,1.9 1,3 L1,3 Z"/>
+  <path fill="#1A73E8" fill-rule="evenodd" d="M2,11 L14,11 L14,5 L2,5 L2,11 Z M1,12 L15,12 L15,4 L1,4 L1,12 Z M10,3 L12,3 L12,1 L10,1 L10,3 Z M10,15 L12,15 L12,13 L10,13 L10,15 Z M13,15 C14.1,15 15,14.1 15,13 L13,13 L13,15 Z M7,15 L9,15 L9,13 L7,13 L7,15 Z M4,3 L6,3 L6,1 L4,1 L4,3 Z M3,15 L3,13 L1,13 C1,14.1 1.9,15 3,15 L3,15 Z M13,1 L13,3 L15,3 C15,1.9 14.1,1 13,1 L13,1 Z M7,3 L9,3 L9,1 L7,1 L7,3 Z M4,15 L6,15 L6,13 L4,13 L4,15 Z M1,3 L3,3 L3,1 C1.9,1 1,1.9 1,3 L1,3 Z"/>
 </svg>
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout.svg b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout.svg
index aef4bb01..db0589c8 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout.svg
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout.svg
@@ -1,3 +1,3 @@
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="#1A73E8" fill-rule="evenodd" d="M5,9 L9,9 L9,5 L5,5 L5,9 Z M4,10 L10,10 L10,4 L4,4 L4,10 Z M9,2 L11,2 L11,0 L9,0 L9,2 Z M9,14 L11,14 L11,12 L9,12 L9,14 Z M12,11 L14,11 L14,9 L12,9 L12,11 Z M12,5 L14,5 L14,3 L12,3 L12,5 Z M12,14 C13.1,14 14,13.1 14,12 L12,12 L12,14 Z M12,8 L14,8 L14,6 L12,6 L12,8 Z M6,14 L8,14 L8,12 L6,12 L6,14 Z M3,2 L5,2 L5,0 L3,0 L3,2 Z M0,11 L2,11 L2,9 L0,9 L0,11 Z M2,14 L2,12 L0,12 C0,13.1 0.9,14 2,14 L2,14 Z M12,0 L12,2 L14,2 C14,0.9 13.1,0 12,0 L12,0 Z M6,2 L8,2 L8,0 L6,0 L6,2 Z M0,5 L2,5 L2,3 L0,3 L0,5 Z M3,14 L5,14 L5,12 L3,12 L3,14 Z M0,8 L2,8 L2,6 L0,6 L0,8 Z M2,2 L2,0 C0.9,0 0,0.9 0,2 L2,2 Z" transform="translate(1 1)"/>
+  <path fill="#80868B" fill-rule="evenodd" d="M5,9 L9,9 L9,5 L5,5 L5,9 Z M4,10 L10,10 L10,4 L4,4 L4,10 Z M9,2 L11,2 L11,0 L9,0 L9,2 Z M9,14 L11,14 L11,12 L9,12 L9,14 Z M12,11 L14,11 L14,9 L12,9 L12,11 Z M12,5 L14,5 L14,3 L12,3 L12,5 Z M12,14 C13.1,14 14,13.1 14,12 L12,12 L12,14 Z M12,8 L14,8 L14,6 L12,6 L12,8 Z M6,14 L8,14 L8,12 L6,12 L6,14 Z M3,2 L5,2 L5,0 L3,0 L3,2 Z M0,11 L2,11 L2,9 L0,9 L0,11 Z M2,14 L2,12 L0,12 C0,13.1 0.9,14 2,14 L2,14 Z M12,0 L12,2 L14,2 C14,0.9 13.1,0 12,0 L12,0 Z M6,2 L8,2 L8,0 L6,0 L6,2 Z M0,5 L2,5 L2,3 L0,3 L0,5 Z M3,14 L5,14 L5,12 L3,12 L3,14 Z M0,8 L2,8 L2,6 L0,6 L0,8 Z M2,2 L2,0 C0.9,0 0,0.9 0,2 L2,2 Z" transform="translate(1 1)"/>
 </svg>
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout_disabled.svg b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout_disabled.svg
index db0589c8..aef4bb01 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout_disabled.svg
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/images/ui/center_layout_disabled.svg
@@ -1,3 +1,3 @@
 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
-  <path fill="#80868B" fill-rule="evenodd" d="M5,9 L9,9 L9,5 L5,5 L5,9 Z M4,10 L10,10 L10,4 L4,4 L4,10 Z M9,2 L11,2 L11,0 L9,0 L9,2 Z M9,14 L11,14 L11,12 L9,12 L9,14 Z M12,11 L14,11 L14,9 L12,9 L12,11 Z M12,5 L14,5 L14,3 L12,3 L12,5 Z M12,14 C13.1,14 14,13.1 14,12 L12,12 L12,14 Z M12,8 L14,8 L14,6 L12,6 L12,8 Z M6,14 L8,14 L8,12 L6,12 L6,14 Z M3,2 L5,2 L5,0 L3,0 L3,2 Z M0,11 L2,11 L2,9 L0,9 L0,11 Z M2,14 L2,12 L0,12 C0,13.1 0.9,14 2,14 L2,14 Z M12,0 L12,2 L14,2 C14,0.9 13.1,0 12,0 L12,0 Z M6,2 L8,2 L8,0 L6,0 L6,2 Z M0,5 L2,5 L2,3 L0,3 L0,5 Z M3,14 L5,14 L5,12 L3,12 L3,14 Z M0,8 L2,8 L2,6 L0,6 L0,8 Z M2,2 L2,0 C0.9,0 0,0.9 0,2 L2,2 Z" transform="translate(1 1)"/>
+  <path fill="#1A73E8" fill-rule="evenodd" d="M5,9 L9,9 L9,5 L5,5 L5,9 Z M4,10 L10,10 L10,4 L4,4 L4,10 Z M9,2 L11,2 L11,0 L9,0 L9,2 Z M9,14 L11,14 L11,12 L9,12 L9,14 Z M12,11 L14,11 L14,9 L12,9 L12,11 Z M12,5 L14,5 L14,3 L12,3 L12,5 Z M12,14 C13.1,14 14,13.1 14,12 L12,12 L12,14 Z M12,8 L14,8 L14,6 L12,6 L12,8 Z M6,14 L8,14 L8,12 L6,12 L6,14 Z M3,2 L5,2 L5,0 L3,0 L3,2 Z M0,11 L2,11 L2,9 L0,9 L0,11 Z M2,14 L2,12 L0,12 C0,13.1 0.9,14 2,14 L2,14 Z M12,0 L12,2 L14,2 C14,0.9 13.1,0 12,0 L12,0 Z M6,2 L8,2 L8,0 L6,0 L6,2 Z M0,5 L2,5 L2,3 L0,3 L0,5 Z M3,14 L5,14 L5,12 L3,12 L3,14 Z M0,8 L2,8 L2,6 L0,6 L0,8 Z M2,2 L2,0 C0.9,0 0,0.9 0,2 L2,2 Z" transform="translate(1 1)"/>
 </svg>
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
index 85bef1e6..ae830e0 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
@@ -368,14 +368,19 @@
           alphaEnabled: true
         };
 
-    chrome.app.window.create('main.html', options, function(w) {
-      wallpaperPickerWindow = w;
+    chrome.app.window.create('main.html', options, function(window) {
+      wallpaperPickerWindow = window;
       chrome.wallpaperPrivate.minimizeInactiveWindows();
-      w.onClosed.addListener(function() {
+      window.onClosed.addListener(function() {
         wallpaperPickerWindow = null;
-        chrome.wallpaperPrivate.restoreMinimizedWindows();
         // In case the app exits unexpectedly during preview.
         chrome.wallpaperPrivate.cancelPreviewWallpaper(() => {});
+        // If the app exits during preview, do not restore the previously active
+        // windows. Continue to show the new wallpaper.
+        if (!window.contentWindow.document.body.classList.contains(
+                'preview-mode')) {
+          chrome.wallpaperPrivate.restoreMinimizedWindows();
+        }
       });
       if (useNewWallpaperPicker) {
         // By design, the new wallpaper picker should never be shown on top of
@@ -384,7 +389,7 @@
             'focus', function() {
               chrome.wallpaperPrivate.minimizeInactiveWindows();
             });
-        w.onMinimized.addListener(function() {
+        window.onMinimized.addListener(function() {
           chrome.wallpaperPrivate.restoreMinimizedWindows();
         });
       }
@@ -664,10 +669,15 @@
       fileName, layout, Constants.WallpaperSourceEnum.ThirdParty, appName);
 
   getWallpaperPickerInfo((useNewWallpaperPicker, highResolutionSuffix) => {
+    // Surprise me/daily refresh should be auto-disabled if wallpaper is changed
+    // by third-party apps.
     if (!useNewWallpaperPicker) {
       SurpriseWallpaper.getInstance().disable();
       return;
     }
+    WallpaperUtil.saveDailyRefreshInfo(
+        {enabled: false, collectionId: null, resumeToken: null});
+
     if (wallpaperPickerWindow) {
       var event = new CustomEvent(
           Constants.WallpaperChangedBy3rdParty,
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
index 8fcf2ed..0ea9704 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_images_grid.js
@@ -97,6 +97,9 @@
           if (e.keyCode == 13)
             this.parentNode.selectedItem = this.dataItem;
         });
+        this.addEventListener('mousedown', e => {
+          e.preventDefault();
+        });
       }
 
       imageEl.classList.add('thumbnail');
@@ -705,10 +708,9 @@
       if (!this.dailyRefreshItem.querySelector('.daily-refresh-banner')) {
         var dailyRefreshBanner = document.querySelector('.daily-refresh-banner')
                                      .cloneNode(true /*deep=*/);
-        wallpaperManager.decorateDailyRefreshSlider(
-            this.collectionId,
-            dailyRefreshBanner.querySelector('.daily-refresh-slider'));
         this.dailyRefreshItem.appendChild(dailyRefreshBanner);
+        wallpaperManager.decorateDailyRefreshItem(
+            this.collectionId, this.dailyRefreshItem);
       }
 
       slideShowImage.style.opacity =
@@ -728,17 +730,12 @@
       var images = this.dailyRefreshImages;
       if (images.length <= index)
         return;
-      images[index].style.opacity = 1;
-
-      if (images.length > 1) {
-        var previousIndex = (index - 1) % images.length;
-        if (previousIndex < 0)
-          previousIndex += images.length;
-        images[previousIndex].style.opacity = 0;
-        var nextIndex = (index + 1) % images.length;
-        this.dailyRefreshTimer_ =
-            window.setTimeout(this.showNextImage_.bind(this, nextIndex), 3000);
+      for (var i = 0; i < images.length; ++i) {
+        images[i].style.opacity = i === index ? 1 : 0;
       }
+      var nextIndex = (index + 1) % images.length;
+      this.dailyRefreshTimer_ =
+          window.setTimeout(this.showNextImage_.bind(this, nextIndex), 3000);
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
index 3ea3c59a..f77fcbd 100644
--- a/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
+++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/wallpaper_manager.js
@@ -517,6 +517,10 @@
  * do not depend on the download should be initialized here.
  */
 WallpaperManager.prototype.preDownloadDomInit_ = function() {
+  this.document_.defaultView.addEventListener(
+      'resize', this.onResize_.bind(this));
+  this.document_.defaultView.addEventListener(
+      'keydown', this.onKeyDown_.bind(this));
   if (this.useNewWallpaperPicker_) {
     $('minimize-button').addEventListener('click', function() {
       chrome.app.window.current().minimize();
@@ -530,24 +534,32 @@
       // Clear the check mark (if any). Do not try to locate the new wallpaper
       // in the picker to avoid changing the selected category abruptly.
       this.wallpaperGrid_.selectedItem = null;
+      this.disableDailyRefresh_();
     });
+    var imagePicker = this.document_.body.querySelector('.image-picker');
+    imagePicker.addEventListener('scroll', function() {
+      var scrollTimer;
+      return () => {
+        imagePicker.classList.add('show-scroll-bar');
+        window.clearTimeout(scrollTimer);
+        scrollTimer = window.setTimeout(() => {
+          imagePicker.classList.remove('show-scroll-bar');
+        }, 500);
+      };
+    }());
   } else {
     $('window-close-button').addEventListener('click', function() {
       window.close();
     });
+    $('learn-more').href = LearnMoreURL;
+    $('close-error').addEventListener('click', function() {
+      $('error-container').hidden = true;
+    });
+    $('close-wallpaper-selection').addEventListener('click', function() {
+      $('wallpaper-selection-container').hidden = true;
+      $('set-wallpaper-layout').disabled = true;
+    });
   }
-  this.document_.defaultView.addEventListener(
-      'resize', this.onResize_.bind(this));
-  this.document_.defaultView.addEventListener(
-      'keydown', this.onKeyDown_.bind(this));
-  $('learn-more').href = LearnMoreURL;
-  $('close-error').addEventListener('click', function() {
-    $('error-container').hidden = true;
-  });
-  $('close-wallpaper-selection').addEventListener('click', function() {
-    $('wallpaper-selection-container').hidden = true;
-    $('set-wallpaper-layout').disabled = true;
-  });
 };
 
 /**
@@ -885,19 +897,22 @@
               0.4;
           visibleItemList[0].style.marginTop = topMargin + 'px';
           visibleItemList[1].style.marginTop = topMargin / 2 + 'px';
-
-          // Make sure that all the texts are centered.
-          for (var item of visibleItemList) {
-            var totalPadding = $('current-wallpaper-more-options').offsetWidth -
-                (item.querySelector('.icon').offsetWidth +
-                 item.querySelector('.text').offsetWidth);
-            item.querySelector('.icon').style.WebkitMarginStart =
-                totalPadding / 2 + 'px';
-          }
+        }
+        // Add necessary padding and make sure all the texts are centered. Clear
+        // the existing padding first.
+        for (var item of visibleItemList) {
+          item.style.paddingLeft = item.style.paddingRight = '0px';
+        }
+        var totalWidth = $('current-wallpaper-more-options').offsetWidth;
+        for (var item of visibleItemList) {
+          var padding = 15 +
+              (totalWidth -
+               (item.querySelector('.icon').offsetWidth +
+                item.querySelector('.text').offsetWidth)) /
+                  2;
+          item.style.paddingLeft = item.style.paddingRight = padding + 'px';
         }
 
-        $('current-wallpaper-more-options')
-            .classList.toggle('online-wallpaper', isOnlineWallpaper);
         // Clear the existing contents (needed if the wallpaper changes while
         // the picker is open).
         $('current-wallpaper-description').innerHTML = '';
@@ -1046,6 +1061,10 @@
   $('wallpaper-set-by-message').textContent = '';
   $('wallpaper-grid').classList.remove('small');
 
+  // Disables daily refresh if user selects a non-daily wallpaper.
+  if (activeItem && activeItem.source !== Constants.WallpaperSourceEnum.Daily)
+    this.disableDailyRefresh_();
+
   if (activeItem) {
     WallpaperUtil.saveWallpaperInfo(
         currentWallpaperURL, activeItem.layout, activeItem.source, '');
@@ -2183,7 +2202,7 @@
 
 /**
  * Fetches the info related to the daily refresh feature and updates the UI for
- * the sliders. Only used by the new wallpaper picker.
+ * the items. Only used by the new wallpaper picker.
  * @private
  */
 WallpaperManager.prototype.initializeDailyRefreshStates_ = function() {
@@ -2204,7 +2223,7 @@
       };
     }
 
-    this.updateDailyRefreshSliderStates_(this.dailyRefreshInfo_);
+    this.updateDailyRefreshItemStates_(this.dailyRefreshInfo_);
     this.decorateCurrentWallpaperInfoBar_();
   };
 
@@ -2213,58 +2232,50 @@
 };
 
 /**
- * Updates the UI of all the daily refresh sliders based on the info.
+ * Updates the UI of all the daily refresh items based on the info.
  * @param {Object} dailyRefreshInfo The daily refresh info.
  * @private
  */
-WallpaperManager.prototype.updateDailyRefreshSliderStates_ = function(
+WallpaperManager.prototype.updateDailyRefreshItemStates_ = function(
     dailyRefreshInfo) {
-  if (!this.dailyRefreshSliderMap_ || !dailyRefreshInfo)
+  if (!this.dailyRefreshItemMap_ || !dailyRefreshInfo)
     return;
 
-  Object.entries(this.dailyRefreshSliderMap_)
-      .forEach(([collectionId, dailyRefreshSlider]) => {
+  Object.entries(this.dailyRefreshItemMap_)
+      .forEach(([collectionId, dailyRefreshItem]) => {
         var enabled = dailyRefreshInfo.enabled &&
             dailyRefreshInfo.collectionId === collectionId;
-        dailyRefreshSlider.classList.toggle('checked', enabled);
-        dailyRefreshSlider.setAttribute('aria-checked', enabled);
+        dailyRefreshItem.classList.toggle('checked', enabled);
+        dailyRefreshItem.querySelector('.daily-refresh-slider')
+            .setAttribute('aria-checked', enabled);
       });
 };
 
 /**
- * Decorates the UI and registers event listener for the slider.
- * @param {string} collectionId The collection id that this slider is associated
+ * Decorates the UI and registers event listener for the item.
+ * @param {string} collectionId The collection id that this item is associated
  *     with.
- * @param {Object} dailyRefreshSlider The daily refresh slider.
+ * @param {Object} dailyRefreshItem The daily refresh item.
  */
-WallpaperManager.prototype.decorateDailyRefreshSlider = function(
-    collectionId, dailyRefreshSlider) {
-  if (!this.dailyRefreshSliderMap_)
-    this.dailyRefreshSliderMap_ = {};
+WallpaperManager.prototype.decorateDailyRefreshItem = function(
+    collectionId, dailyRefreshItem) {
+  if (!this.dailyRefreshItemMap_)
+    this.dailyRefreshItemMap_ = {};
 
-  this.dailyRefreshSliderMap_[collectionId] = dailyRefreshSlider;
-  this.updateDailyRefreshSliderStates_(this.dailyRefreshInfo_);
-  dailyRefreshSlider.addEventListener('click', () => {
-    var isSliderEnabled = dailyRefreshSlider.classList.contains('checked');
+  this.dailyRefreshItemMap_[collectionId] = dailyRefreshItem;
+  this.updateDailyRefreshItemStates_(this.dailyRefreshInfo_);
+  dailyRefreshItem.addEventListener('click', () => {
+    var isItemEnabled = dailyRefreshItem.classList.contains('checked');
     var isCollectionEnabled =
         collectionId === this.dailyRefreshInfo_.collectionId;
-    if (isSliderEnabled !== isCollectionEnabled) {
+    if (isItemEnabled !== isCollectionEnabled) {
       console.error(
           'There is a mismatch between the enabled daily refresh collection ' +
-          'and the slider state. This should never happen.');
+          'and the item state. This should never happen.');
       return;
     }
-    if (isSliderEnabled) {
-      // Disable daily refresh. The current value of the collection id and
-      // resume token can be discarded.
-      this.dailyRefreshInfo_ = {
-        enabled: false,
-        collectionId: null,
-        resumeToken: null
-      };
-      WallpaperUtil.saveDailyRefreshInfo(this.dailyRefreshInfo_);
-      this.updateDailyRefreshSliderStates_(this.dailyRefreshInfo_);
-      this.decorateCurrentWallpaperInfoBar_();
+    if (isItemEnabled) {
+      this.disableDailyRefresh_();
     } else {
       // Enable daily refresh but do not overwrite |dailyRefreshInfo_| yet
       // (since it's still possible to revert). The resume token is left empty
@@ -2277,21 +2288,21 @@
       this.setDailyRefreshWallpaper_();
     }
     var toggleRippleAnimation = enabled => {
-      dailyRefreshSlider.classList.toggle('ripple-animation', enabled);
+      dailyRefreshItem.classList.toggle('ripple-animation', enabled);
     };
     toggleRippleAnimation(true);
     window.setTimeout(() => {
       toggleRippleAnimation(false);
     }, 360);
   });
-  dailyRefreshSlider.addEventListener('keypress', e => {
+  dailyRefreshItem.addEventListener('keypress', e => {
     if (e.keyCode == 13)
-      dailyRefreshSlider.click();
+      dailyRefreshItem.click();
   });
-  dailyRefreshSlider.addEventListener('mousedown', e => {
+  dailyRefreshItem.addEventListener('mousedown', e => {
     e.preventDefault();
   });
-  dailyRefreshSlider.setAttribute('aria-label', str('surpriseMeLabel'));
+  dailyRefreshItem.setAttribute('aria-label', str('surpriseMeLabel'));
 };
 
 /**
@@ -2303,7 +2314,7 @@
   if (!this.pendingDailyRefreshInfo_)
     return;
   // There should be immediate UI update even though the info hasn't been saved.
-  this.updateDailyRefreshSliderStates_(this.pendingDailyRefreshInfo_);
+  this.updateDailyRefreshItemStates_(this.pendingDailyRefreshInfo_);
   this.updateSpinnerVisibility_(true);
 
   var retryCount = 0;
@@ -2315,7 +2326,7 @@
           var failureCallback = () => {
             this.pendingDailyRefreshInfo_ = null;
             // Restore the original states.
-            this.updateDailyRefreshSliderStates_(this.dailyRefreshInfo_);
+            this.updateDailyRefreshItemStates_(this.dailyRefreshInfo_);
             this.updateSpinnerVisibility_(false);
           };
           if (chrome.runtime.lastError) {
@@ -2406,6 +2417,7 @@
  * @param {Object} button The button object.
  * @param {function} eventListener The function to be called when the button is
  *     clicked or the Enter key is pressed.
+ * @private
  */
 WallpaperManager.prototype.addEventToButton_ = function(button, eventListener) {
   // Replace the button with a clone to clear all previous event listeners.
@@ -2427,4 +2439,23 @@
   });
 };
 
+/**
+ * Helper function to disable daily refresh on the new wallpaper picker.
+ * Discards the current values of collection id and resume token. No-op if it's
+ * already disabled.
+ * @private
+ */
+WallpaperManager.prototype.disableDailyRefresh_ = function() {
+  if (!this.dailyRefreshInfo_ || !this.dailyRefreshInfo_.enabled)
+    return;
+  this.dailyRefreshInfo_ = {
+    enabled: false,
+    collectionId: null,
+    resumeToken: null
+  };
+  WallpaperUtil.saveDailyRefreshInfo(this.dailyRefreshInfo_);
+  this.updateDailyRefreshItemStates_(this.dailyRefreshInfo_);
+  this.decorateCurrentWallpaperInfoBar_();
+};
+
 })();
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.css b/chrome/browser/resources/local_ntp/custom_backgrounds.css
index 845af46..674f7a8 100644
--- a/chrome/browser/resources/local_ntp/custom_backgrounds.css
+++ b/chrome/browser/resources/local_ntp/custom_backgrounds.css
@@ -436,3 +436,58 @@
   left: auto;
   right: 67px;
 }
+
+#custom-bg-attr {
+  border-radius: 8px;
+  bottom: 16px;
+  color: white;
+  font-family: 'Roboto', arial, sans-serif;
+  left: 16px;
+  padding: 8px 8px 8px 8px;
+  position: fixed;
+}
+
+html[dir=rtl] #custom-bg-attr {
+  left: auto;
+  position: fixed;
+  right: 16px;
+}
+
+.attr1 {
+  font-size: 13px;
+  height: 20px;
+  line-height: 20px;
+  vertical-align: middle;
+}
+
+.attr2 {
+  font-size: 11px;
+  height: 20px;
+  line-height: 20px;
+  vertical-align: middle;
+}
+
+#custom-bg-attr.attr-link:hover {
+  background: rgba(32, 33, 36, .1);
+}
+
+.attr1.attr-link,
+.attr2.attr-link {
+  display: inline-block;
+  text-decoration: underline;
+}
+
+#link-icon {
+  background: url(icons/link.svg);
+  background-size: 10px 10px;
+  display: inline-block;
+  height: 10px;
+  margin-right: 8px;
+  vertical-align: middle;
+  width: 10px;
+}
+
+html[dir=rtl] #link-icon {
+  margin-right: auto;
+  margin-left: 8px;
+}
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.js b/chrome/browser/resources/local_ntp/custom_backgrounds.js
index f06e281..52082bcf 100644
--- a/chrome/browser/resources/local_ntp/custom_backgrounds.js
+++ b/chrome/browser/resources/local_ntp/custom_backgrounds.js
@@ -25,6 +25,7 @@
  * @const
  */
 customBackgrounds.IDS = {
+  ATTRIBUTIONS: 'custom-bg-attr',
   BACK: 'bg-sel-back',
   CANCEL: 'bg-sel-footer-cancel',
   CONNECT_GOOGLE_PHOTOS: 'edit-bg-google-photos',
@@ -38,6 +39,7 @@
   MSG_BOX_MSG: 'message-box-message',
   MSG_BOX_LINK: 'message-box-link',
   MSG_BOX_CONTAINER: 'message-box-container',
+  LINK_ICON: 'link-icon',
   MENU: 'bg-sel-menu',
   OPTIONS_TITLE: 'edit-bg-title',
   RESTORE_DEFAULT: 'edit-bg-restore-default',
@@ -56,6 +58,9 @@
  * @const
  */
 customBackgrounds.CLASSES = {
+  ATTR_1: 'attr1',
+  ATTR_2: 'attr2',
+  ATTR_LINK: 'attr-link',
   COLLECTION_DIALOG: 'is-col-sel',
   COLLECTION_SELECTED: 'bg-selected',  // Highlight selected tile
   COLLECTION_TILE: 'bg-sel-tile',  // Preview tile for background customization
@@ -114,6 +119,51 @@
 }
 
 /**
+ * Display custom background image attributions on the page.
+ * @param {string} attributionLine1 First line of attribution.
+ * @param {string} attributionLine2 Second line of attribution.
+ * @param {string} attributionActionUrl Url to learn more about the image.
+ */
+customBackgrounds.setAttribution = function(
+    attributionLine1, attributionLine2, attributionActionUrl) {
+  var attributionBox = $(customBackgrounds.IDS.ATTRIBUTIONS);
+  var attr1 = document.createElement('div');
+  var attr2 = document.createElement('div');
+  if (attributionLine1 != '') {
+    // Shouldn't be changed from textContent for security assurances.
+    attr1.textContent = attributionLine1;
+    attr1.classList.add(customBackgrounds.CLASSES.ATTR_1);
+    $(customBackgrounds.IDS.ATTRIBUTIONS).appendChild(attr1);
+  }
+  if (attributionLine2 != '') {
+    // Shouldn't be changed from textContent for security assurances.
+    attr2.textContent = attributionLine2;
+    attr2.classList.add(customBackgrounds.CLASSES.ATTR_2);
+    attributionBox.appendChild(attr2);
+  }
+  if (attributionActionUrl != '') {
+    var attr = (attributionLine2 != '' ? attr2 : attr1);
+    attr.classList.add(customBackgrounds.CLASSES.ATTR_LINK);
+
+    var linkIcon = document.createElement('div');
+    linkIcon.id = customBackgrounds.IDS.LINK_ICON;
+    attr.insertBefore(linkIcon, attr.firstChild);
+
+    attributionBox.classList.add(customBackgrounds.CLASSES.ATTR_LINK);
+    attributionBox.onclick = function() {
+      window.open(attributionActionUrl, '_blank');
+    };
+  }
+};
+
+customBackgrounds.clearAttribution = function() {
+  var attributions = $(customBackgrounds.IDS.ATTRIBUTIONS);
+  while (attributions.firstChild) {
+    attributions.removeChild(attributions.firstChild);
+  }
+};
+
+/**
  * Remove all collection tiles from the container when the dialog
  * is closed.
  */
@@ -140,9 +190,11 @@
 /* Close and reset the dialog, and set the background.
  * @param {string} url The url of the selected background.
  */
-customBackgrounds.setBackground = function(url) {
+customBackgrounds.setBackground = function(
+    url, attributionLine1, attributionLine2, attributionActionUrl) {
   customBackgrounds.closeCollectionDialog($(customBackgrounds.IDS.MENU));
-  window.chrome.embeddedSearch.newTabPage.setBackgroundURL(url);
+  window.chrome.embeddedSearch.newTabPage.setBackgroundURLWithAttributions(
+      url, attributionLine1, attributionLine2, attributionActionUrl);
 };
 
 /**
@@ -376,10 +428,22 @@
             'url(' + imageData[i].thumbnailImageUrl + ')';
       }
       tile.dataset.url = imageData[i].imageUrl;
+      tile.dataset.attributionLine1 =
+          (imageData[i].attributions[0] != undefined ?
+               imageData[i].attributions[0] :
+               '');
+      tile.dataset.attributionLine2 =
+          (imageData[i].attributions[1] != undefined ?
+               imageData[i].attributions[1] :
+               '');
+      tile.dataset.attributionActionUrl = imageData[i].attributionActionUrl;
     } else {
       tile.style.backgroundImage =
           'url(' + imageData[i].thumbnailPhotoUrl + ')';
       tile.dataset.url = imageData[i].photoUrl;
+      tile.dataset.attributionLine1 = '';
+      tile.dataset.attributionLine2 = '';
+      tile.dataset.attributionActionUrl = '';
     }
 
     tile.id = 'img_tile_' + i;
@@ -405,7 +469,9 @@
       if (clickCount == 1) {
         tileInteraction(event);
       } else if (clickCount == 2) {
-        customBackgrounds.setBackground(this.dataset.url);
+        customBackgrounds.setBackground(
+            this.dataset.url, this.dataset.attributionLine1,
+            this.dataset.attributionLine2, this.dataset.attributionActionUrl);
       }
     };
     tile.onkeyup = function(event) {
@@ -647,7 +713,11 @@
       return;
     }
 
-    customBackgrounds.setBackground(customBackgrounds.selectedTile.dataset.url);
+    customBackgrounds.setBackground(
+        customBackgrounds.selectedTile.dataset.url,
+        customBackgrounds.selectedTile.dataset.attributionLine1,
+        customBackgrounds.selectedTile.dataset.attributionLine2,
+        customBackgrounds.selectedTile.dataset.attributionActionUrl);
   };
   $(customBackgrounds.IDS.DONE).onclick = doneInteraction;
   $(customBackgrounds.IDS.DONE).onkeyup = function(event) {
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.css b/chrome/browser/resources/local_ntp/custom_links_edit.css
new file mode 100644
index 0000000..ce2a8dc2
--- /dev/null
+++ b/chrome/browser/resources/local_ntp/custom_links_edit.css
@@ -0,0 +1,87 @@
+/* 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. */
+
+#edit-link-dialog::backdrop {
+  background-color: rgba(255, 255, 255, .75);
+}
+
+#edit-link-dialog {
+  background-color: #fff;
+  border: none;
+  border-radius: 8px;
+  bottom: 0;
+  box-shadow:
+      0 1px 3px 0 rgba(60, 64, 67, 0.3), 0 4px 8px 3px rgba(60, 64, 67, 0.15);
+  font-family: 'Roboto', arial, sans-serif;
+  margin: auto;
+  padding: 16px;
+  top: 0;
+  width: 320px;
+  z-index: 10000;
+}
+
+#edit-link-dialog > div {
+  width: 100%;
+}
+
+.dialog-title {
+  font-size: 15px;
+  line-height: 24px;
+  margin-bottom: 16px;
+}
+
+.field-container {
+  margin-bottom: 16px;
+}
+
+.field-title {
+  color: rgb(154, 160, 166);
+  font-size: 10px;
+  font-weight: 500;
+  margin-bottom: 4px;
+}
+
+input {
+  -webkit-padding-end: 8px;
+  -webkit-padding-start: 8px;
+  background-color: rgb(232, 234, 237);
+  border: none;
+  border-radius: 4px;
+  font-size: 13px;
+  height: 32px;
+  line-height: 24px;
+  width: calc(100% - 16px);
+}
+
+.buttons-container {
+  display: flex;
+  justify-content: space-between;
+  margin-top: 24px;
+}
+
+.buttons-container .right {
+}
+
+button {
+  border: none;
+  border-radius: 4px;
+  font-size: 12px;
+  height: 32px;
+  padding: 0 16px;
+}
+
+button.primary {
+  background-color: rgb(26, 115, 232);
+  color: white;
+}
+
+button.secondary {
+  background-color: white;
+  border: 1px solid rgb(218,220,224);
+  color: rgb(26, 115, 232);
+}
+
+#cancel {
+  margin-right: 8px;
+}
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.html b/chrome/browser/resources/local_ntp/custom_links_edit.html
new file mode 100644
index 0000000..d194d52
--- /dev/null
+++ b/chrome/browser/resources/local_ntp/custom_links_edit.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<!-- 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. -->
+<head>
+  <base target="_top">
+  <meta charset="utf-8">
+  <link rel="stylesheet" type="text/css" href="edit.css">
+  <script src="edit.js"></script>
+</head>
+<body>
+  <dialog id="edit-link-dialog">
+    <div class="dialog-title">Edit shortcut</div>
+    <div class="field-container">
+      <div class="field-title">Name</div>
+      <input class="field-input" autocomplete="no" tabindex="0"></input>
+    </div>
+    <div class="field-container">
+      <div class="field-title">URL</div>
+      <input class="field-input" autocomplete="url" tabindex="0"></input>
+    </div>
+    <div class="buttons-container">
+      <span>
+        <button id="delete" class="secondary">Remove</button>
+      </span>
+      <span class="right">
+        <button id="cancel" class="secondary">Cancel</button>
+        <button id="done" class="primary">Done</button>
+      </span>
+    </div>
+  </dialog>
+</body>
+</html>
diff --git a/chrome/browser/resources/local_ntp/custom_links_edit.js b/chrome/browser/resources/local_ntp/custom_links_edit.js
new file mode 100644
index 0000000..3fa26f2
--- /dev/null
+++ b/chrome/browser/resources/local_ntp/custom_links_edit.js
@@ -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. */
+
+
+/**
+ * Enum for ids.
+ * @enum {string}
+ * @const
+ */
+const IDS = {
+  EDIT_DIALOG: 'edit-link-dialog',  // Edit dialog.
+  CANCEL: 'cancel',                 // Cancel button.
+  DELETE: 'delete',                 // Delete button.
+  DONE: 'done',                     // Done button.
+};
+
+
+/**
+ * The origin of this request, i.e. 'https://www.google.TLD' for the remote NTP,
+ * or 'chrome-search://local-ntp' for the local NTP.
+ * @const {string}
+ */
+let DOMAIN_ORIGIN = '{{ORIGIN}}';
+
+
+/**
+ * Alias for document.getElementById.
+ * @param {string} id The ID of the element to find.
+ * @return {HTMLElement} The found element or null if not found.
+ */
+function $(id) {
+  // eslint-disable-next-line no-restricted-properties
+  return document.getElementById(id);
+}
+
+
+/**
+ * Send a message to close the edit dialog. Called when the edit flow has been
+ * completed.
+ * @param {!Event} event The click event.
+ */
+function closeDialog(event) {
+  window.parent.postMessage({cmd: 'closeDialog'}, DOMAIN_ORIGIN);
+}
+
+
+/**
+ * Does some initialization and shows the dialog window.
+ */
+function init() {
+  $(IDS.EDIT_DIALOG).showModal();
+  $(IDS.DELETE).addEventListener('click', closeDialog);
+  $(IDS.CANCEL).addEventListener('click', closeDialog);
+  $(IDS.DONE).addEventListener('click', closeDialog);
+}
+
+
+window.addEventListener('DOMContentLoaded', init);
diff --git a/chrome/browser/resources/local_ntp/icons/add_link.svg b/chrome/browser/resources/local_ntp/icons/add_link.svg
new file mode 100644
index 0000000..a7e84a5
--- /dev/null
+++ b/chrome/browser/resources/local_ntp/icons/add_link.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <g fill="none" fill-rule="evenodd">
+    <rect width="2" height="12" x="7" y="2" fill="#000"/>
+    <rect width="2" height="12" x="7" y="2" fill="#000" transform="rotate(-90 8 8)"/>
+  </g>
+</svg>
diff --git a/chrome/browser/resources/local_ntp/icons/link.svg b/chrome/browser/resources/local_ntp/icons/link.svg
new file mode 100644
index 0000000..3300cd6
--- /dev/null
+++ b/chrome/browser/resources/local_ntp/icons/link.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <g fill="none" fill-rule="evenodd">
+    <polygon points="0 0 16 0 16 16 0 16"/>
+    <path fill="#fff" fill-rule="nonzero" d="M1.52,8 C1.52,6.632 2.632,5.52 4,5.52 L7.2,5.52 L7.2,4 L4,4 C1.792,4 0,5.792 0,8 C0,10.208 1.792,12 4,12 L7.2,12 L7.2,10.48 L4,10.48 C2.632,10.48 1.52,9.368 1.52,8 Z M4.8,8.8 L11.2,8.8 L11.2,7.2 L4.8,7.2 L4.8,8.8 Z M12,4 L8.8,4 L8.8,5.52 L12,5.52 C13.368,5.52 14.48,6.632 14.48,8 C14.48,9.368 13.368,10.48 12,10.48 L8.8,10.48 L8.8,12 L12,12 C14.208,12 16,10.208 16,8 C16,5.792 14.208,4 12,4 Z"/>
+  </g>
+</svg>
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 54c59770..1baa033 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -75,6 +75,10 @@
   display: block;
 }
 
+body.hidden {
+  overflow: hidden;
+}
+
 /* Button defaults vary by platform. Reset CSS so that the NTP can use buttons
  * as a kind of clickable div. */
 button {
@@ -110,6 +114,7 @@
 }
 
 body.hide-fakebox #fakebox {
+  opacity: 0;
   visibility: hidden;
 }
 
@@ -303,7 +308,10 @@
   box-shadow: none;
   margin: 0 auto;
   max-width: 560px;
+  opacity: 1;
   transition: background-color 300ms ease-in-out;
+  /* Transition should be similar to .mv-tile/.md-tile opacity transition. */
+  transition: opacity 200ms;
 }
 
 .md #fakebox:hover {
@@ -663,6 +671,20 @@
   width: 100%;
 }
 
+#custom-links-edit {
+  border: none;
+  display: none;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  width: 100%;
+  z-index: 10000;
+}
+
+#custom-links-edit.show {
+  display: block;
+}
+
 #one-google {
   position: absolute;
   right: 0;
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index 58e50d46..1720c78 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -85,6 +85,7 @@
         <div id="message-box-link" class="ripple"></div>
       </div>
     </div>
+    <div id="custom-bg-attr"></div>
   </div>
 
   <dialog div id="edit-bg-dialog">
@@ -157,5 +158,8 @@
   </dialog>
 
   <div id="one-google-end-of-body"></div>
+
+  <iframe id="custom-links-edit" name="custom-links-edit"
+          src="chrome-search://most-visited/edit.html"></iframe>
 </body>
 </html>
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 52307979..61f1fad 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -75,6 +75,9 @@
   DELAYED_HIDE_NOTIFICATION: 'mv-notice-delayed-hide',
   FADE: 'fade',  // Enables opacity transition on logo and doodle.
   FAKEBOX_FOCUS: 'fakebox-focused',  // Applies focus styles to the fakebox
+  SHOW_EDIT_DIALOG: 'show',          // Displays the edit custom link dialog.
+  HIDE_BODY_OVERFLOW: 'hidden',      // Prevents scrolling while the edit custom
+                                     // link dialog is open.
   // Applies float animations to the Most Visited notification
   FLOAT_UP: 'float-up',
   // Applies ripple animation to the element on click
@@ -106,6 +109,7 @@
 var IDS = {
   ATTRIBUTION: 'attribution',
   ATTRIBUTION_TEXT: 'attribution-text',
+  CUSTOM_LINKS_EDIT_IFRAME: 'custom-links-edit',
   FAKEBOX: 'fakebox',
   FAKEBOX_INPUT: 'fakebox-input',
   FAKEBOX_TEXT: 'fakebox-text',
@@ -306,9 +310,13 @@
 
     if (imageWithOverlay != document.body.style.backgroundImage) {
       customBackgrounds.closeCustomizationDialog();
+      customBackgrounds.clearAttribution();
     }
 
     document.body.style.setProperty('background-image', imageWithOverlay);
+
+    customBackgrounds.setAttribution(
+        info.attribution1, info.attribution2, info.attributionActionUrl);
   }
   $(customBackgrounds.IDS.RESTORE_DEFAULT).hidden =
       !info.customBackgroundConfigured;
@@ -630,6 +638,17 @@
 
 
 /**
+ * @param {boolean} show True if do show the edit custom link dialog and disable
+ *  scrolling.
+ */
+function setEditCustomLinkDialogVisibility(show) {
+  $(IDS.CUSTOM_LINKS_EDIT_IFRAME)
+      .classList.toggle(CLASSES.SHOW_EDIT_DIALOG, show);
+  document.body.classList.toggle(CLASSES.HIDE_BODY_OVERFLOW, show);
+}
+
+
+/**
  * @param {!Element} element The element to register the handler for.
  * @param {number} keycode The keycode of the key to register.
  * @param {!Function} handler The key handler to register.
@@ -643,7 +662,7 @@
 
 
 /**
- * Event handler for messages from the most visited iframe.
+ * Event handler for messages from the most visited and edit custom link iframe.
  * @param {Event} event Event received.
  */
 function handlePostMessage(event) {
@@ -677,6 +696,10 @@
     document.body.style.setProperty('--logo-iframe-height', height);
     document.body.style.setProperty('--logo-iframe-width', width);
     document.body.style.setProperty('--logo-iframe-resize-duration', duration);
+  } else if (cmd === 'startEditLink') {
+    setEditCustomLinkDialogVisibility(true);
+  } else if (cmd === 'closeDialog') {
+    setEditCustomLinkDialogVisibility(false);
   }
 }
 
@@ -953,6 +976,10 @@
     args.push('enableMD=1');
   }
 
+  if (configData.isCustomLinksEnabled) {
+    args.push('enableCustomLinks=1');
+  }
+
   // Create the most visited iframe.
   var iframe = document.createElement('iframe');
   iframe.id = IDS.TILES_IFRAME;
@@ -966,6 +993,8 @@
     sendThemeInfoToMostVisitedIframe();
   };
 
+  // TODO(851293): Add translated title attribute to edit custom link iframe.
+
   window.addEventListener('message', handlePostMessage);
 
   document.body.classList.add(CLASSES.INITED);
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 46d8668..126a4ae 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -469,7 +469,8 @@
   width: var(--md-icon-size);
 }
 
-.md-fallback-background {
+.md-fallback-background,
+.md-add-background {
   align-items: center;
   background-color: rgb(136, 136, 136);
   border-radius: 50%;
@@ -489,6 +490,16 @@
   width: var(--md-fallback-letter-size);
 }
 
+.md-add-background {
+  background-color: rgb(241, 243, 244);
+}
+
+.md-add-icon {
+  background: url(chrome-search://most-visited/add_link.svg) no-repeat center;
+  height: var(--md-favicon-size);
+  width: var(--md-favicon-size);
+}
+
 .md-title {
   color: rgba(33, 32, 36, 0.86);
   font-family: 'Roboto', arial, sans-serif;
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index bcdcfc6f..231f2ba 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -23,6 +23,8 @@
   MD_LINK: 'md-link',
   MD_ICON: 'md-icon',
   MD_ICON_BACKGROUND: 'md-icon-background',
+  MD_ADD_ICON: 'md-add-icon',
+  MD_ADD_BACKGROUND: 'md-add-background',
   MD_MENU: 'md-menu',
   MD_TILE: 'md-tile',
   MD_TILE_INNER: 'md-tile-inner',
@@ -67,11 +69,18 @@
 
 
 /**
- * Total number of tiles to show at any time. If the host page doesn't send
- * enough tiles, we fill them blank.
+ * Maximum number of MostVisited tiles to show at any time. If the host page
+ * doesn't send enough tiles, we fill them blank.
  * @const {number}
  */
-var NUMBER_OF_TILES = 8;
+var MAX_NUM_TILES = 8;
+
+
+/**
+ * Maximum number of custom link tiles to show at any time.
+ * @const {number}
+ */
+var MAX_NUM_CUSTOM_LINKS = 10;
 
 
 /**
@@ -120,6 +129,13 @@
 
 
 /**
+ * True if custom links is enabled.
+ * @type {boolean}
+ */
+let isCustomLinksEnabled = false;
+
+
+/**
  * Log an event on the NTP.
  * @param {number} eventType Event from LOG_TYPE.
  */
@@ -129,7 +145,7 @@
 
 /**
  * Log impression of an NTP tile.
- * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES.
+ * @param {number} tileIndex Position of the tile, >= 0 and < MAX_NUM_TILES.
  * @param {number} tileTitleSource The source of the tile's title as received
  *                 from getMostVisitedItemData.
  * @param {number} tileSource The tile's source as received from
@@ -146,7 +162,7 @@
 
 /**
  * Log click on an NTP tile.
- * @param {number} tileIndex Position of the tile, >= 0 and < NUMBER_OF_TILES.
+ * @param {number} tileIndex Position of the tile, >= 0 and < MAX_NUM_TILES.
  * @param {number} tileTitleSource The source of the tile's title as received
  *                 from getMostVisitedItemData.
  * @param {number} tileSource The tile's source as received from
@@ -258,9 +274,24 @@
   // Store the tiles on the current closure.
   var cur = tiles;
 
-  // Create empty tiles until we have NUMBER_OF_TILES.
-  while (cur.childNodes.length < NUMBER_OF_TILES) {
-    addTile({});
+  // Add an "add new custom link" button if we haven't reached the maximum
+  // number of links.
+  if (isCustomLinksEnabled && cur.childNodes.length < MAX_NUM_CUSTOM_LINKS) {
+    let data = {
+      'tid': -1,
+      'title': 'Add shortcut',  // TODO(851293): Use translated strings.
+      'url': '',
+      'isAddButton': true,
+    };
+    tiles.appendChild(renderMaterialDesignTile(data));
+  }
+
+  // Create empty tiles until we have MAX_NUM_TILES. This is not required for
+  // the Material Design style tiles.
+  if (!isMDEnabled) {
+    while (cur.childNodes.length < MAX_NUM_TILES) {
+      addTile({});
+    }
   }
 
   var parent = document.querySelector('#most-visited');
@@ -324,7 +355,7 @@
 /**
  * Handler for the 'show' message from the host page, called when it wants to
  * add a suggestion tile.
- * It's also used to fill up our tiles to NUMBER_OF_TILES if necessary.
+ * It's also used to fill up our tiles to MAX_NUM_TILES if necessary.
  * @param {object} args Data for the tile to be rendered.
  */
 var addTile = function(args) {
@@ -367,6 +398,15 @@
 
 
 /**
+ * Starts add custom link flow. Tells host page to show the edit custom link
+ * dialog.
+ */
+function addCustomLink() {
+  window.parent.postMessage({cmd: 'startEditLink'}, DOMAIN_ORIGIN);
+}
+
+
+/**
  * Returns whether the given URL has a known, safe scheme.
  * @param {string} url URL to check.
  */
@@ -378,8 +418,10 @@
 
 /**
  * Renders a MostVisited tile to the DOM.
- * @param {object} data Object containing rid, url, title, favicon, thumbnail.
- *     data is null if you want to construct an empty tile.
+ * @param {object} data Object containing rid, url, title, favicon, thumbnail,
+ *     and optionally isAddButton. isAddButton is true if you want to construct
+ *     an add custom link button. data is null if you want to construct an
+ *     empty tile. isAddButton can only be set if custom links is enabled.
  */
 var renderTile = function(data) {
   if (isMDEnabled) {
@@ -543,8 +585,9 @@
 
 /**
  * Renders a MostVisited tile with Material Design styles.
- * @param {object} data Object containing rid, url, title, favicon. data is null
- *     if you want to construct an empty tile.
+ * @param {object} data Object containing rid, url, title, favicon, and
+ *     optionally isAddButton. isAddButton is if you want to construct an add
+ *     custom link button. data is null if you want to construct an empty tile.
  * @return {Element}
  */
 function renderMaterialDesignTile(data) {
@@ -570,13 +613,18 @@
   mdTile.title = data.title;
 
   mdTile.addEventListener('click', function(ev) {
-    logMostVisitedNavigation(
-        position, data.tileTitleSource, data.tileSource, tileType,
-        data.dataGenerationTime);
+    if (data.isAddButton) {
+      addCustomLink();
+    } else {
+      logMostVisitedNavigation(
+          position, data.tileTitleSource, data.tileSource, tileType,
+          data.dataGenerationTime);
+    }
   });
   mdTile.addEventListener('keydown', function(event) {
-    if (event.keyCode == 46 /* DELETE */ ||
-        event.keyCode == 8 /* BACKSPACE */) {
+    if ((event.keyCode == 46 /* DELETE */ ||
+         event.keyCode == 8 /* BACKSPACE */) &&
+        !data.isAddButton) {
       event.preventDefault();
       event.stopPropagation();
       blacklistTile(this);
@@ -602,47 +650,58 @@
 
   let mdFavicon = document.createElement('div');
   mdFavicon.className = CLASSES.MD_FAVICON;
-  let fi = document.createElement('img');
-  // TODO(crbug.com/853780): Use data.fallbackBackgroundColorRgba and
-  // data.fallbackTextColorRgba;
-  fi.src = 'chrome-search://ntpicon/size/24@' + window.devicePixelRatio + 'x/' +
-      data.url;
-  // Set title and alt to empty so screen readers won't say the image name.
-  fi.title = '';
-  fi.alt = '';
-  loadedCounter += 1;
-  fi.addEventListener('load', function(ev) {
-    // Store the type for a potential later navigation.
-    tileType = TileVisualType.ICON_REAL;
-    logMostVisitedImpression(
-        position, data.tileTitleSource, data.tileSource, tileType,
-        data.dataGenerationTime);
-    // Note: It's important to call countLoad last, because that might emit the
-    // NTP_ALL_TILES_LOADED event, which must happen after the impression log.
-    countLoad();
-  });
-  fi.addEventListener('error', function(ev) {
-    let fallbackBackground = document.createElement('div');
-    fallbackBackground.className = CLASSES.MD_FALLBACK_BACKGROUND;
-    let fallbackLetter = document.createElement('div');
-    fallbackLetter.className = CLASSES.MD_FALLBACK_LETTER;
-    fallbackLetter.innerText = data.title.charAt(0).toUpperCase();
-    mdFavicon.classList.add(CLASSES.FAILED_FAVICON);
+  if (data.isAddButton) {
+    let mdAdd = document.createElement('div');
+    mdAdd.className = CLASSES.MD_ADD_ICON;
+    let addBackground = document.createElement('div');
+    addBackground.className = CLASSES.MD_ADD_BACKGROUND;
 
-    fallbackBackground.appendChild(fallbackLetter);
-    mdFavicon.removeChild(fi);
-    mdFavicon.appendChild(fallbackBackground);
+    addBackground.appendChild(mdAdd);
+    mdFavicon.appendChild(addBackground);
+  } else {
+    let fi = document.createElement('img');
+    // Set title and alt to empty so screen readers won't say the image name.
+    fi.title = '';
+    fi.alt = '';
+    fi.src = 'chrome-search://ntpicon/size/24@' + window.devicePixelRatio +
+        'x/' + data.url;
+    loadedCounter += 1;
+    fi.addEventListener('load', function(ev) {
+      // Store the type for a potential later navigation.
+      tileType = TileVisualType.ICON_REAL;
+      logMostVisitedImpression(
+          position, data.tileTitleSource, data.tileSource, tileType,
+          data.dataGenerationTime);
+      // Note: It's important to call countLoad last, because that might emit
+      // the NTP_ALL_TILES_LOADED event, which must happen after the impression
+      // log.
+      countLoad();
+    });
+    fi.addEventListener('error', function(ev) {
+      let fallbackBackground = document.createElement('div');
+      fallbackBackground.className = CLASSES.MD_FALLBACK_BACKGROUND;
+      let fallbackLetter = document.createElement('div');
+      fallbackLetter.className = CLASSES.MD_FALLBACK_LETTER;
+      fallbackLetter.innerText = data.title.charAt(0).toUpperCase();
+      mdFavicon.classList.add(CLASSES.FAILED_FAVICON);
 
-    // Store the type for a potential later navigation.
-    tileType = TileVisualType.ICON_DEFAULT;
-    logMostVisitedImpression(
-        position, data.tileTitleSource, data.tileSource, tileType,
-        data.dataGenerationTime);
-    // Note: It's important to call countLoad last, because that might emit the
-    // NTP_ALL_TILES_LOADED event, which must happen after the impression log.
-    countLoad();
-  });
-  mdFavicon.appendChild(fi);
+      fallbackBackground.appendChild(fallbackLetter);
+      mdFavicon.removeChild(fi);
+      mdFavicon.appendChild(fallbackBackground);
+
+      // Store the type for a potential later navigation.
+      tileType = TileVisualType.ICON_DEFAULT;
+      logMostVisitedImpression(
+          position, data.tileTitleSource, data.tileSource, tileType,
+          data.dataGenerationTime);
+      // Note: It's important to call countLoad last, because that might emit
+      // the NTP_ALL_TILES_LOADED event, which must happen after the impression
+      // log.
+      countLoad();
+    });
+
+    mdFavicon.appendChild(fi);
+  }
 
   mdIcon.appendChild(mdFavicon);
   mdTileInner.appendChild(mdIcon);
@@ -655,24 +714,27 @@
   mdTitle.style.direction = data.direction || 'ltr';
   mdTitleContainer.appendChild(mdTitle);
   mdTileInner.appendChild(mdTitleContainer);
-
-  let mdMenu = document.createElement('button');
-  mdMenu.className = CLASSES.MD_MENU;
-  mdMenu.title = queryArgs['removeTooltip'] || '';
-  mdMenu.addEventListener('click', function(ev) {
-    removeAllOldTiles();
-    blacklistTile(mdTile);
-    ev.preventDefault();
-    ev.stopPropagation();
-  });
-  // Don't allow the event to bubble out to the containing tile, as that would
-  // trigger navigation to the tile URL.
-  mdMenu.addEventListener('keydown', function(event) {
-    event.stopPropagation();
-  });
-
   mdTile.appendChild(mdTileInner);
-  mdTile.appendChild(mdMenu);
+
+  if (!data.isAddButton) {
+    let mdMenu = document.createElement('button');
+    mdMenu.className = CLASSES.MD_MENU;
+    mdMenu.title = queryArgs['removeTooltip'] || '';
+    mdMenu.addEventListener('click', function(ev) {
+      removeAllOldTiles();
+      blacklistTile(mdTile);
+      ev.preventDefault();
+      ev.stopPropagation();
+    });
+    // Don't allow the event to bubble out to the containing tile, as that would
+    // trigger navigation to the tile URL.
+    mdMenu.addEventListener('keydown', function(event) {
+      event.stopPropagation();
+    });
+
+    mdTile.appendChild(mdMenu);
+  }
+
   return mdTile;
 }
 
@@ -715,6 +777,11 @@
     document.body.classList.add(CLASSES.MATERIAL_DESIGN);
   }
 
+  // Enable custom links.
+  if (queryArgs['enableCustomLinks'] == '1') {
+    isCustomLinksEnabled = true;
+  }
+
   window.addEventListener('message', handlePostMessage);
 };
 
diff --git a/chrome/browser/resources/md_extensions/error_page.js b/chrome/browser/resources/md_extensions/error_page.js
index 360b01a9..ea9ec3a 100644
--- a/chrome/browser/resources/md_extensions/error_page.js
+++ b/chrome/browser/resources/md_extensions/error_page.js
@@ -76,6 +76,13 @@
       /** @type {!extensions.ErrorPageDelegate|undefined} */
       delegate: Object,
 
+      // Whether or not dev mode is enabled.
+      inDevMode: {
+        type: Boolean,
+        value: false,
+        observer: 'onInDevModeChanged_',
+      },
+
       /** @private {!Array<!(ManifestError|RuntimeError)>} */
       entries_: Array,
 
@@ -198,6 +205,16 @@
       e.stopPropagation();
     },
 
+    /** private */
+    onInDevModeChanged_: function() {
+      if (!this.inDevMode) {
+        // Wait until next render cycle in case error page is loading.
+        this.async(() => {
+          this.onCloseButtonTap_();
+        });
+      }
+    },
+
     /**
      * Fetches the source for the selected error and populates the code section.
      * @private
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index 9772389..c1d1fb0 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -104,7 +104,7 @@
       <cr-lazy-render id="error-page">
         <template>
           <extensions-error-page data="[[errorPageItem_]]" slot="view"
-              delegate="[[delegate]]" slot="view">
+              delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
           </extensions-error-page>
         </template>
       </cr-lazy-render>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index a298548..b0e03709 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -113,6 +113,12 @@
     'subpage-expand': 'onSubpageExpanded_',
   },
 
+  /**
+   * Used to avoid handling a new toggle while currently toggling.
+   * @private {boolean}
+   */
+  advancedTogglingInProgress_: false,
+
   /** @override */
   attached: function() {
     this.currentRoute_ = settings.getCurrentRoute();
@@ -291,12 +297,21 @@
   },
 
   advancedToggleClicked_: function() {
+    if (this.advancedTogglingInProgress_)
+      return;
+
+    this.advancedTogglingInProgress_ = true;
     const toggle = this.$$('#toggleContainer');
     if (!this.advancedToggleExpanded) {
       this.advancedToggleExpanded = true;
       this.async(() => {
-        this.$$('#advancedPageTemplate').get().then(advancedPage => {
-          this.fire('scroll-to-top', toggle.offsetTop);
+        this.$$('#advancedPageTemplate').get().then(() => {
+          this.fire('scroll-to-top', {
+            top: toggle.offsetTop,
+            callback: () => {
+              this.advancedTogglingInProgress_ = false;
+            }
+          });
         });
       });
     } else {
@@ -304,6 +319,7 @@
         bottom: toggle.offsetTop + toggle.offsetHeight + 24,
         callback: () => {
           this.advancedToggleExpanded = false;
+          this.advancedTogglingInProgress_ = false;
         }
       });
     }
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 4464e116e..b3e2d45 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -197,22 +197,24 @@
     // Preload bold Roboto so it doesn't load and flicker the first time used.
     document.fonts.load('bold 12px Roboto');
     settings.setGlobalScrollTarget(this.$.container);
-    this.addEventListener('scroll-to-top', event => {
-      this.$.container.scrollTo({top: event.detail, behavior: 'smooth'});
-    });
-    this.addEventListener('scroll-to-bottom', event => {
-      this.$.container.scrollTo({
-        top: event.detail.bottom - this.$.container.clientHeight,
-        behavior: 'smooth'
-      });
+
+    const scrollToTop = top => new Promise(resolve => {
+      this.$.container.scrollTo({top, behavior: 'smooth'});
       const onScroll = () => {
         this.debounce('scrollEnd', () => {
-          event.detail.callback();
           this.$.container.removeEventListener('scroll', onScroll);
+          resolve();
         }, 75);
       };
       this.$.container.addEventListener('scroll', onScroll);
     });
+    this.addEventListener('scroll-to-top', e => {
+      scrollToTop(e.detail.top).then(e.detail.callback);
+    });
+    this.addEventListener('scroll-to-bottom', e => {
+      scrollToTop(e.detail.bottom - this.$.container.clientHeight)
+          .then(e.detail.callback);
+    });
   },
 
   /** @override */
diff --git a/chrome/browser/resources/settings/site_settings/BUILD.gn b/chrome/browser/resources/settings/site_settings/BUILD.gn
index 4a94b84a..1a7dcca 100644
--- a/chrome/browser/resources/settings/site_settings/BUILD.gn
+++ b/chrome/browser/resources/settings/site_settings/BUILD.gn
@@ -196,6 +196,7 @@
     "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:list_property_update_behavior",
     "//ui/webui/resources/js:web_ui_listener_behavior",
     "//ui/webui/resources/js/cr/ui:focus_without_ink",
   ]
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 80f5ac7..10c0cfc 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://resources/html/list_property_update_behavior.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="../i18n_setup.html">
@@ -59,7 +60,7 @@
         </button>
       </cr-action-menu>
 
-      <div class="list-frame" hidden$="[[hasSites_(sites)]]">
+      <div class="list-frame" hidden$="[[hasSites_(sites.*)]]">
         <div class="list-item secondary">$i18n{noSitesAdded}</div>
       </div>
       <div class="list-frame menu-content vertical-list" id="listContainer">
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js
index fad337e..1781ec3 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -11,7 +11,11 @@
 
   is: 'site-list',
 
-  behaviors: [SiteSettingsBehavior, WebUIListenerBehavior],
+  behaviors: [
+    SiteSettingsBehavior,
+    WebUIListenerBehavior,
+    ListPropertyUpdateBehavior,
+  ],
 
   properties: {
     /** @private */
@@ -233,53 +237,24 @@
    */
   populateList_: function() {
     this.browserProxy_.getExceptionList(this.category).then(exceptionList => {
-      this.processExceptions_([exceptionList]);
+      this.processExceptions_(exceptionList);
       this.closeActionMenu_();
     });
   },
 
   /**
    * Process the exception list returned from the native layer.
-   * @param {!Array<!Array<RawSiteException>>} data List of sites (exceptions)
-   *     to process.
+   * @param {!Array<RawSiteException>} exceptionList
    * @private
    */
-  processExceptions_: function(data) {
-    const sites = /** @type {!Array<RawSiteException>} */ ([]);
-    for (let i = 0; i < data.length; ++i) {
-      const exceptionList = data[i];
-      for (let k = 0; k < exceptionList.length; ++k) {
-        if (exceptionList[k].setting == settings.ContentSetting.DEFAULT ||
-            exceptionList[k].setting != this.categorySubtype) {
-          continue;
-        }
-
-        sites.push(exceptionList[k]);
-      }
-    }
-    this.sites = this.toSiteArray_(sites);
-  },
-
-  /**
-   * Converts a list of exceptions received from the C++ handler to
-   * full SiteException objects.
-   * @param {!Array<RawSiteException>} sites A list of sites to convert.
-   * @return {!Array<SiteException>} A list of full SiteExceptions.
-   * @private
-   */
-  toSiteArray_: function(sites) {
-    const results = /** @type {!Array<SiteException>} */ ([]);
-    let lastOrigin = '';
-    let lastEmbeddingOrigin = '';
-    for (let i = 0; i < sites.length; ++i) {
-      /** @type {!SiteException} */
-      const siteException = this.expandSiteException(sites[i]);
-
-      results.push(siteException);
-      lastOrigin = siteException.origin;
-      lastEmbeddingOrigin = siteException.embeddingOrigin;
-    }
-    return results;
+  processExceptions_: function(exceptionList) {
+    const sites =
+        exceptionList
+            .filter(
+                site => site.setting != settings.ContentSetting.DEFAULT &&
+                    site.setting == this.categorySubtype)
+            .map(site => this.expandSiteException(site));
+    this.updateList('sites', x => x.origin, sites);
   },
 
   /**
diff --git a/chrome/browser/search/iframe_source.cc b/chrome/browser/search/iframe_source.cc
index 5149906f..e8e9bba9 100644
--- a/chrome/browser/search/iframe_source.cc
+++ b/chrome/browser/search/iframe_source.cc
@@ -29,6 +29,8 @@
     return "text/css";
   if (base::EndsWith(path, ".html", base::CompareCase::INSENSITIVE_ASCII))
     return "text/html";
+  if (base::EndsWith(path, ".svg", base::CompareCase::INSENSITIVE_ASCII))
+    return "image/svg+xml";
   return std::string();
 }
 
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 8d55b37..41707bd 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -44,6 +44,39 @@
 
 namespace {
 
+const char* kNtpCustomBackgroundURL = "background_url";
+const char* kNtpCustomBackgroundAttributionLine1 = "attribution_line_1";
+const char* kNtpCustomBackgroundAttributionLine2 = "attribution_line_2";
+const char* kNtpCustomBackgroundAttributionActionURL = "attribution_action_url";
+
+base::DictionaryValue GetBackgroundInfoAsDict(
+    const GURL& background_url,
+    const std::string& attribution_line_1,
+    const std::string& attribution_line_2,
+    const GURL& action_url) {
+  base::DictionaryValue background_info;
+  background_info.SetKey(kNtpCustomBackgroundURL,
+                         base::Value(background_url.spec()));
+  background_info.SetKey(kNtpCustomBackgroundAttributionLine1,
+                         base::Value(attribution_line_1));
+  background_info.SetKey(kNtpCustomBackgroundAttributionLine2,
+                         base::Value(attribution_line_2));
+  background_info.SetKey(kNtpCustomBackgroundAttributionActionURL,
+                         base::Value(action_url.spec()));
+
+  return background_info;
+}
+
+std::unique_ptr<base::DictionaryValue> NtpCustomBackgroundDefaults() {
+  std::unique_ptr<base::DictionaryValue> defaults =
+      std::make_unique<base::DictionaryValue>();
+  defaults->SetString(kNtpCustomBackgroundURL, std::string());
+  defaults->SetString(kNtpCustomBackgroundAttributionLine1, std::string());
+  defaults->SetString(kNtpCustomBackgroundAttributionLine2, std::string());
+  defaults->SetString(kNtpCustomBackgroundAttributionActionURL, std::string());
+  return defaults;
+}
+
 void CopyFileToProfilePath(const base::FilePath& from_path) {
   base::FilePath user_data_dir;
   base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
@@ -52,6 +85,14 @@
   base::CopyFile(from_path, to_path);
 }
 
+void RemoveLocalBackgroundImageCopy() {
+  base::FilePath user_data_dir;
+  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  base::FilePath path(user_data_dir.AppendASCII(
+      chrome::kChromeSearchLocalNtpBackgroundFilename));
+  base::DeleteFile(path, false);
+}
+
 }  // namespace
 
 InstantService::InstantService(Profile* profile)
@@ -154,7 +195,7 @@
     BuildThemeInfo();
   }
 
-  ApplyGoogleNtpThemeElements();
+  ApplyOrResetCustomBackgroundThemeInfo();
 
   NotifyAboutThemeInfo();
 }
@@ -173,11 +214,23 @@
 }
 
 void InstantService::SetCustomBackgroundURL(const GURL& url) {
-  PrefService* pref_service_ = profile_->GetPrefs();
-  if (url.is_empty()) {
-    pref_service_->ClearPref(prefs::kNTPCustomBackgroundURL);
+  SetCustomBackgroundURLWithAttributions(url, std::string(), std::string(),
+                                         GURL());
+}
+
+void InstantService::SetCustomBackgroundURLWithAttributions(
+    const GURL& background_url,
+    const std::string& attribution_line_1,
+    const std::string& attribution_line_2,
+    const GURL& action_url) {
+  PrefService* pref_service = profile_->GetPrefs();
+
+  if (background_url.is_valid()) {
+    base::DictionaryValue background_info = GetBackgroundInfoAsDict(
+        background_url, attribution_line_1, attribution_line_2, action_url);
+    pref_service->Set(prefs::kNtpCustomBackgroundDict, background_info);
   } else {
-    pref_service_->SetString(prefs::kNTPCustomBackgroundURL, url.spec());
+    pref_service->ClearPref(prefs::kNtpCustomBackgroundDict);
   }
 
   UpdateThemeInfo();
@@ -189,8 +242,11 @@
   std::string time_string = std::to_string(base::Time::Now().ToTimeT());
   std::string local_string(chrome::kChromeSearchLocalNtpBackgroundUrl);
   GURL timestamped_url(local_string + "?ts=" + time_string);
-  profile_->GetPrefs()->SetString(prefs::kNTPCustomBackgroundURL,
-                                  timestamped_url.spec());
+
+  base::DictionaryValue background_info = GetBackgroundInfoAsDict(
+      timestamped_url, std::string(), std::string(), GURL());
+  PrefService* pref_service = profile_->GetPrefs();
+  pref_service->Set(prefs::kNtpCustomBackgroundDict, background_info);
   UpdateThemeInfo();
 }
 
@@ -395,18 +451,78 @@
   }
 }
 
-void InstantService::ApplyGoogleNtpThemeElements() {
-  // User has set a custom background image.
+// TODO(crbug.com/863942): Should switching default search provider retain the
+// copy of user uploaded photos?
+void InstantService::ApplyOrResetCustomBackgroundThemeInfo() {
+  // Custom backgrounds for non-Google search providers are not supported.
+  if (!search::DefaultSearchProviderIsGoogle(profile_)) {
+    ResetCustomBackgroundThemeInfo();
+    return;
+  }
+
+  // Attempt to get custom background URL from preferences.
+  const base::DictionaryValue* background_info =
+      profile_->GetPrefs()->GetDictionary(prefs::kNtpCustomBackgroundDict);
+  const base::Value* background_url =
+      background_info->FindKey(kNtpCustomBackgroundURL);
+  if (!background_url) {
+    ResetCustomBackgroundThemeInfo();
+    return;
+  }
+
+  // Verify that the custom background URL is valid.
   GURL custom_background_url(
-      profile_->GetPrefs()->GetString(prefs::kNTPCustomBackgroundURL));
-  if (custom_background_url.is_valid() &&
-      search::DefaultSearchProviderIsGoogle(profile_)) {
-    theme_info_->custom_background_url = custom_background_url;
-  } else {
-    theme_info_->custom_background_url = GURL::EmptyGURL();
+      background_info->FindKey(kNtpCustomBackgroundURL)->GetString());
+  if (!custom_background_url.is_valid()) {
+    ResetCustomBackgroundThemeInfo();
+    return;
+  }
+
+  // Set custom background information in theme info (attributions are
+  // optional).
+  const base::Value* attribution_line_1 =
+      background_info->FindKey(kNtpCustomBackgroundAttributionLine1);
+  const base::Value* attribution_line_2 =
+      background_info->FindKey(kNtpCustomBackgroundAttributionLine2);
+  const base::Value* attribution_action_url =
+      background_info->FindKey(kNtpCustomBackgroundAttributionActionURL);
+
+  theme_info_->custom_background_url = custom_background_url;
+
+  if (attribution_line_1) {
+    theme_info_->custom_background_attribution_line_1 =
+        background_info->FindKey(kNtpCustomBackgroundAttributionLine1)
+            ->GetString();
+  }
+  if (attribution_line_2) {
+    theme_info_->custom_background_attribution_line_2 =
+        background_info->FindKey(kNtpCustomBackgroundAttributionLine2)
+            ->GetString();
+  }
+  if (attribution_action_url) {
+    GURL action_url(
+        background_info->FindKey(kNtpCustomBackgroundAttributionActionURL)
+            ->GetString());
+
+    if (action_url.SchemeIsCryptographic()) {
+      theme_info_->custom_background_attribution_action_url = action_url;
+    }
   }
 }
 
+void InstantService::ResetCustomBackgroundThemeInfo() {
+  profile_->GetPrefs()->ClearPref(prefs::kNtpCustomBackgroundDict);
+  base::PostTaskWithTraits(FROM_HERE,
+                           {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
+                           base::BindOnce(&RemoveLocalBackgroundImageCopy));
+
+  theme_info_->custom_background_url = GURL();
+  theme_info_->custom_background_attribution_line_1 = std::string();
+  theme_info_->custom_background_attribution_line_2 = std::string();
+  theme_info_->custom_background_attribution_action_url = GURL();
+}
+
 void InstantService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
-  registry->RegisterStringPref(prefs::kNTPCustomBackgroundURL, std::string());
+  registry->RegisterDictionaryPref(prefs::kNtpCustomBackgroundDict,
+                                   NtpCustomBackgroundDefaults());
 }
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index db314e4d..3ad108e 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -97,9 +97,19 @@
   // Invoked when a custom background is selected on the NTP.
   void SetCustomBackgroundURL(const GURL& url);
 
+  // Invoked when a custom background with attributions is selected on the NTP.
+  void SetCustomBackgroundURLWithAttributions(
+      const GURL& background_url,
+      const std::string& attribution_line_1,
+      const std::string& attribution_line_2,
+      const GURL& action_url);
+
   // Invoked when a user selected the "Upload an image" option on the NTP.
   void SelectLocalBackgroundImage(const base::FilePath& path);
 
+  // Used for testing.
+  ThemeBackgroundInfo* GetThemeInfoForTesting() { return theme_info_.get(); }
+
  private:
   friend class InstantExtendedTest;
   friend class InstantUnitTestBase;
@@ -129,7 +139,9 @@
 
   void BuildThemeInfo();
 
-  void ApplyGoogleNtpThemeElements();
+  void ApplyOrResetCustomBackgroundThemeInfo();
+
+  void ResetCustomBackgroundThemeInfo();
 
   // Update the background pref to point to
   // chrome-search://local-ntp/background.jpg
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc
index a817174..89e8d246 100644
--- a/chrome/browser/search/instant_service_unittest.cc
+++ b/chrome/browser/search/instant_service_unittest.cc
@@ -6,8 +6,12 @@
 
 #include <vector>
 
+#include "base/files/file_util.h"
+#include "base/path_service.h"
 #include "chrome/browser/search/instant_unittest_base.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/search/instant_types.h"
+#include "chrome/common/url_constants.h"
 #include "components/ntp_tiles/ntp_tile.h"
 #include "components/ntp_tiles/section_type.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -31,3 +35,92 @@
   EXPECT_EQ(ntp_tiles::TileSource::TOP_SITES, items[0].source);
   EXPECT_EQ(ntp_tiles::TileTitleSource::TITLE_TAG, items[0].title_source);
 }
+
+TEST_F(InstantServiceTest, SetCustomBackgroundURL) {
+  const GURL kUrl("https://www.foo.com");
+  instant_service_->SetCustomBackgroundURL(kUrl);
+
+  ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(kUrl, theme_info->custom_background_url);
+}
+
+TEST_F(InstantServiceTest, SetCustomBackgroundURLInvalidURL) {
+  const GURL kUrl("foo");
+  instant_service_->SetCustomBackgroundURL(kUrl);
+
+  ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(std::string(), theme_info->custom_background_url.spec());
+}
+
+TEST_F(InstantServiceTest, SetCustomBackgroundURLWithAttributions) {
+  const GURL kUrl("https://www.foo.com");
+  const std::string kAttributionLine1 = "foo";
+  const std::string kAttributionLine2 = "bar";
+  const GURL kActionUrl("https://www.bar.com");
+  instant_service_->SetCustomBackgroundURLWithAttributions(
+      kUrl, kAttributionLine1, kAttributionLine2, kActionUrl);
+
+  ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(kUrl, theme_info->custom_background_url);
+  EXPECT_EQ(kAttributionLine1,
+            theme_info->custom_background_attribution_line_1);
+  EXPECT_EQ(kAttributionLine2,
+            theme_info->custom_background_attribution_line_2);
+  EXPECT_EQ(kActionUrl, theme_info->custom_background_attribution_action_url);
+}
+
+TEST_F(InstantServiceTest, ChangingSearchProviderClearsThemeInfoAndPref) {
+  const GURL kUrl("https://www.foo.com");
+  const std::string kAttributionLine1 = "foo";
+  const std::string kAttributionLine2 = "bar";
+  const GURL kActionUrl("https://www.bar.com");
+
+  SetUserSelectedDefaultSearchProvider("{google:baseURL}");
+  instant_service_->SetCustomBackgroundURLWithAttributions(
+      kUrl, kAttributionLine1, kAttributionLine2, kActionUrl);
+
+  ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(kUrl, theme_info->custom_background_url);
+  EXPECT_EQ(kAttributionLine1,
+            theme_info->custom_background_attribution_line_1);
+  EXPECT_EQ(kAttributionLine2,
+            theme_info->custom_background_attribution_line_2);
+  EXPECT_EQ(kActionUrl, theme_info->custom_background_attribution_action_url);
+
+  SetUserSelectedDefaultSearchProvider("https://www.search.com");
+  instant_service_->UpdateThemeInfo();
+
+  theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(GURL(), theme_info->custom_background_url);
+  EXPECT_EQ(std::string(), theme_info->custom_background_attribution_line_1);
+  EXPECT_EQ(std::string(), theme_info->custom_background_attribution_line_2);
+  EXPECT_EQ(GURL(), theme_info->custom_background_attribution_action_url);
+
+  SetUserSelectedDefaultSearchProvider("{google:baseURL}");
+  instant_service_->UpdateThemeInfo();
+
+  theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(GURL(), theme_info->custom_background_url);
+  EXPECT_EQ(std::string(), theme_info->custom_background_attribution_line_1);
+  EXPECT_EQ(std::string(), theme_info->custom_background_attribution_line_2);
+  EXPECT_EQ(GURL(), theme_info->custom_background_attribution_action_url);
+}
+
+TEST_F(InstantServiceTest,
+       ChangingSearchProviderRemovesLocalBackgroundImageCopy) {
+  base::FilePath user_data_dir;
+  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  base::FilePath path(user_data_dir.AppendASCII(
+      chrome::kChromeSearchLocalNtpBackgroundFilename));
+
+  base::WriteFile(path, "background_image", 16);
+
+  SetUserSelectedDefaultSearchProvider("https://www.search.com");
+  instant_service_->UpdateThemeInfo();
+
+  base::TaskScheduler::GetInstance()->FlushForTesting();
+
+  bool file_exists = base::PathExists(path);
+
+  EXPECT_EQ(false, file_exists);
+}
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 5fe249a..987641d 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -231,6 +231,8 @@
   config_data.SetBoolean("isMDIconsEnabled", features::IsMDIconsEnabled());
 
   if (is_google) {
+    config_data.SetBoolean("isCustomLinksEnabled",
+                           features::IsCustomLinksEnabled());
     config_data.SetBoolean("isCustomBackgroundsEnabled",
                            features::IsCustomBackgroundsEnabled());
   }
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index d7641c8..7abd3681d 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -30,6 +30,15 @@
 const char kUtilJSPath[] = "/util.js";
 const char kCommonCSSPath[] = "/common.css";
 
+// Add custom link button icon.
+const char kAddSvgPath[] = "/add_link.svg";
+
+// Edit custom links dialog iframe, used by the local NTP and the Google remote
+// NTP.
+const char kEditHTMLPath[] = "/edit.html";
+const char kEditCSSPath[] = "/edit.css";
+const char kEditJSPath[] = "/edit.js";
+
 }  // namespace
 
 MostVisitedIframeSource::MostVisitedIframeSource() = default;
@@ -87,6 +96,14 @@
     SendJSWithOrigin(IDR_MOST_VISITED_UTIL_JS, wc_getter, callback);
   } else if (path == kCommonCSSPath) {
     SendResource(IDR_MOST_VISITED_IFRAME_CSS, callback);
+  } else if (path == kEditHTMLPath) {
+    SendResource(IDR_CUSTOM_LINKS_EDIT_HTML, callback);
+  } else if (path == kEditCSSPath) {
+    SendResource(IDR_CUSTOM_LINKS_EDIT_CSS, callback);
+  } else if (path == kEditJSPath) {
+    SendJSWithOrigin(IDR_CUSTOM_LINKS_EDIT_JS, wc_getter, callback);
+  } else if (path == kAddSvgPath) {
+    SendResource(IDR_CUSTOM_LINKS_ADD_SVG, callback);
   } else {
     callback.Run(nullptr);
   }
@@ -98,5 +115,6 @@
          path == kTitleCSSPath || path == kTitleJSPath ||
          path == kThumbnailHTMLPath || path == kThumbnailCSSPath ||
          path == kThumbnailJSPath || path == kUtilJSPath ||
-         path == kCommonCSSPath;
+         path == kCommonCSSPath || path == kEditHTMLPath ||
+         path == kEditCSSPath || path == kEditJSPath || path == kAddSvgPath;
 }
diff --git a/chrome/browser/search/ntp_features.cc b/chrome/browser/search/ntp_features.cc
index 5611710..eb53fe6 100644
--- a/chrome/browser/search/ntp_features.cc
+++ b/chrome/browser/search/ntp_features.cc
@@ -34,6 +34,10 @@
   return ntp_tiles::IsMDIconsEnabled();
 }
 
+bool IsCustomLinksEnabled() {
+  return ntp_tiles::IsCustomLinksEnabled();
+}
+
 bool IsCustomBackgroundsEnabled() {
   return base::FeatureList::IsEnabled(kNtpBackgrounds) ||
          base::FeatureList::IsEnabled(features::kExperimentalUi);
diff --git a/chrome/browser/search/ntp_features.h b/chrome/browser/search/ntp_features.h
index d9a0df3..9b0b75ffc 100644
--- a/chrome/browser/search/ntp_features.h
+++ b/chrome/browser/search/ntp_features.h
@@ -18,9 +18,12 @@
 // Returns whether the Material Design UI is enabled on the New Tab Page.
 bool IsMDUIEnabled();
 
-// Returns whether New Tab Page Custom Link Icons are enabled.
+// Returns whether the Material Design UI for Most Visited is enabled.
 bool IsMDIconsEnabled();
 
+// Returns whether New Tab Page custom links are enabled.
+bool IsCustomLinksEnabled();
+
 // Returns whether New Tab Page Background Selection is enabled.
 bool IsCustomBackgroundsEnabled();
 
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
index 7a806c2..48ec26ef 100644
--- a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
+++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
@@ -14,7 +14,6 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
-#include "base/guid.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_params.h"
@@ -70,17 +69,11 @@
 // overidden by a field trial group.  See https://crbug.com/487270.
 const uint64_t kDeltaDefaultExpirationInSeconds = UINT64_C(604800);
 
-// Field trial information
-const char kRevertCertificateErrorDecisionsFieldTrialName[] =
-    "RevertCertificateErrorDecisions";
-const char kForgetAtSessionEndGroup[] = "Session";
-
 // Keys for the per-site error + certificate finger to judgment content
 // settings map.
 const char kSSLCertDecisionCertErrorMapKey[] = "cert_exceptions_map";
 const char kSSLCertDecisionExpirationTimeKey[] = "decision_expiration_time";
 const char kSSLCertDecisionVersionKey[] = "version";
-const char kSSLCertDecisionGUIDKey[] = "guid";
 
 const int kDefaultSSLCertDecisionVersion = 1;
 
@@ -181,17 +174,6 @@
   return GURL(url);
 }
 
-// By default, certificate exception decisions are remembered for one week.
-// However, there is a field trial group for the "old" style of certificate
-// decision memory that expires decisions at session end. ExpireAtSessionEnd()
-// returns |true| if and only if the user is in that field trial group.
-bool ExpireAtSessionEnd() {
-  std::string group_name = base::FieldTrialList::FindFullName(
-      kRevertCertificateErrorDecisionsFieldTrialName);
-  return !group_name.empty() &&
-         group_name.compare(kForgetAtSessionEndGroup) == 0;
-}
-
 std::string GetKey(const net::X509Certificate& cert, int error) {
   // Since a security decision will be made based on the fingerprint, Chrome
   // should use the SHA-256 fingerprint for the certificate.
@@ -264,22 +246,10 @@
 const base::Feature kRecurrentInterstitialFeature{
     "RecurrentInterstitialFeature", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// If |should_remember_ssl_decisions_| is
-// FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END, that means that all invalid
-// certificate proceed decisions should be forgotten when the session ends. To
-// simulate that, Chrome keeps track of a guid to represent the current browser
-// session and stores it in decision entries. See the comment for
-// |current_expiration_guid_| for more information.
 ChromeSSLHostStateDelegate::ChromeSSLHostStateDelegate(Profile* profile)
     : clock_(new base::DefaultClock()),
-      profile_(profile),
-      current_expiration_guid_(base::GenerateGUID()) {
+      profile_(profile) {
   MigrateOldSettings(HostContentSettingsMapFactory::GetForProfile(profile));
-  if (ExpireAtSessionEnd())
-    should_remember_ssl_decisions_ =
-        FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END;
-  else
-    should_remember_ssl_decisions_ = REMEMBER_SSL_EXCEPTION_DECISIONS_FOR_DELTA;
 }
 
 ChromeSSLHostStateDelegate::~ChromeSSLHostStateDelegate() {
@@ -626,9 +596,7 @@
   // NULL.
   // - Expired and |create_entries| is CREATE_DICTIONARY_ENTRIES, update the
   // expiration time.
-  if (should_remember_ssl_decisions_ !=
-          FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END &&
-      decision_expiration.ToInternalValue() <= now.ToInternalValue()) {
+  if (decision_expiration.ToInternalValue() <= now.ToInternalValue()) {
     *expired_previous_decision = true;
 
     if (create_entries == DO_NOT_CREATE_DICTIONARY_ENTRIES)
@@ -642,20 +610,8 @@
     // better to store the value as a string.
     dict->SetString(kSSLCertDecisionExpirationTimeKey,
                     base::Int64ToString(expiration_time.ToInternalValue()));
-  } else if (should_remember_ssl_decisions_ ==
-             FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END) {
-    if (dict->HasKey(kSSLCertDecisionGUIDKey)) {
-      std::string old_expiration_guid;
-      success = dict->GetString(kSSLCertDecisionGUIDKey, &old_expiration_guid);
-      if (old_expiration_guid.compare(current_expiration_guid_) != 0) {
-        *expired_previous_decision = true;
-        expired = true;
-      }
-    }
   }
 
-  dict->SetString(kSSLCertDecisionGUIDKey, current_expiration_guid_);
-
   // Extract the map of certificate fingerprints to errors from the setting.
   base::DictionaryValue* cert_error_dict = NULL;  // Will be owned by dict
   if (expired ||
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate.h b/chrome/browser/ssl/chrome_ssl_host_state_delegate.h
index 065f179..77b8a9f1 100644
--- a/chrome/browser/ssl/chrome_ssl_host_state_delegate.h
+++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate.h
@@ -92,16 +92,6 @@
     DO_NOT_CREATE_DICTIONARY_ENTRIES
   };
 
-  // Specifies whether user SSL error decisions should be forgetten at the end
-  // of this current session (the old style of remembering decisions), or
-  // whether they should be remembered across session restarts for a specified
-  // length of time, deteremined by
-  // |default_ssl_cert_decision_expiration_delta_|.
-  enum RememberSSLExceptionDecisionsDisposition {
-    FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END,
-    REMEMBER_SSL_EXCEPTION_DECISIONS_FOR_DELTA
-  };
-
   // Returns a dictionary of certificate fingerprints and errors that have been
   // allowed as exceptions by the user.
   //
@@ -122,7 +112,6 @@
       bool* expired_previous_decision);
 
   std::unique_ptr<base::Clock> clock_;
-  RememberSSLExceptionDecisionsDisposition should_remember_ssl_decisions_;
   Profile* profile_;
 
   // A BrokenHostEntry is a pair of (host, child_id) that indicates the host
@@ -138,29 +127,6 @@
   // the specific process.
   std::set<BrokenHostEntry> ran_content_with_cert_errors_hosts_;
 
-  // This is a GUID to mark this unique session. Whenever a certificate decision
-  // expiration is set, the GUID is saved as well so Chrome can tell if it was
-  // last set during the current session. This is used by the
-  // FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END experimental group to
-  // determine if the expired_previous_decision bit should be set on queries.
-  //
-  // Why not just iterate over the set of current extensions and mark them all
-  // as expired when the session starts, rather than storing a GUID for the
-  // current session? Glad you asked! Unfortunately, content settings does not
-  // currently support iterating over all current *compound* content setting
-  // values (iteration only works for simple content settings). While this could
-  // be added, it would be a fair amount of work for what amounts to a temporary
-  // measurement problem, so it's not worth the complexity.
-  //
-  // TODO(jww): This is only used by the default and disable groups of the
-  // certificate memory decisions experiment to tell if a decision has expired
-  // since the last session. Since this is only used for UMA purposes, this
-  // should be removed after the experiment has finished, and a call to Clear()
-  // should be added to the constructor and destructor for members of the
-  // FORGET_SSL_EXCEPTION_DECISIONS_AT_SESSION_END groups. See
-  // https://crbug.com/418631 for more details.
-  const std::string current_expiration_guid_;
-
   // Tracks how many times an error page has been shown for a given error, up
   // to a certain threshold value.
   std::map<int /* error code */, int /* count */> recurrent_errors_;
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc b/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc
index 13b961e..44f4549 100644
--- a/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc
+++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc
@@ -48,12 +48,6 @@
   return net::ImportCertFromFile(net::GetTestCertsDirectory(), kOkCertFile);
 }
 
-// Helper function for setting Finch options
-void SetFinchConfig(base::CommandLine* command_line, const std::string& group) {
-  command_line->AppendSwitchASCII("--force-fieldtrials",
-                                  "RevertCertificateErrorDecisions/" + group);
-}
-
 bool CStrStringMatcher(const char* a, const std::string& b) {
   return a == b;
 }
@@ -491,83 +485,9 @@
       net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED));
 }
 
-class ForgetAtSessionEndSSLHostStateDelegateTest
-    : public ChromeSSLHostStateDelegateTest {
- protected:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    ChromeSSLHostStateDelegateTest::SetUpCommandLine(command_line);
-    SetFinchConfig(command_line, "Session");
-  }
-};
-
-// QueryPolicyExpired unit tests to make sure that if a certificate decision has
-// expired, the return value from QueryPolicy returns the correct vaule.
-IN_PROC_BROWSER_TEST_F(ForgetAtSessionEndSSLHostStateDelegateTest,
-                       PRE_QueryPolicyExpired) {
-  scoped_refptr<net::X509Certificate> cert = GetOkCert();
-  content::WebContents* tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
-  content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
-  bool expired_previous_decision;
-
-  // The certificate has never been seen before, so it should be UNKNOWN and
-  // should also indicate that it hasn't expired.
-  EXPECT_EQ(
-      content::SSLHostStateDelegate::DENIED,
-      state->QueryPolicy(kWWWGoogleHost, *cert, net::ERR_CERT_DATE_INVALID,
-                         &expired_previous_decision));
-  EXPECT_FALSE(expired_previous_decision);
-
-  // After allowing the certificate, a query should say that it is allowed and
-  // also specify that it hasn't expired.
-  state->AllowCert(kWWWGoogleHost, *cert, net::ERR_CERT_DATE_INVALID);
-  EXPECT_EQ(
-      content::SSLHostStateDelegate::ALLOWED,
-      state->QueryPolicy(kWWWGoogleHost, *cert, net::ERR_CERT_DATE_INVALID,
-                         &expired_previous_decision));
-  EXPECT_FALSE(expired_previous_decision);
-}
-
-// Since this is being checked on a browser instance that expires security
-// decisions after restart, the test needs to  wait until after a restart to
-// verify that the expiration state is correct.
-IN_PROC_BROWSER_TEST_F(ForgetAtSessionEndSSLHostStateDelegateTest,
-                       QueryPolicyExpired) {
-  scoped_refptr<net::X509Certificate> cert = GetOkCert();
-  content::WebContents* tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
-  content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
-  bool expired_previous_decision;
-
-  // The browser content has restart thus expiring the user decision made above,
-  // so it should indicate that the certificate and error are DENIED but also
-  // that they expired since the last query.
-  EXPECT_EQ(
-      content::SSLHostStateDelegate::DENIED,
-      state->QueryPolicy(kWWWGoogleHost, *cert, net::ERR_CERT_DATE_INVALID,
-                         &expired_previous_decision));
-  EXPECT_TRUE(expired_previous_decision);
-
-  // However, with a new query, it should indicate that no new expiration has
-  // occurred.
-  EXPECT_EQ(
-      content::SSLHostStateDelegate::DENIED,
-      state->QueryPolicy(kWWWGoogleHost, *cert, net::ERR_CERT_DATE_INVALID,
-                         &expired_previous_decision));
-  EXPECT_FALSE(expired_previous_decision);
-}
-
 // Tests the basic behavior of cert memory in incognito.
 class IncognitoSSLHostStateDelegateTest
-    : public ChromeSSLHostStateDelegateTest {
- protected:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    ChromeSSLHostStateDelegateTest::SetUpCommandLine(command_line);
-    SetFinchConfig(command_line, "OneWeek");
-  }
-};
+    : public ChromeSSLHostStateDelegateTest {};
 
 IN_PROC_BROWSER_TEST_F(IncognitoSSLHostStateDelegateTest, PRE_AfterRestart) {
   scoped_refptr<net::X509Certificate> cert = GetOkCert();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index b86684e..5e363d0 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1546,7 +1546,6 @@
       "toolbar/media_router_contextual_menu.h",
       "toolbar/recent_tabs_sub_menu_model.cc",
       "toolbar/recent_tabs_sub_menu_model.h",
-      "toolbar/toolbar_action_button_state.h",
       "toolbar/toolbar_action_view_controller.h",
       "toolbar/toolbar_action_view_delegate.h",
       "toolbar/toolbar_actions_bar.cc",
@@ -1728,6 +1727,7 @@
     deps += [
       "//chrome/app/vector_icons",
       "//chrome/browser:theme_properties",
+      "//chrome/browser/apps/foundation/app_service/public/mojom",
       "//chrome/browser/media/router",
       "//chrome/browser/profile_resetter:profile_reset_report_proto",
       "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc b/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
index c39a8ab3..1afb160 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
@@ -194,14 +194,12 @@
         resized_image, false /* discard_transparency */, &png_data);
   }
   if (encode_result) {
-    // Now save this so we can reload it later when needed.
-    crostini::CrostiniRegistryService* registry_service =
-        crostini::CrostiniRegistryServiceFactory::GetForProfile(
-            host_->profile());
-    DCHECK(registry_service);
+    if (!host_->registry_service_)
+      return;
 
+    // Now save this so we can reload it later when needed.
     const base::FilePath path =
-        registry_service->GetIconPath(host_->app_id(), scale_factor_);
+        host_->registry_service_->GetIconPath(host_->app_id(), scale_factor_);
     DCHECK(!path.empty());
     base::PostTaskWithTraits(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
@@ -231,7 +229,9 @@
                                  const std::string& app_id,
                                  int resource_size_in_dip,
                                  Observer* observer)
-    : profile_(profile),
+    : registry_service_(
+          crostini::CrostiniRegistryServiceFactory::GetForProfile(profile)
+              ->GetWeakPtr()),
       app_id_(app_id),
       resource_size_in_dip_(resource_size_in_dip),
       observer_(observer),
@@ -246,12 +246,10 @@
 CrostiniAppIcon::~CrostiniAppIcon() = default;
 
 void CrostiniAppIcon::LoadForScaleFactor(ui::ScaleFactor scale_factor) {
-  crostini::CrostiniRegistryService* registry_service =
-      crostini::CrostiniRegistryServiceFactory::GetForProfile(profile_);
-  DCHECK(registry_service);
+  DCHECK(registry_service_);
 
   const base::FilePath path =
-      registry_service->GetIconPath(app_id_, scale_factor);
+      registry_service_->GetIconPath(app_id_, scale_factor);
   DCHECK(!path.empty());
 
   base::PostTaskWithTraitsAndReplyWithResult(
@@ -263,14 +261,14 @@
 
 void CrostiniAppIcon::MaybeRequestIcon(ui::ScaleFactor scale_factor) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  crostini::CrostiniRegistryService* registry_service =
-      crostini::CrostiniRegistryServiceFactory::GetForProfile(profile_);
-  DCHECK(registry_service);
+  // Fail safely if the icon outlives the Profile (and the Crostini Registry).
+  if (!registry_service_)
+    return;
 
   // CrostiniRegistryService notifies CrostiniAppModelBuilder via Observer when
   // icon is ready and CrostiniAppModelBuilder refreshes the icon of the
   // corresponding item by calling LoadScaleFactor.
-  registry_service->MaybeRequestIcon(app_id_, scale_factor);
+  registry_service_->MaybeRequestIcon(app_id_, scale_factor);
 }
 
 // static
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_icon.h b/chrome/browser/ui/app_list/crostini/crostini_app_icon.h
index c68e4e4..a222687 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_icon.h
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_icon.h
@@ -19,6 +19,10 @@
 class FilePath;
 }
 
+namespace crostini {
+class CrostiniRegistryService;
+}
+
 class Profile;
 
 // A class that provides an ImageSkia for UI code to use. It handles Crostini
@@ -44,7 +48,6 @@
 
   const std::string& app_id() const { return app_id_; }
   const gfx::ImageSkia& image_skia() const { return image_skia_; }
-  Profile* profile() const { return profile_; }
 
   // Icon loading is performed in several steps. It is initiated by
   // LoadImageForScaleFactor request that specifies a required scale factor.
@@ -82,7 +85,7 @@
   // Removed the corresponding |request| from our list.
   void DiscardDecodeRequest(DecodeRequest* request);
 
-  Profile* profile_;
+  base::WeakPtr<crostini::CrostiniRegistryService> registry_service_;
   const std::string app_id_;
   const int resource_size_in_dip_;
   Observer* const observer_;
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index ae69f0c..e38e397 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -88,6 +88,7 @@
     case AutocompleteMatchType::PHYSICAL_WEB_DEPRECATED:
     case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW_DEPRECATED:
     case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
+    case AutocompleteMatchType::DOCUMENT_SUGGESTION:
       return kIcDomainIcon;
 
     case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index cf06d4c..d2ae235 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
 #include "chrome/common/url_constants.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
-#include "components/arc/intent_helper/page_transition_util.h"
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/sessions/core/tab_restore_service_observer.h"
 #include "components/url_formatter/url_fixer.h"
@@ -41,6 +40,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
 
 namespace {
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index fd8c967..f57c1ded 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -20,10 +20,6 @@
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/native_widget_types.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h"
-#endif  // OS_CHROMEOS
-
 class Browser;
 class LoginHandler;
 class Profile;
@@ -308,22 +304,6 @@
 
 }  // namespace chrome
 
-#if defined(OS_CHROMEOS)
-
-// TODO(djacobo): Find a better place for IntentPickerResponse.
-// This callback informs the launch name and type of the app selected by the
-// user, along with the reason why the Bubble was closed and whether the
-// decision should be persisted. When the reason is ERROR or DIALOG_DEACTIVATED,
-// the values of the launch name, app type, and persistence boolean are all
-// ignored.
-using IntentPickerResponse =
-    base::OnceCallback<void(const std::string&,
-                            chromeos::AppType,
-                            chromeos::IntentPickerCloseReason,
-                            bool should_persist)>;
-
-#endif  // OS_CHROMEOS
-
 void ShowFolderUploadConfirmationDialog(
     const base::FilePath& path,
     base::OnceCallback<void(const std::vector<ui::SelectedFileInfo>&)> callback,
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
index 0671ef55..5cb149c 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_action_button.mm
@@ -21,7 +21,6 @@
 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#include "chrome/browser/ui/toolbar/toolbar_action_button_state.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
@@ -415,17 +414,8 @@
   base::string16 tooltip = viewController_->GetTooltip(webContents);
   [self setToolTip:(tooltip.empty() ? nil : base::SysUTF16ToNSString(tooltip))];
 
-  // For now, on Cocoa, pretend that the button is always in the normal state.
-  // This only affects behavior when
-  // extensions::features::kRuntimeHostPermissions is enabled (which is
-  // currently off everywhere by default), and there's a good likelihood that
-  // MacViews for the toolbar (https://crbug.com/671916) may ship prior to this.
-  // Since it's a non-trivial amount of work to get this right in Cocoa, settle
-  // with this for now. (The only behavior difference is that the icon
-  // background won't darken on mouseover and click).
   gfx::Image image =
-      viewController_->GetIcon(webContents, gfx::Size([self frame].size),
-                               ToolbarActionButtonState::kNormal);
+      viewController_->GetIcon(webContents, gfx::Size([self frame].size));
 
   if (!image.IsEmpty())
     [self setImage:image.ToNSImage()];
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc
index 1555033..71359114 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.cc
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -82,13 +82,12 @@
 
 gfx::Image ExtensionActionViewController::GetIcon(
     content::WebContents* web_contents,
-    const gfx::Size& size,
-    ToolbarActionButtonState state) {
+    const gfx::Size& size) {
   if (!ExtensionIsValid())
     return gfx::Image();
 
   return gfx::Image(
-      gfx::ImageSkia(GetIconImageSource(web_contents, size, state), size));
+      gfx::ImageSkia(GetIconImageSource(web_contents, size), size));
 }
 
 base::string16 ExtensionActionViewController::GetActionName() const {
@@ -283,8 +282,7 @@
 ExtensionActionViewController::GetIconImageSourceForTesting(
     content::WebContents* web_contents,
     const gfx::Size& size) {
-  return GetIconImageSource(web_contents, size,
-                            ToolbarActionButtonState::kNormal);
+  return GetIconImageSource(web_contents, size);
 }
 
 ExtensionActionViewController*
@@ -371,8 +369,7 @@
 std::unique_ptr<IconWithBadgeImageSource>
 ExtensionActionViewController::GetIconImageSource(
     content::WebContents* web_contents,
-    const gfx::Size& size,
-    ToolbarActionButtonState state) {
+    const gfx::Size& size) {
   int tab_id = SessionTabHelper::IdForTab(web_contents).id();
   std::unique_ptr<IconWithBadgeImageSource> image_source(
       new IconWithBadgeImageSource(size));
@@ -400,7 +397,6 @@
       toolbar_actions_bar_ && toolbar_actions_bar_->in_overflow_mode();
 
   bool has_blocked_actions = HasBeenBlocked(web_contents);
-  image_source->set_state(state);
   image_source->set_paint_blocked_actions_decoration(has_blocked_actions);
   image_source->set_paint_page_action_decoration(
       !has_blocked_actions && is_overflow &&
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.h b/chrome/browser/ui/extensions/extension_action_view_controller.h
index eb929f3e1..cc2d81c 100644
--- a/chrome/browser/ui/extensions/extension_action_view_controller.h
+++ b/chrome/browser/ui/extensions/extension_action_view_controller.h
@@ -52,8 +52,7 @@
   std::string GetId() const override;
   void SetDelegate(ToolbarActionViewDelegate* delegate) override;
   gfx::Image GetIcon(content::WebContents* web_contents,
-                     const gfx::Size& size,
-                     ToolbarActionButtonState state) override;
+                     const gfx::Size& size) override;
   base::string16 GetActionName() const override;
   base::string16 GetAccessibleName(content::WebContents* web_contents) const
       override;
@@ -137,8 +136,7 @@
   // Returns the image source for the icon.
   std::unique_ptr<IconWithBadgeImageSource> GetIconImageSource(
       content::WebContents* web_contents,
-      const gfx::Size& size,
-      ToolbarActionButtonState state);
+      const gfx::Size& size);
 
   // Returns true if this extension has a page action and that page action wants
   // to run on the given |web_contents|.
diff --git a/chrome/browser/ui/extensions/icon_with_badge_image_source.cc b/chrome/browser/ui/extensions/icon_with_badge_image_source.cc
index e3011120..77c7327 100644
--- a/chrome/browser/ui/extensions/icon_with_badge_image_source.cc
+++ b/chrome/browser/ui/extensions/icon_with_badge_image_source.cc
@@ -14,13 +14,17 @@
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
 #include "chrome/grit/theme_resources.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_paint_util.h"
 
 namespace {
 
@@ -35,6 +39,16 @@
       target_scale);
 }
 
+float GetBlockedActionBadgeRadius() {
+#if defined(OS_MACOSX)
+  // Cocoa. Note: this doesn't look great on Cocoa. But runtime host
+  // permissions are expected to be launched after MacViews for top-chrome.
+  if (!base::FeatureList::IsEnabled(features::kViewsBrowserWindows))
+    return 11.4f;
+#endif
+  return 12.0f;
+}
+
 }  // namespace
 
 IconWithBadgeImageSource::Badge::Badge(const std::string& text,
@@ -193,26 +207,37 @@
 
 void IconWithBadgeImageSource::PaintBlockedActionDecoration(
     gfx::Canvas* canvas) {
-  SkColor fill_color;
-  switch (state_) {
-    case ToolbarActionButtonState::kNormal:
-      fill_color = SK_ColorWHITE;
-      break;
-    case ToolbarActionButtonState::kHovered:
-      fill_color = gfx::kGoogleGrey200;
-      break;
-    case ToolbarActionButtonState::kPressed:
-      fill_color = gfx::kGoogleGrey300;
-      break;
-  }
+  // To match the CSS notion of blur (spread outside the bounding box) to the
+  // Skia notion of blur (spread outside and inside the bounding box), we have
+  // to double the CSS-based blur values.
+  constexpr int kBlurCorrection = 2;
 
+  constexpr int kKeyShadowOpacity = 0x4D;  // 30%
+  const gfx::ShadowValue key_shadow(
+      gfx::Vector2d(0, 1), kBlurCorrection * 2 /*blur*/,
+      SkColorSetA(gfx::kGoogleGrey800, kKeyShadowOpacity));
+
+  constexpr int kAmbientShadowOpacity = 0x26;  // 15%
+  const gfx::ShadowValue ambient_shadow(
+      gfx::Vector2d(0, 2), kBlurCorrection * 6 /*blur*/,
+      SkColorSetA(gfx::kGoogleGrey800, kAmbientShadowOpacity));
+
+  const float blocked_action_badge_radius = GetBlockedActionBadgeRadius();
+
+  // Sanity checking.
   const gfx::Rect icon_rect = GetIconAreaRect();
+  DCHECK_LE(2 * blocked_action_badge_radius, icon_rect.width());
+  DCHECK_EQ(icon_rect.width(), icon_rect.height());
+
   cc::PaintFlags paint_flags;
   paint_flags.setStyle(cc::PaintFlags::kFill_Style);
   paint_flags.setAntiAlias(true);
-  paint_flags.setColor(fill_color);
-  canvas->DrawCircle(icon_rect.CenterPoint(), icon_rect.width() / 2,
-                     paint_flags);
+  paint_flags.setColor(SK_ColorWHITE);
+  paint_flags.setLooper(
+      gfx::CreateShadowDrawLooper({key_shadow, ambient_shadow}));
+
+  canvas->DrawCircle(gfx::PointF(icon_rect.CenterPoint()),
+                     blocked_action_badge_radius, paint_flags);
 }
 
 gfx::Rect IconWithBadgeImageSource::GetIconAreaRect() const {
diff --git a/chrome/browser/ui/extensions/icon_with_badge_image_source.h b/chrome/browser/ui/extensions/icon_with_badge_image_source.h
index 317dffc9..addf0c4 100644
--- a/chrome/browser/ui/extensions/icon_with_badge_image_source.h
+++ b/chrome/browser/ui/extensions/icon_with_badge_image_source.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "chrome/browser/ui/toolbar/toolbar_action_button_state.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/canvas_image_source.h"
@@ -48,7 +47,6 @@
   void set_paint_blocked_actions_decoration(bool should_paint) {
     paint_blocked_actions_decoration_ = should_paint;
   }
-  void set_state(ToolbarActionButtonState state) { state_ = state; }
   bool grayscale() const { return grayscale_; }
   bool paint_page_action_decoration() const {
     return paint_page_action_decoration_;
@@ -56,7 +54,6 @@
   bool paint_blocked_actions_decoration() const {
     return paint_blocked_actions_decoration_;
   }
-  ToolbarActionButtonState state() const { return state_; }
 
  private:
   // gfx::CanvasImageSource:
@@ -98,8 +95,6 @@
   // had actions blocked.
   bool paint_blocked_actions_decoration_ = false;
 
-  ToolbarActionButtonState state_ = ToolbarActionButtonState::kNormal;
-
   DISALLOW_COPY_AND_ASSIGN(IconWithBadgeImageSource);
 };
 
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc
index 311e950..d3b21dfe 100644
--- a/chrome/browser/ui/search/local_ntp_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -543,7 +543,10 @@
 class LocalNTPMDTest : public LocalNTPTest {
  public:
   LocalNTPMDTest()
-      : LocalNTPTest({features::kUseGoogleLocalNtp, features::kNtpUIMd}, {}) {}
+      : LocalNTPTest(
+            /*enabled_features=*/{features::kUseGoogleLocalNtp,
+                                  ntp_tiles::kNtpIcons},
+            /*disabled_features=*/{ntp_tiles::kNtpCustomLinks}) {}
 
  private:
   base::test::ScopedFeatureList feature_list_;
@@ -590,6 +593,37 @@
   EXPECT_EQ(0, failed_favicons);
 }
 
+class LocalNTPCustomLinksTest : public LocalNTPTest {
+ public:
+  LocalNTPCustomLinksTest()
+      : LocalNTPTest(
+            /*enabled_features=*/{features::kUseGoogleLocalNtp,
+                                  features::kNtpUIMd, ntp_tiles::kNtpIcons,
+                                  ntp_tiles::kNtpCustomLinks},
+            /*disabled_features=*/{}) {}
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(LocalNTPCustomLinksTest, ShowsAddCustomLinkButton) {
+  content::WebContents* active_tab =
+      local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+
+  // Get the iframe and check that the tiles loaded correctly.
+  content::RenderFrameHost* iframe = GetMostVisitedIframe(active_tab);
+
+  // Check if only one add button exists in the iframe.
+  bool has_add_button = false;
+  ASSERT_TRUE(instant_test_utils::GetBoolFromJS(
+      iframe, "document.querySelectorAll('.md-add-icon').length == 1",
+      &has_add_button));
+  EXPECT_TRUE(has_add_button);
+}
+
+// TODO(851293): Add test for not showing add button when at max links.
+
 // A minimal implementation of an interstitial page.
 class TestInterstitialPageDelegate : public content::InterstitialPageDelegate {
  public:
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc
index d9ec99c..65a5bf7 100644
--- a/chrome/browser/ui/search/search_ipc_router.cc
+++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -268,6 +268,18 @@
   delegate_->OnSetCustomBackgroundURL(url);
 }
 
+void SearchIPCRouter::SetCustomBackgroundURLWithAttributions(
+    const GURL& background_url,
+    const std::string& attribution_line_1,
+    const std::string& attribution_line_2,
+    const GURL& action_url) {
+  if (!policy_->ShouldProcessSetCustomBackgroundURLWithAttributions())
+    return;
+
+  delegate_->OnSetCustomBackgroundURLWithAttributions(
+      background_url, attribution_line_1, attribution_line_2, action_url);
+}
+
 void SearchIPCRouter::SelectLocalBackgroundImage() {
   if (!policy_->ShouldProcessSelectLocalBackgroundImage())
     return;
diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h
index 68ae6ca..4710767 100644
--- a/chrome/browser/ui/search/search_ipc_router.h
+++ b/chrome/browser/ui/search/search_ipc_router.h
@@ -83,6 +83,17 @@
     // Called when a custom background is selected on the NTP.
     virtual void OnSetCustomBackgroundURL(const GURL& url) = 0;
 
+    // Called when a custom background with attributions is selected on the NTP.
+    // background_url: Url of the background image.
+    // attribution_line_1: First attribution line for the image.
+    // attribution_line_2: Second attribution line for the image.
+    // action_url: Url to learn more about the backgrounds image.
+    virtual void OnSetCustomBackgroundURLWithAttributions(
+        const GURL& background_url,
+        const std::string& attribution_line_1,
+        const std::string& attribution_line_2,
+        const GURL& action_url) = 0;
+
     // Called to open the file select dialog for selecting a
     // NTP background image.
     virtual void OnSelectLocalBackgroundImage() = 0;
@@ -110,6 +121,7 @@
     virtual bool ShouldSendMostVisitedItems() = 0;
     virtual bool ShouldSendThemeBackgroundInfo() = 0;
     virtual bool ShouldProcessSetCustomBackgroundURL() = 0;
+    virtual bool ShouldProcessSetCustomBackgroundURLWithAttributions() = 0;
     virtual bool ShouldProcessSelectLocalBackgroundImage() = 0;
   };
 
@@ -175,6 +187,11 @@
   void HistorySyncCheck(int page_seq_no,
                         HistorySyncCheckCallback callback) override;
   void SetCustomBackgroundURL(const GURL& url) override;
+  void SetCustomBackgroundURLWithAttributions(
+      const GURL& background_url,
+      const std::string& attribution_line_1,
+      const std::string& attribution_line_2,
+      const GURL& action_url) override;
   void SelectLocalBackgroundImage() override;
   void set_embedded_search_client_factory_for_testing(
       std::unique_ptr<EmbeddedSearchClientFactory> factory) {
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
index 7283c9a1..85420abe9 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
+++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.cc
@@ -79,3 +79,8 @@
 bool SearchIPCRouterPolicyImpl::ShouldProcessSetCustomBackgroundURL() {
   return !is_incognito_ && search::IsInstantNTP(web_contents_);
 }
+
+bool SearchIPCRouterPolicyImpl::
+    ShouldProcessSetCustomBackgroundURLWithAttributions() {
+  return !is_incognito_ && search::IsInstantNTP(web_contents_);
+}
diff --git a/chrome/browser/ui/search/search_ipc_router_policy_impl.h b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
index 9d2bff6..1564e3d0 100644
--- a/chrome/browser/ui/search/search_ipc_router_policy_impl.h
+++ b/chrome/browser/ui/search/search_ipc_router_policy_impl.h
@@ -40,6 +40,7 @@
   bool ShouldSendMostVisitedItems() override;
   bool ShouldSendThemeBackgroundInfo() override;
   bool ShouldProcessSetCustomBackgroundURL() override;
+  bool ShouldProcessSetCustomBackgroundURLWithAttributions() override;
   bool ShouldProcessSelectLocalBackgroundImage() override;
 
   // Used by unit tests.
diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc
index aba27c7..f2a0804 100644
--- a/chrome/browser/ui/search/search_ipc_router_unittest.cc
+++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc
@@ -70,6 +70,11 @@
   MOCK_METHOD1(ChromeIdentityCheck, bool(const base::string16& identity));
   MOCK_METHOD0(HistorySyncCheck, bool());
   MOCK_METHOD1(OnSetCustomBackgroundURL, void(const GURL& url));
+  MOCK_METHOD4(OnSetCustomBackgroundURLWithAttributions,
+               void(const GURL& background_url,
+                    const std::string& attribution1,
+                    const std::string& attribution2,
+                    const GURL& attributionActionUrl));
   MOCK_METHOD0(OnSelectLocalBackgroundImage, void());
 };
 
@@ -86,6 +91,7 @@
   MOCK_METHOD0(ShouldProcessChromeIdentityCheck, bool());
   MOCK_METHOD0(ShouldProcessHistorySyncCheck, bool());
   MOCK_METHOD0(ShouldProcessSetCustomBackgroundURL, bool());
+  MOCK_METHOD0(ShouldProcessSetCustomBackgroundURLWithAttributions, bool());
   MOCK_METHOD0(ShouldProcessSelectLocalBackgroundImage, bool());
   MOCK_METHOD1(ShouldSendSetInputInProgress, bool(bool));
   MOCK_METHOD0(ShouldSendOmniboxFocusChanged, bool());
@@ -615,6 +621,44 @@
   GetSearchIPCRouter().SetCustomBackgroundURL(bg_url);
 }
 
+TEST_F(SearchIPCRouterTest, ProcessSetCustomBackgroundURLWithAttributionsMsg) {
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  SetupMockDelegateAndPolicy();
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy();
+  GURL bg_url("www.foo.com");
+  std::string attr1("foo");
+  std::string attr2("bar");
+  GURL action_url("www.bar.com");
+  EXPECT_CALL(*mock_delegate(), OnSetCustomBackgroundURLWithAttributions(
+                                    bg_url, attr1, attr2, action_url))
+      .Times(1);
+  EXPECT_CALL(*policy, ShouldProcessSetCustomBackgroundURLWithAttributions())
+      .Times(1)
+      .WillOnce(Return(true));
+
+  GetSearchIPCRouter().SetCustomBackgroundURLWithAttributions(
+      bg_url, attr1, attr2, action_url);
+}
+
+TEST_F(SearchIPCRouterTest, IgnoreSetCustomBackgroundURLWithAttributionsMsg) {
+  NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
+  SetupMockDelegateAndPolicy();
+  MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy();
+  GURL bg_url("www.foo.com");
+  std::string attr1("foo");
+  std::string attr2("bar");
+  GURL action_url("www.bar.com");
+  EXPECT_CALL(*mock_delegate(), OnSetCustomBackgroundURLWithAttributions(
+                                    bg_url, attr1, attr2, action_url))
+      .Times(0);
+  EXPECT_CALL(*policy, ShouldProcessSetCustomBackgroundURLWithAttributions())
+      .Times(1)
+      .WillOnce(Return(false));
+
+  GetSearchIPCRouter().SetCustomBackgroundURLWithAttributions(
+      bg_url, attr1, attr2, action_url);
+}
+
 TEST_F(SearchIPCRouterTest, ProcessSelectLocalBackgroundImageMsg) {
   NavigateAndCommitActiveTab(GURL("chrome-search://foo/bar"));
   SetupMockDelegateAndPolicy();
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc
index 9bcae451..febd7265 100644
--- a/chrome/browser/ui/search/search_tab_helper.cc
+++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -359,6 +359,17 @@
     instant_service_->SetCustomBackgroundURL(url);
 }
 
+void SearchTabHelper::OnSetCustomBackgroundURLWithAttributions(
+    const GURL& background_url,
+    const std::string& attribution_line_1,
+    const std::string& attribution_line_2,
+    const GURL& action_url) {
+  if (instant_service_) {
+    instant_service_->SetCustomBackgroundURLWithAttributions(
+        background_url, attribution_line_1, attribution_line_2, action_url);
+  }
+}
+
 void SearchTabHelper::FileSelected(const base::FilePath& path,
                                    int index,
                                    void* params) {
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h
index 4d52218..e73064f 100644
--- a/chrome/browser/ui/search/search_tab_helper.h
+++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -107,6 +107,11 @@
   bool ChromeIdentityCheck(const base::string16& identity) override;
   bool HistorySyncCheck() override;
   void OnSetCustomBackgroundURL(const GURL& url) override;
+  void OnSetCustomBackgroundURLWithAttributions(
+      const GURL& background_url,
+      const std::string& attribution_line_1,
+      const std::string& attribution_line_2,
+      const GURL& action_url) override;
   void OnSelectLocalBackgroundImage() override;
 
   // Overridden from InstantServiceObserver:
diff --git a/chrome/browser/ui/search/search_tab_helper_unittest.cc b/chrome/browser/ui/search/search_tab_helper_unittest.cc
index 407fec9a..7b5d3aa 100644
--- a/chrome/browser/ui/search/search_tab_helper_unittest.cc
+++ b/chrome/browser/ui/search/search_tab_helper_unittest.cc
@@ -69,6 +69,11 @@
   MOCK_METHOD1(ChromeIdentityCheck, bool(const base::string16& identity));
   MOCK_METHOD0(HistorySyncCheck, bool());
   MOCK_METHOD1(OnSetCustomBackgroundURL, void(const GURL& url));
+  MOCK_METHOD4(OnSetCustomBackgroundURLWithAttributions,
+               void(const GURL& background_url,
+                    const std::string& attribution_line_1,
+                    const std::string& attribution_line_2,
+                    const GURL& action_url));
   MOCK_METHOD0(OnSelectLocalBackgroundImage, void());
 };
 
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
index 28b2981..5fceed84 100644
--- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
+++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -649,8 +649,7 @@
   ASSERT_EQ(1u, actions.size());
   gfx::Image icon = actions[0]->GetIcon(
       second_browser->tab_strip_model()->GetActiveWebContents(),
-      second_browser->window()->GetToolbarActionsBar()->GetViewSize(),
-      ToolbarActionButtonState::kNormal);
+      second_browser->window()->GetToolbarActionsBar()->GetViewSize());
   const gfx::ImageSkia* skia = icon.ToImageSkia();
   ASSERT_TRUE(skia);
   // Force the image to try and load a representation.
diff --git a/chrome/browser/ui/toolbar/media_router_action.cc b/chrome/browser/ui/toolbar/media_router_action.cc
index b3e02bbc..fe1db71 100644
--- a/chrome/browser/ui/toolbar/media_router_action.cc
+++ b/chrome/browser/ui/toolbar/media_router_action.cc
@@ -96,8 +96,7 @@
 }
 
 gfx::Image MediaRouterAction::GetIcon(content::WebContents* web_contents,
-                                      const gfx::Size& size,
-                                      ToolbarActionButtonState state) {
+                                      const gfx::Size& size) {
   return gfx::Image(
       gfx::CreateVectorIcon(*current_icon_, GetIconColor(*current_icon_)));
 }
diff --git a/chrome/browser/ui/toolbar/media_router_action.h b/chrome/browser/ui/toolbar/media_router_action.h
index 3cddec5..e94d5734 100644
--- a/chrome/browser/ui/toolbar/media_router_action.h
+++ b/chrome/browser/ui/toolbar/media_router_action.h
@@ -48,8 +48,7 @@
   std::string GetId() const override;
   void SetDelegate(ToolbarActionViewDelegate* delegate) override;
   gfx::Image GetIcon(content::WebContents* web_contents,
-                     const gfx::Size& size,
-                     ToolbarActionButtonState state) override;
+                     const gfx::Size& size) override;
   base::string16 GetActionName() const override;
   base::string16 GetAccessibleName(content::WebContents* web_contents)
       const override;
diff --git a/chrome/browser/ui/toolbar/media_router_action_unittest.cc b/chrome/browser/ui/toolbar/media_router_action_unittest.cc
index 298e92d..e4ae353 100644
--- a/chrome/browser/ui/toolbar/media_router_action_unittest.cc
+++ b/chrome/browser/ui/toolbar/media_router_action_unittest.cc
@@ -29,8 +29,7 @@
 namespace {
 
 gfx::Image GetActionIcon(ToolbarActionViewController* action) {
-  constexpr auto kTestButtonState = ToolbarActionButtonState::kNormal;
-  return action->GetIcon(nullptr, gfx::Size(), kTestButtonState);
+  return action->GetIcon(nullptr, gfx::Size());
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc
index 75ec8c2..dd4839f 100644
--- a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc
+++ b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.cc
@@ -36,8 +36,7 @@
 
 gfx::Image TestToolbarActionViewController::GetIcon(
     content::WebContents* web_contents,
-    const gfx::Size& size,
-    ToolbarActionButtonState state) {
+    const gfx::Size& size) {
   return gfx::Image();
 }
 
diff --git a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h
index f63d3e9..abb6d1c 100644
--- a/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h
+++ b/chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h
@@ -19,8 +19,7 @@
   std::string GetId() const override;
   void SetDelegate(ToolbarActionViewDelegate* delegate) override;
   gfx::Image GetIcon(content::WebContents* web_contents,
-                     const gfx::Size& size,
-                     ToolbarActionButtonState state) override;
+                     const gfx::Size& size) override;
   base::string16 GetActionName() const override;
   base::string16 GetAccessibleName(content::WebContents* web_contents)
       const override;
diff --git a/chrome/browser/ui/toolbar/toolbar_action_button_state.h b/chrome/browser/ui/toolbar/toolbar_action_button_state.h
deleted file mode 100644
index 82ae203e..0000000
--- a/chrome/browser/ui/toolbar/toolbar_action_button_state.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_BUTTON_STATE_H_
-#define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_BUTTON_STATE_H_
-
-// The state of the toolbar action button; used when generating an icon depends
-// on the state. We don't use views::Button::State to avoid a hard dependency
-// ui/views code from this code, since it's shared with Cocoa.
-enum class ToolbarActionButtonState {
-  kNormal,
-  kHovered,
-  kPressed,
-};
-
-#endif  // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_BUTTON_STATE_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
index 95f0225..ddbb797 100644
--- a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
+++ b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_ACTION_VIEW_CONTROLLER_H_
 
 #include "base/strings/string16.h"
-#include "chrome/browser/ui/toolbar/toolbar_action_button_state.h"
 #include "ui/gfx/image/image.h"
 
 namespace content {
@@ -39,8 +38,7 @@
 
   // Returns the icon to use for the given |web_contents| and |size|.
   virtual gfx::Image GetIcon(content::WebContents* web_contents,
-                             const gfx::Size& size,
-                             ToolbarActionButtonState state) = 0;
+                             const gfx::Size& size) = 0;
 
   // Returns the name of the action, which can be separate from the accessible
   // name or name for the tooltip.
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
index e4a4e640..0461b7fd 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -28,6 +28,7 @@
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
+#include "ui/views/bubble/bubble_border.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/bubble/tooltip_icon.h"
 #include "ui/views/controls/button/blue_button.h"
@@ -50,11 +51,7 @@
 
 const int kGooglePayLogoSeparatorHeight = 12;
 
-// Using custom padding instead of reusing left/right padding from
-// INSETS_DIALOG_TITLE, because it gives too much spacing when there is a
-// separator line between the icon and the title.
-// TODO(ftirelo): This padding should come from the layout provider.
-const int kTitleSeparatorPadding = 8;
+const int kTooltipIconSize = 12;
 
 const SkColor kTitleSeparatorColor = SkColorSetRGB(0x9E, 0x9E, 0x9E);
 
@@ -188,10 +185,15 @@
   // is added to the widget, so the bubble frame view is guaranteed to exist.
   if (GetCurrentFlowStep() != UPLOAD_SAVE_ONLY_STEP)
     return;
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
 
   auto title_container = std::make_unique<views::View>();
+  // TODO(ftirelo): DISTANCE_RELATED_BUTTON_HORIZONTAL isn't the right choice
+  //                here, but INSETS_DIALOG_TITLE gives too much padding.
+  //                Make a new Harmony DistanceMetric?
   title_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::kHorizontal, gfx::Insets(), kTitleSeparatorPadding));
+      views::BoxLayout::kHorizontal, gfx::Insets(),
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));
 
   // kGooglePayLogoIcon is square, and CreateTiledImage() will clip it whereas
   // setting the icon size would rescale it incorrectly.
@@ -348,11 +350,14 @@
         std::make_unique<views::View>();
 
     // Set up cardholder name label.
+    // TODO(jsaul): DISTANCE_RELATED_BUTTON_HORIZONTAL isn't the right choice
+    //              here, but DISTANCE_RELATED_CONTROL_HORIZONTAL gives too much
+    //              padding. Make a new Harmony DistanceMetric?
     cardholder_name_label_row->SetLayoutManager(
         std::make_unique<views::BoxLayout>(
             views::BoxLayout::kHorizontal, gfx::Insets(),
             provider->GetDistanceMetric(
-                views::DISTANCE_RELATED_CONTROL_HORIZONTAL)));
+                views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));
     std::unique_ptr<views::Label> cardholder_name_label =
         std::make_unique<views::Label>(
             l10n_util::GetStringUTF16(
@@ -372,8 +377,12 @@
     // textfield will be prefilled.
     if (!prefilled_name.empty()) {
       std::unique_ptr<views::TooltipIcon> cardholder_name_tooltip =
-          std::make_unique<views::TooltipIcon>(l10n_util::GetStringUTF16(
-              IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP));
+          std::make_unique<views::TooltipIcon>(
+              l10n_util::GetStringUTF16(
+                  IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP),
+              kTooltipIconSize);
+      cardholder_name_tooltip->set_anchor_point_arrow(
+          views::BubbleBorder::Arrow::TOP_LEFT);
       cardholder_name_tooltip->set_id(DialogViewId::CARDHOLDER_NAME_TOOLTIP);
       cardholder_name_label_row->AddChildView(
           cardholder_name_tooltip.release());
diff --git a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
index 5370cf4..26b5914 100644
--- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
+++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -65,8 +65,6 @@
                            const gfx::Size& max_size);
   ~ConstrainedDialogWebView() override;
 
-  void SetAutoResizeSize(const gfx::Size& auto_resize_size);
-
   // ConstrainedWebDialogDelegate:
   const ui::WebDialogDelegate* GetWebDialogDelegate() const override;
   ui::WebDialogDelegate* GetWebDialogDelegate() override;
@@ -95,27 +93,13 @@
   gfx::Size CalculatePreferredSize() const override;
   gfx::Size GetMinimumSize() const override;
   gfx::Size GetMaximumSize() const override;
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
-  void RenderViewHostChanged(content::RenderViewHost* old_host,
-                             content::RenderViewHost* new_host) override;
   void DocumentOnLoadCompletedInMainFrame() override;
 
  private:
-  void EnableAutoResize();
-
   InitiatorWebContentsObserver initiator_observer_;
 
   std::unique_ptr<ConstrainedWebDialogDelegateViews> impl_;
 
-  // Minimum and maximum sizes to determine dialog bounds for auto-resizing.
-  const gfx::Size min_size_;
-  const gfx::Size max_size_;
-
-  // The self-reported desired size of the WebContents. Empty if auto resize is
-  // not enabled. This will be passed to and possibly adjusted by the
-  // WebDialogDelegate in order to calculate the preferred size of the dialog.
-  gfx::Size auto_resize_size_;
-
   DISALLOW_COPY_AND_ASSIGN(ConstrainedDialogWebView);
 };
 
@@ -157,7 +141,11 @@
     if (!initiator_observer_->web_contents())
       return;
 
-    web_view_->SetAutoResizeSize(new_size);
+    // views::WebView is only a delegate for a WebContents it creates itself via
+    // views::WebView::GetWebContents(). ConstrainedDialogWebView's constructor
+    // sets its own WebContents (via an override of WebView::GetWebContents()).
+    // So forward this notification to views::WebView.
+    web_view_->ResizeDueToAutoResize(source, new_size);
 
     content::WebContents* top_level_web_contents =
         constrained_window::GetTopLevelWebContents(
@@ -234,22 +222,16 @@
       impl_(new ConstrainedWebDialogDelegateViews(browser_context,
                                                   delegate,
                                                   &initiator_observer_,
-                                                  this)),
-      min_size_(RestrictToPlatformMinimumSize(min_size)),
-      max_size_(max_size) {
+                                                  this)) {
   SetWebContents(GetWebContents());
   AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
-  if (!max_size_.IsEmpty())
-    EnableAutoResize();
+  if (!max_size.IsEmpty()) {
+    EnableSizingFromWebContents(RestrictToPlatformMinimumSize(min_size),
+                                max_size);
+  }
 }
 ConstrainedDialogWebView::~ConstrainedDialogWebView() {}
 
-void ConstrainedDialogWebView::SetAutoResizeSize(
-    const gfx::Size& default_size) {
-  auto_resize_size_ = default_size;
-  PreferredSizeChanged();
-}
-
 const ui::WebDialogDelegate* ConstrainedDialogWebView::GetWebDialogDelegate()
     const {
   return impl_->GetWebDialogDelegate();
@@ -342,37 +324,23 @@
     return gfx::Size();
 
   // If auto-resizing is enabled and the dialog has been auto-resized,
-  // |auto_resize_size_| will hold the appropriate current size.  In this
-  // case, GetDialogSize() should leave its argument untouched.  In all
-  // other cases, GetDialogSize() will overwrite the passed-in size.
-  gfx::Size size = auto_resize_size_;
+  // View::GetPreferredSize() won't try to calculate the size again, since a
+  // preferred size has been set explicitly from the renderer.
+  gfx::Size size = WebView::CalculatePreferredSize();
   GetWebDialogDelegate()->GetDialogSize(&size);
   return size;
 }
 
 gfx::Size ConstrainedDialogWebView::GetMinimumSize() const {
-  return min_size_;
+  return min_size();
 }
 
 gfx::Size ConstrainedDialogWebView::GetMaximumSize() const {
-  return !max_size_.IsEmpty() ? max_size_ : WebView::GetMaximumSize();
-}
-
-void ConstrainedDialogWebView::RenderViewCreated(
-    content::RenderViewHost* render_view_host) {
-  if (!max_size_.IsEmpty())
-    EnableAutoResize();
-}
-
-void ConstrainedDialogWebView::RenderViewHostChanged(
-    content::RenderViewHost* old_host,
-    content::RenderViewHost* new_host) {
-  if (!max_size_.IsEmpty())
-    EnableAutoResize();
+  return !max_size().IsEmpty() ? max_size() : WebView::GetMaximumSize();
 }
 
 void ConstrainedDialogWebView::DocumentOnLoadCompletedInMainFrame() {
-  if (!max_size_.IsEmpty() && initiator_observer_.web_contents()) {
+  if (!max_size().IsEmpty() && initiator_observer_.web_contents()) {
     content::WebContents* top_level_web_contents =
         constrained_window::GetTopLevelWebContents(
             initiator_observer_.web_contents());
@@ -383,12 +351,6 @@
   }
 }
 
-void ConstrainedDialogWebView::EnableAutoResize() {
-  content::RenderWidgetHostView* render_widget_host_view =
-      GetWebContents()->GetRenderWidgetHostView();
-  render_widget_host_view->EnableAutoResize(min_size_, max_size_);
-}
-
 }  // namespace
 
 ConstrainedWebDialogDelegate* ShowConstrainedWebDialog(
diff --git a/chrome/browser/ui/views/extensions/extension_view_views.cc b/chrome/browser/ui/views/extensions/extension_view_views.cc
index c78743f..44c79d75 100644
--- a/chrome/browser/ui/views/extensions/extension_view_views.cc
+++ b/chrome/browser/ui/views/extensions/extension_view_views.cc
@@ -36,6 +36,11 @@
       browser_(browser),
       container_(nullptr) {
   SetWebContents(host_->web_contents());
+  if (host->extension_host_type() == extensions::VIEW_TYPE_EXTENSION_POPUP) {
+    EnableSizingFromWebContents(
+        gfx::Size(ExtensionPopup::kMinWidth, ExtensionPopup::kMinHeight),
+        gfx::Size(ExtensionPopup::kMaxWidth, ExtensionPopup::kMaxHeight));
+  }
 }
 
 ExtensionViewViews::~ExtensionViewViews() {
@@ -80,18 +85,12 @@
     return;
   }
 
-  if (new_size != GetPreferredSize())
-    SetPreferredSize(new_size);
+  WebView::ResizeDueToAutoResize(web_contents, new_size);
 }
 
 void ExtensionViewViews::RenderViewCreated(
     content::RenderViewHost* render_view_host) {
-  extensions::ViewType host_type = host_->extension_host_type();
-  if (host_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
-    host_->host_contents()->GetRenderWidgetHostView()->EnableAutoResize(
-        gfx::Size(ExtensionPopup::kMinWidth, ExtensionPopup::kMinHeight),
-        gfx::Size(ExtensionPopup::kMaxWidth, ExtensionPopup::kMaxHeight));
-  }
+  WebView::RenderViewCreated(render_view_host);
 }
 
 void ExtensionViewViews::HandleKeyboardEvent(
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index 6742815..b0310758 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -57,6 +57,10 @@
   return false;
 }
 
+int ExternalProtocolDialog::GetDefaultDialogButton() const {
+  return ui::DIALOG_BUTTON_CANCEL;
+}
+
 base::string16 ExternalProtocolDialog::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return delegate_->GetDialogButtonLabel(button);
diff --git a/chrome/browser/ui/views/external_protocol_dialog.h b/chrome/browser/ui/views/external_protocol_dialog.h
index 4cdc1b5..7eba7230 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.h
+++ b/chrome/browser/ui/views/external_protocol_dialog.h
@@ -32,6 +32,7 @@
   // views::DialogDelegateView:
   gfx::Size CalculatePreferredSize() const override;
   bool ShouldShowCloseButton() const override;
+  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   base::string16 GetWindowTitle() const override;
   bool Cancel() override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index ec738c3..6c04da2 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -98,6 +98,10 @@
   return frame()->IsFullscreen();
 }
 
+bool BrowserNonClientFrameView::HasClientEdge() const {
+  return !MD::IsRefreshUi();
+}
+
 gfx::ImageSkia BrowserNonClientFrameView::GetIncognitoAvatarIcon() const {
   const SkColor icon_color = color_utils::PickContrastingColor(
       SK_ColorWHITE, gfx::kChromeIconGrey, GetFrameColor());
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 99ec235..42f0ae5 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -75,6 +75,9 @@
   // Returns whether the top UI should hide.
   virtual bool ShouldHideTopUIForFullscreen() const;
 
+  // Returns whether the content is painted with a client edge or not.
+  virtual bool HasClientEdge() const;
+
   // Retrieves the icon to use in the frame to indicate an incognito window.
   gfx::ImageSkia GetIncognitoAvatarIcon() const;
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 1cd7e04..9d34c20 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -500,7 +500,8 @@
   if (toolbar_bounds.IsEmpty())
     return toolbar_bounds;
   // The apparent toolbar edges are outside the "real" toolbar edges.
-  toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0);
+  if (HasClientEdge())
+    toolbar_bounds.Inset(-views::NonClientFrameView::kClientEdgeThickness, 0);
   return toolbar_bounds;
 }
 
@@ -555,12 +556,7 @@
 }
 
 bool BrowserView::HasClientEdge() const {
-#if defined(OS_WIN)
-  return base::win::GetVersion() < base::win::VERSION_WIN10 ||
-         !frame_->ShouldUseNativeFrame();
-#else
-  return true;
-#endif
+  return frame()->GetFrameView()->HasClientEdge();
 }
 
 bool BrowserView::GetAccelerator(int cmd_id,
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 8765619..49ad2216 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -166,6 +166,12 @@
   return 0;
 }
 
+bool GlassBrowserFrameView::HasClientEdge() const {
+  // Native Windows 10 should never paint a client edge.
+  return base::win::GetVersion() < base::win::VERSION_WIN10 &&
+         BrowserNonClientFrameView::HasClientEdge();
+}
+
 void GlassBrowserFrameView::UpdateThrobber(bool running) {
   if (ShowCustomIcon())
     window_icon_->Update();
@@ -502,7 +508,7 @@
 
 int GlassBrowserFrameView::ClientBorderThickness(bool restored) const {
   // The frame ends abruptly at the 1 pixel window border drawn by Windows 10.
-  if (!browser_view()->HasClientEdge())
+  if (!HasClientEdge())
     return 0;
 
   if ((IsMaximized() || frame()->IsFullscreen()) && !restored)
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index 3f873730..1ed7fe6 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -38,6 +38,7 @@
   gfx::Rect GetBoundsForTabStrip(views::View* tabstrip) const override;
   int GetTopInset(bool restored) const override;
   int GetThemeBackgroundXInset() const override;
+  bool HasClientEdge() const override;
   void UpdateThrobber(bool running) override;
   gfx::Size GetMinimumSize() const override;
   int GetTabStripLeftInset() const override;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 1d7acf9..d1178e1d 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -421,6 +421,10 @@
   return browser_view()->IsTabStripVisible();
 }
 
+bool OpaqueBrowserFrameView::HasClientEdge() const {
+  return layout_->HasClientEdge();
+}
+
 bool OpaqueBrowserFrameView::IsToolbarVisible() const {
   return browser_view()->IsToolbarVisible() &&
       !browser_view()->toolbar()->GetPreferredSize().IsEmpty();
@@ -599,7 +603,9 @@
   const int w = client_bounds.width();
   // If the toolbar isn't going to draw a top edge for us, draw one ourselves.
   if (!tabstrip_visible) {
-    client_bounds.Inset(-kClientEdgeThickness, -1, -kClientEdgeThickness,
+    const int edge_thickness =
+        browser_view()->HasClientEdge() ? kClientEdgeThickness : 0;
+    client_bounds.Inset(-edge_thickness, -1, -edge_thickness,
                         client_bounds.height());
     BrowserView::Paint1pxHorizontalLine(canvas, GetToolbarTopSeparatorColor(),
                                         client_bounds, true);
@@ -625,24 +631,26 @@
         ThemeProperties::COLOR_TOOLBAR, incognito);
   }
 
-  // Draw the client edges.
-  const gfx::ImageSkia* const right_image =
-      tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
-  const int img_w = right_image->width();
-  const int right = client_bounds.right();
-  const int bottom = std::max(y, height() - NonClientBorderThickness());
-  const int height = bottom - y;
-  canvas->TileImageInt(*right_image, right, y, img_w, height);
-  canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER),
-                       right, bottom);
-  const gfx::ImageSkia* const bottom_image =
-      tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
-  canvas->TileImageInt(*bottom_image, x, bottom, w, bottom_image->height());
-  canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER),
-                       x - img_w, bottom);
-  canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE), x - img_w,
-                       y, img_w, height);
-  FillClientEdgeRects(x, y, w, height, true, toolbar_color, canvas);
+  if (browser_view()->HasClientEdge()) {
+    // Draw the client edges.
+    const gfx::ImageSkia* const right_image =
+        tp->GetImageSkiaNamed(IDR_CONTENT_RIGHT_SIDE);
+    const int img_w = right_image->width();
+    const int right = client_bounds.right();
+    const int bottom = std::max(y, height() - NonClientBorderThickness());
+    const int height = bottom - y;
+    canvas->TileImageInt(*right_image, right, y, img_w, height);
+    canvas->DrawImageInt(
+        *tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER), right, bottom);
+    const gfx::ImageSkia* const bottom_image =
+        tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_CENTER);
+    canvas->TileImageInt(*bottom_image, x, bottom, w, bottom_image->height());
+    canvas->DrawImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER),
+                         x - img_w, bottom);
+    canvas->TileImageInt(*tp->GetImageSkiaNamed(IDR_CONTENT_LEFT_SIDE),
+                         x - img_w, y, img_w, height);
+    FillClientEdgeRects(x, y, w, height, true, toolbar_color, canvas);
+  }
 
   // For popup windows, draw location bar sides.
   SkColor location_bar_border_color =
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
index 43ad897..4c7c92dd 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -68,6 +68,7 @@
   void UpdateWindowTitle() override;
   void SizeConstraintsChanged() override;
   void ActivationChanged(bool active) override;
+  bool HasClientEdge() const override;
 
   // views::View:
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index 3a33d34..02b16b91 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -152,11 +152,17 @@
   return thickness;
 }
 
+bool OpaqueBrowserFrameViewLayout::HasClientEdge() const {
+  return !MD::IsRefreshUi();
+}
+
 int OpaqueBrowserFrameViewLayout::NonClientBorderThickness() const {
   const int frame = FrameBorderThickness(false);
   // When we fill the screen, we don't show a client edge.
-  return (IsTitleBarCondensed() || delegate_->IsFullscreen()) ?
-      frame : (frame + views::NonClientFrameView::kClientEdgeThickness);
+  return (!HasClientEdge() || IsTitleBarCondensed() ||
+          delegate_->IsFullscreen())
+             ? frame
+             : (frame + views::NonClientFrameView::kClientEdgeThickness);
 }
 
 int OpaqueBrowserFrameViewLayout::NonClientTopHeight(bool restored) const {
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
index c73dbf0f..f974180 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
@@ -144,6 +144,8 @@
   // is dependent on whether in material refresh mode or not.
   static int GetNonClientRestoredExtraThickness();
 
+  bool HasClientEdge() const;
+
  protected:
   // Whether a specific button should be inserted on the leading or trailing
   // side.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
index 0007d476..c9b11ac 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
@@ -21,12 +21,11 @@
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/label.h"
 
+using MD = ui::MaterialDesignController;
+
 namespace {
 
 const int kWindowWidth = 500;
-const int kNonClientBorderThickness =
-    OpaqueBrowserFrameViewLayout::kFrameBorderThickness +
-    views::NonClientFrameView::kClientEdgeThickness;
 const int kMinimizeButtonWidth = 26;
 const int kMaximizeButtonWidth = 25;
 const int kCloseButtonWidth = 43;
@@ -37,6 +36,12 @@
     kMinimizeButtonWidth + kMaximizeButtonWidth + kCloseButtonWidth;
 const int kCaptionButtonHeight = 18;
 
+int NonClientBorderThickness() {
+  return OpaqueBrowserFrameViewLayout::kFrameBorderThickness +
+         (MD::IsRefreshUi() ? 0
+                            : views::NonClientFrameView::kClientEdgeThickness);
+}
+
 class TestLayoutDelegate : public OpaqueBrowserFrameViewLayoutDelegate {
  public:
   TestLayoutDelegate() : show_caption_buttons_(true), maximized_(false) {}
@@ -239,7 +244,6 @@
   }
 
   void ExpectTabStripAndMinimumSize(bool caption_buttons_on_left) {
-    using MD = ui::MaterialDesignController;
     int caption_buttons_width = kCaptionButtonsWidth;
     bool show_caption_buttons = delegate_->ShouldShowCaptionButtons();
     bool maximized = delegate_->IsMaximized() || !show_caption_buttons;
@@ -256,7 +260,7 @@
                     : OpaqueBrowserFrameViewLayout::kFrameBorderThickness;
       tabstrip_x += caption_buttons_width + right_of_close;
     } else if (!maximized) {
-      tabstrip_x += kNonClientBorderThickness;
+      tabstrip_x += NonClientBorderThickness();
     }
     gfx::Size tabstrip_min_size(delegate_->GetTabstripPreferredSize());
     gfx::Rect tabstrip_bounds(
@@ -282,7 +286,7 @@
         showing_caption_buttons_on_right ? kMaximizedExtraCloseWidth : 0;
     int restored_spacing =
         (caption_buttons_on_left
-             ? kNonClientBorderThickness
+             ? NonClientBorderThickness()
              : OpaqueBrowserFrameViewLayout::kFrameBorderThickness);
     if (!MD::IsRefreshUi()) {
       maximized_spacing +=
@@ -297,7 +301,7 @@
     EXPECT_EQ(tabstrip_width, tabstrip_bounds.width());
     EXPECT_EQ(tabstrip_min_size.height(), tabstrip_bounds.height());
     maximized_spacing = 0;
-    restored_spacing = 2 * kNonClientBorderThickness;
+    restored_spacing = 2 * NonClientBorderThickness();
     if (!MD::IsRefreshUi()) {
       maximized_spacing +=
           showing_caption_buttons_on_right
@@ -313,7 +317,7 @@
     EXPECT_EQ(min_width, min_size.width());
     int restored_border_height =
         OpaqueBrowserFrameViewLayout::kFrameBorderThickness +
-        kNonClientBorderThickness;
+        NonClientBorderThickness();
     if (MD::IsRefreshUi()) {
       restored_border_height +=
           OpaqueBrowserFrameViewLayout::kRefreshNonClientExtraTopThickness;
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc
index 6b69c142..2dda35c 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -127,7 +127,7 @@
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   if (!browser || !BrowserView::GetBrowserViewForBrowser(browser)) {
     std::move(intent_picker_cb)
-        .Run(kInvalidLaunchName, chromeos::AppType::INVALID,
+        .Run(kInvalidLaunchName, apps::mojom::AppType::kUnknown,
              chromeos::IntentPickerCloseReason::ERROR, false);
     return nullptr;
   }
@@ -207,7 +207,7 @@
 
 bool IntentPickerBubbleView::Cancel() {
   RunCallback(arc::ArcIntentHelperBridge::kArcIntentHelperPackageName,
-              chromeos::AppType::INVALID,
+              apps::mojom::AppType::kUnknown,
               chromeos::IntentPickerCloseReason::STAY_IN_CHROME,
               remember_selection_checkbox_->checked());
   return true;
@@ -216,7 +216,7 @@
 bool IntentPickerBubbleView::Close() {
   // Whenever closing the bubble without pressing |Just once| or |Always| we
   // need to report back that the user didn't select anything.
-  RunCallback(kInvalidLaunchName, chromeos::AppType::INVALID,
+  RunCallback(kInvalidLaunchName, apps::mojom::AppType::kUnknown,
               chromeos::IntentPickerCloseReason::DIALOG_DEACTIVATED, false);
   return true;
 }
@@ -341,7 +341,7 @@
 // If the widget gets closed without an app being selected we still need to use
 // the callback so the caller can Resume the navigation.
 void IntentPickerBubbleView::OnWidgetDestroying(views::Widget* widget) {
-  RunCallback(kInvalidLaunchName, chromeos::AppType::INVALID,
+  RunCallback(kInvalidLaunchName, apps::mojom::AppType::kUnknown,
               chromeos::IntentPickerCloseReason::DIALOG_DEACTIVATED, false);
 }
 
@@ -392,7 +392,7 @@
 
 void IntentPickerBubbleView::RunCallback(
     const std::string& launch_name,
-    chromeos::AppType app_type,
+    apps::mojom::AppType app_type,
     chromeos::IntentPickerCloseReason close_reason,
     bool should_persist) {
   if (!intent_picker_cb_.is_null()) {
@@ -436,7 +436,7 @@
   // TODO(crbug.com/826982): allow PWAs to have their decision persisted when
   // there is a central Chrome OS apps registry to store persistence.
   const bool should_enable =
-      app_info_[selected_app_tag_].type != chromeos::AppType::PWA;
+      app_info_[selected_app_tag_].type != apps::mojom::AppType::kWeb;
 
   // Reset the checkbox state to the default unchecked if becomes disabled.
   if (!should_enable)
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.h b/chrome/browser/ui/views/intent_picker_bubble_view.h
index 1f0c38fd..79f2ea30 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view.h
+++ b/chrome/browser/ui/views/intent_picker_bubble_view.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "chrome/browser/apps/foundation/app_service/public/mojom/types.mojom.h"
 #include "chrome/browser/chromeos/apps/intent_helper/apps_navigation_types.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
@@ -124,7 +125,7 @@
   // the internal ScrollView.
   IntentPickerLabelButton* GetIntentPickerLabelButtonAt(size_t index);
   void RunCallback(const std::string& launch_name,
-                   chromeos::AppType app_type,
+                   apps::mojom::AppType app_type,
                    chromeos::IntentPickerCloseReason close_reason,
                    bool should_persist);
 
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
index 421876e..1053756 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
@@ -42,14 +42,14 @@
  protected:
   void CreateBubbleView(bool use_icons, bool disable_stay_in_chrome) {
     // Pushing a couple of fake apps just to check they are created on the UI.
-    app_info_.emplace_back(chromeos::AppType::ARC, gfx::Image(), "package_1",
-                           "dank app 1");
-    app_info_.emplace_back(chromeos::AppType::ARC, gfx::Image(), "package_2",
-                           "dank_app_2");
+    app_info_.emplace_back(apps::mojom::AppType::kArc, gfx::Image(),
+                           "package_1", "dank app 1");
+    app_info_.emplace_back(apps::mojom::AppType::kArc, gfx::Image(),
+                           "package_2", "dank_app_2");
     // Also adding the corresponding Chrome's package name on ARC, even if this
     // is given to the picker UI as input it should be ignored.
     app_info_.emplace_back(
-        chromeos::AppType::ARC, gfx::Image(),
+        apps::mojom::AppType::kArc, gfx::Image(),
         arc::ArcIntentHelperBridge::kArcIntentHelperPackageName,
         "legit_chrome");
 
@@ -88,7 +88,7 @@
 
   // Dummy method to be called upon bubble closing.
   void OnBubbleClosed(const std::string& selected_app_package,
-                      chromeos::AppType app_type,
+                      apps::mojom::AppType app_type,
                       chromeos::IntentPickerCloseReason close_reason,
                       bool should_persist) {}
 
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index ede2da3..0e10e89 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -72,6 +72,18 @@
   if (!visible())
     return;
 
+  if (!layer())
+    SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+
+  // When using focus rings are visible we should hide the separator instantly
+  // when the IconLabelBubbleView is focused. Otherwise we should follow the
+  // inkdrop.
+  if (views::PlatformStyle::kPreferFocusRings && owner_->is_focused()) {
+    layer()->SetOpacity(0.0f);
+    return;
+  }
+
   views::InkDrop* ink_drop = owner_->GetInkDrop();
   DCHECK(ink_drop);
 
@@ -88,10 +100,6 @@
     duration = kFadeInDurationMs;
   }
 
-  if (!layer())
-    SetPaintToLayer();
-  layer()->SetFillsBoundsOpaquely(false);
-
   if (disable_animation_for_test_) {
     layer()->SetOpacity(opacity);
   } else {
@@ -180,6 +188,10 @@
   return ShouldShowLabel();
 }
 
+bool IconLabelBubbleView::ShouldShowExtraSpace() const {
+  return false;
+}
+
 double IconLabelBubbleView::WidthMultiplier() const {
   return 1.0;
 }
@@ -232,8 +244,12 @@
   separator_bounds.Inset(0, (separator_bounds.height() - separator_height) / 2);
 
   float separator_width = GetPrefixedSeparatorWidth() + GetEndPadding();
-  separator_view_->SetBounds(label_->bounds().right(), separator_bounds.y(),
-                             separator_width, separator_height);
+  int separator_x =
+      ui::MaterialDesignController::IsRefreshUi() && label_->text().empty()
+          ? image_->bounds().right()
+          : label_->bounds().right();
+  separator_view_->SetBounds(separator_x, separator_bounds.y(), separator_width,
+                             separator_height);
 
   gfx::Rect ink_drop_bounds = GetLocalBounds();
   if (ShouldShowSeparator()) {
@@ -365,6 +381,18 @@
   OnActivate(event);
 }
 
+void IconLabelBubbleView::OnFocus() {
+  is_focused_ = true;
+  separator_view_->UpdateOpacity();
+  Button::OnFocus();
+}
+
+void IconLabelBubbleView::OnBlur() {
+  is_focused_ = false;
+  separator_view_->UpdateOpacity();
+  Button::OnBlur();
+}
+
 void IconLabelBubbleView::OnWidgetDestroying(views::Widget* widget) {
   widget->RemoveObserver(this);
 }
@@ -382,7 +410,11 @@
 }
 
 gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int label_width) const {
-  gfx::Size size(GetNonLabelSize());
+  gfx::Size size(image_->GetPreferredSize());
+  size.Enlarge(
+      GetInsets().left() + GetPrefixedSeparatorWidth() + GetEndPadding(),
+      GetInsets().height());
+
   const bool shrinking = IsShrinking();
   // Animation continues for the last few pixels even after the label is not
   // visible in order to slide the icon into its final position. Therefore it
@@ -395,8 +427,7 @@
     // enough to show the icon. We don't want to shrink all the way back to
     // zero, since this would mean the view would completely disappear and then
     // pop back to an icon after the animation finishes.
-    const int max_width = size.width() + GetInternalSpacing() + label_width +
-                          GetPrefixedSeparatorWidth();
+    const int max_width = size.width() + GetInternalSpacing() + label_width;
     const int current_width = WidthMultiplier() * max_width;
     size.set_width(shrinking ? std::max(current_width, size.width())
                              : current_width);
@@ -404,15 +435,6 @@
   return size;
 }
 
-gfx::Size IconLabelBubbleView::GetMaxSizeForLabelWidth(int label_width) const {
-  gfx::Size size(GetNonLabelSize());
-  if (ShouldShowLabel() || IsShrinking()) {
-    size.Enlarge(
-        GetInternalSpacing() + label_width + GetPrefixedSeparatorWidth(), 0);
-  }
-  return size;
-}
-
 int IconLabelBubbleView::GetInternalSpacing() const {
   if (image_->GetPreferredSize().IsEmpty())
     return 0;
@@ -426,7 +448,9 @@
 }
 
 int IconLabelBubbleView::GetPrefixedSeparatorWidth() const {
-  return ShouldShowSeparator() ? kSeparatorWidth + kSpaceBesideSeparator : 0;
+  return ShouldShowSeparator() || ShouldShowExtraSpace()
+             ? kSeparatorWidth + kSpaceBesideSeparator
+             : 0;
 }
 
 int IconLabelBubbleView::GetEndPadding() const {
@@ -435,12 +459,6 @@
   return GetInsets().right();
 }
 
-gfx::Size IconLabelBubbleView::GetNonLabelSize() const {
-  gfx::Size size(image_->GetPreferredSize());
-  size.Enlarge(GetInsets().left() + GetEndPadding(), GetInsets().height());
-  return size;
-}
-
 bool IconLabelBubbleView::OnActivate(const ui::Event& event) {
   if (ShowBubble(event)) {
     AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr);
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index 52bdeaaf..1e99a772 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -87,6 +87,8 @@
 
   void OnBubbleCreated(views::Widget* bubble_widget);
 
+  bool is_focused() const { return is_focused_; }
+
  protected:
   static constexpr int kOpenTimeMS = 150;
 
@@ -107,6 +109,12 @@
   // Returns true when the separator should be visible.
   virtual bool ShouldShowSeparator() const;
 
+  // Returns true when additional padding equal to GetPrefixedSeparatorWidth()
+  // should be added to the end of the view. This is useful in the case where
+  // it's required to layout subsequent views in the same position regardless
+  // of whether the separator is shown or not.
+  virtual bool ShouldShowExtraSpace() const;
+
   // Returns a multiplier used to calculate the actual width of the view based
   // on its desired width.  This ranges from 0 for a zero-width view to 1 for a
   // full-width view and can be used to animate the width of the view.
@@ -142,6 +150,8 @@
   bool IsTriggerableEvent(const ui::Event& event) override;
   bool ShouldUpdateInkDropOnClickCanceled() const override;
   void NotifyClick(const ui::Event& event) override;
+  void OnFocus() override;
+  void OnBlur() override;
 
   // views::WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
@@ -153,16 +163,7 @@
 
   gfx::Size GetSizeForLabelWidth(int label_width) const;
 
-  // Returns the maximum size for the label width. The value ignores
-  // WidthMultiplier().
-  gfx::Size GetMaxSizeForLabelWidth(int label_width) const;
-
  private:
-  // Amount of padding from the leading edge of the view to the leading edge of
-  // the image, and from the trailing edge of the label (or image, if the label
-  // is invisible) to the trailing edge of the view.
-  int GetOuterPadding() const;
-
   // Spacing between the image and the label.
   int GetInternalSpacing() const;
 
@@ -173,9 +174,6 @@
   // Padding after the separator.
   int GetEndPadding() const;
 
-  // Gets the minimum size to use when the label is not shown.
-  gfx::Size GetNonLabelSize() const;
-
   // The view has been activated by a user gesture such as spacebar.
   // Returns true if some handling was performed.
   bool OnActivate(const ui::Event& event);
@@ -188,6 +186,7 @@
   views::Label* label_;
   views::InkDropContainerView* ink_drop_container_;
   SeparatorView* separator_view_;
+  bool is_focused_ = false;
 
   // The padding of the element that will be displayed after |this|. This value
   // is relevant for calculating the amount of space to reserve after the
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 73f788922..7c7917c 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -469,16 +469,10 @@
   keyword_hint_view_->SetVisible(false);
 
   const int item_padding = GetLayoutConstant(LOCATION_BAR_ELEMENT_PADDING);
-
-  constexpr int kTextIndentDp = 12;
-  int leading_edit_item_padding =
-      ui::MaterialDesignController::IsRefreshUi()
-          ? GetOmniboxPopupView()->IsOpen() ? kTextIndentDp : 0
-          : item_padding;
   // We always subtract the left padding of the OmniboxView itself to allow for
   // an extended I-beam click target without affecting actual layout.
-  leading_edit_item_padding -= omnibox_view_->GetInsets().left();
-
+  const int leading_edit_item_padding =
+      item_padding - omnibox_view_->GetInsets().left();
   LocationBarLayout leading_decorations(
       LocationBarLayout::LEFT_EDGE, item_padding, leading_edit_item_padding);
   LocationBarLayout trailing_decorations(LocationBarLayout::RIGHT_EDGE,
@@ -1235,11 +1229,6 @@
   // The focus ring may be hidden or shown when the popup visibility changes.
   if (focus_ring_)
     focus_ring_->SchedulePaint();
-
-  if (ui::MaterialDesignController::IsRefreshUi()) {
-    Layout();
-    SchedulePaint();
-  }
 }
 
 const ToolbarModel* LocationBarView::GetToolbarModel() const {
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc
index 369e148..3cec848 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/views/controls/label.h"
 
 using content::WebContents;
@@ -71,6 +72,17 @@
       location_bar_->GetToolbarModel()->GetSecurityLevel(false));
 }
 
+bool LocationIconView::ShouldShowSeparator() const {
+  return ShouldShowLabel() ||
+         (ui::MaterialDesignController::IsRefreshUi() &&
+          !location_bar_->GetOmniboxView()->IsEditingOrEmpty());
+}
+
+bool LocationIconView::ShouldShowExtraSpace() const {
+  return ui::MaterialDesignController::IsRefreshUi() &&
+         location_bar_->GetOmniboxView()->IsEditingOrEmpty();
+}
+
 bool LocationIconView::ShowBubble(const ui::Event& event) {
   auto* contents = location_bar_->GetWebContents();
   if (!contents)
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.h b/chrome/browser/ui/views/location_bar/location_icon_view.h
index 04a0a65..f2d0e46 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.h
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.h
@@ -29,6 +29,8 @@
   bool GetTooltipText(const gfx::Point& p,
                       base::string16* tooltip) const override;
   SkColor GetTextColor() const override;
+  bool ShouldShowSeparator() const override;
+  bool ShouldShowExtraSpace() const override;
   bool ShowBubble(const ui::Event& event) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   bool IsBubbleShowing() const override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
index e27feee..e44e4f7 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -36,7 +36,7 @@
 
 // In the MD refresh or rich suggestions, x-offset of the content and
 // description text.
-static constexpr int kTextIndent = 48;
+static constexpr int kTextIndent = 47;
 
 // TODO(dschuyler): Perhaps this should be based on the font size
 // instead of hardcoded to 2 dp (e.g. by adding a space in an
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 2177268..234a8f7 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -595,3 +595,7 @@
   bool is_active = controller_->TogglePlayPause();
   play_pause_controls_view_->SetToggled(is_active);
 }
+
+void OverlayWindowViews::ClickCustomControl(const std::string& control_id) {
+  controller_->ClickCustomControl(control_id);
+}
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index 3649222..54b1e1ec 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -55,6 +55,9 @@
   gfx::Rect GetCloseControlsBounds();
   gfx::Rect GetPlayPauseControlsBounds();
 
+  // Send the message that a custom control on |this| has been clicked.
+  void ClickCustomControl(const std::string& control_id);
+
  private:
   // Gets the internal |ui::Layer| of the controls.
   ui::Layer* GetControlsBackgroundLayer();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index bce0d33f..dbcbbff8 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -1230,6 +1230,7 @@
   Tab* hovered_tab = nullptr;
   Tabs tabs_dragging;
   Tabs selected_tabs;
+  Tabs hovered_tabs;
 
   {
     // We pass false for |lcd_text_requires_opaque_layer| so that background
@@ -1251,22 +1252,19 @@
         } else {
           tabs_dragging.push_back(tab);
         }
-      } else if (!tab->IsActive()) {
-        if (!tab->IsSelected()) {
-          if (!stacked_layout_) {
-            // In Refresh mode, defer the painting of the hovered tab to below.
-            if (MD::IsRefreshUi() && tab->mouse_hovered()) {
-              hovered_tab = tab;
-            } else {
-              tab->Paint(paint_info);
-            }
-          }
-        } else {
-          selected_tabs.push_back(tab);
-        }
-      } else {
+      } else if (tab->IsActive()) {
         active_tab = tab;
         active_tab_index = i;
+      } else if (tab->IsSelected()) {
+        selected_tabs.push_back(tab);
+      } else if (stacked_layout_) {
+        // Do nothing; this will be handled below.
+      } else if (MD::IsRefreshUi() && tab->mouse_hovered()) {
+        hovered_tab = tab;
+      } else if (MD::IsRefreshUi() && tab->hover_controller()->ShouldDraw()) {
+        hovered_tabs.push_back(tab);
+      } else {
+        tab->Paint(paint_info);
       }
       PaintClosingTabs(i, paint_info);
     }
@@ -1287,26 +1285,24 @@
 
   // Now selected but not active. We don't want these dimmed if using native
   // frame, so they're painted after initial pass.
-  for (size_t i = 0; i < selected_tabs.size(); ++i)
-    selected_tabs[i]->Paint(paint_info);
+  for (Tab* tab : selected_tabs)
+    tab->Paint(paint_info);
 
-  // If the last hovered tab is still animating and there is no currently
-  // hovered tab, make sure it still paints in the right order while it's
-  // animating.
-  if (!hovered_tab && last_hovered_tab_ &&
-      last_hovered_tab_->hover_controller()->ShouldDraw())
-    hovered_tab = last_hovered_tab_;
+  // Next, paint the hover animating tabs in ascending order of the current
+  // animation value.
+  std::sort(hovered_tabs.begin(), hovered_tabs.end(),
+            [](Tab* tab1, Tab* tab2) -> bool {
+              return tab1->hover_controller()->GetAnimationValue() <
+                     tab2->hover_controller()->GetAnimationValue();
+            });
+  for (Tab* tab : hovered_tabs)
+    tab->Paint(paint_info);
 
-  // The currently hovered tab or the last tab that was hovered should be
-  // painted right before the active tab to ensure the highlighted tab shape
-  // looks reasonable.
-  if (hovered_tab && !is_dragging)
+  // The currently hovered tab should be painted right before the active tab
+  // to ensure the highlighted tab shape looks reasonable.
+  if (hovered_tab)
     hovered_tab->Paint(paint_info);
 
-  // Keep track of the last tab that was hovered so that it continues to be
-  // painted right before the active tab while the animation is running.
-  last_hovered_tab_ = hovered_tab;
-
   // Next comes the active tab.
   if (active_tab && !is_dragging)
     active_tab->Paint(paint_info);
@@ -1841,8 +1837,6 @@
   res.first->second.erase(res.second);
   if (res.first->second.empty())
     tabs_closing_map_.erase(res.first);
-  if (tab == last_hovered_tab_)
-    last_hovered_tab_ = nullptr;
 }
 
 void TabStrip::UpdateTabsClosingMap(int index, int delta) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index fbdcc467..075ed55 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -670,10 +670,6 @@
   // tab close comes from a touch device.
   base::OneShotTimer resize_layout_timer_;
 
-  // The last tab over which the mouse was hovered which may still have a hover
-  // animation in progress.
-  Tab* last_hovered_tab_ = nullptr;
-
   // This represents the Tabs in |tabs_| that have been selected.
   //
   // Each time tab selection should change, this class will receive a
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
index facf9d2..83ce1a6 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -567,8 +567,7 @@
   data->provider().SetDragImage(
       view_controller
           ->GetIcon(GetCurrentWebContents(),
-                    toolbar_actions_bar_->GetViewSize(),
-                    ToolbarActionButtonState::kNormal)
+                    toolbar_actions_bar_->GetViewSize())
           .AsImageSkia(),
       press_pt.OffsetFromOrigin());
   // Fill in the remaining info.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index f478f9e..4e9074b 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -58,7 +58,6 @@
       delegate_(delegate),
       called_register_command_(false),
       wants_to_run_(false),
-      is_mouse_pressed_(false),
       menu_(nullptr),
       weak_factory_(this) {
   SetInkDropMode(InkDropMode::ON);
@@ -135,17 +134,11 @@
 std::unique_ptr<views::InkDrop> ToolbarActionView::CreateInkDrop() {
   auto ink_drop = CreateToolbarInkDrop<MenuButton>(this);
 
-  // TODO(devlin): Ink drops look weird with the blocked actions state. We'll
-  // need to resolve that.
   ink_drop->SetShowHighlightOnHover(!delegate_->ShownInsideMenu());
   ink_drop->SetShowHighlightOnFocus(!views::PlatformStyle::kPreferFocusRings);
   return ink_drop;
 }
 
-void ToolbarActionView::StateChanged(ButtonState old_state) {
-  UpdateState();
-}
-
 std::unique_ptr<views::InkDropRipple> ToolbarActionView::CreateInkDropRipple()
     const {
   return CreateToolbarInkDropRipple<MenuButton>(
@@ -182,36 +175,12 @@
 
   wants_to_run_ = view_controller_->WantsToRun(web_contents);
 
-  // We need to handle pressed state separately here (rather than just getting
-  // an image for ToolbarActionButtonState::kPressed and assigning it with
-  // SetImage(views::Button::STATE_PRESSED)) because views::MenuButtons don't
-  // always enter the pressed state when the mouse is down, instead waiting for
-  // menu activation. As a workarond, use our own pressed state tracking and
-  // apply the proper image to the Button::STATE_NORMAL state.
-  ToolbarActionButtonState button_state = ToolbarActionButtonState::kNormal;
-  if (is_mouse_pressed_)
-    button_state = ToolbarActionButtonState::kPressed;
-
-  gfx::Size size = GetPreferredSize();
-  gfx::ImageSkia normal_icon(
-      view_controller_->GetIcon(web_contents, size, button_state)
+  gfx::ImageSkia icon(
+      view_controller_->GetIcon(web_contents, GetPreferredSize())
           .AsImageSkia());
 
-  if (!normal_icon.isNull())
-    SetImage(views::Button::STATE_NORMAL, normal_icon);
-
-  // Unlike with the pressed state (see above), hover state works well with the
-  // views::ImageButton methods. However, we need to make sure that we don't
-  // set if the mouse is down (and we're in pseudo-pressed state), so that it
-  // doesn't override the pressed image.
-  gfx::ImageSkia hover_icon;
-  if (!is_mouse_pressed_) {
-    hover_icon =
-        view_controller_
-            ->GetIcon(web_contents, size, ToolbarActionButtonState::kHovered)
-            .AsImageSkia();
-  }
-  SetImage(views::Button::STATE_HOVERED, hover_icon);
+  if (!icon.isNull())
+    SetImage(views::Button::STATE_NORMAL, icon);
 
   SetTooltipText(view_controller_->GetTooltip(web_contents));
 
@@ -253,8 +222,6 @@
 }
 
 bool ToolbarActionView::OnMousePressed(const ui::MouseEvent& event) {
-  is_mouse_pressed_ = true;
-  UpdateState();
   // views::MenuButton actions are only triggered by left mouse clicks.
   if (event.IsOnlyLeftMouseButton() && !pressed_lock_) {
     // TODO(bruthig): The ACTION_PENDING triggering logic should be in
@@ -265,18 +232,6 @@
   return MenuButton::OnMousePressed(event);
 }
 
-void ToolbarActionView::OnMouseReleased(const ui::MouseEvent& event) {
-  is_mouse_pressed_ = false;
-  UpdateState();
-  views::MenuButton::OnMouseReleased(event);
-}
-
-void ToolbarActionView::OnMouseExited(const ui::MouseEvent& event) {
-  is_mouse_pressed_ = false;
-  UpdateState();
-  MenuButton::OnMouseExited(event);
-}
-
 void ToolbarActionView::OnGestureEvent(ui::GestureEvent* event) {
   // While the dropdown menu is showing, the button should not handle gestures.
   if (menu_)
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.h b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
index ac69350..72469c09 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.h
@@ -74,7 +74,6 @@
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override;
   std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
-  void StateChanged(ButtonState old_state) override;
 
   // ToolbarActionViewDelegateViews:
   content::WebContents* GetCurrentWebContents() const override;
@@ -102,8 +101,6 @@
   // views::MenuButton:
   gfx::Size CalculatePreferredSize() const override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
-  void OnMouseReleased(const ui::MouseEvent& event) override;
-  void OnMouseExited(const ui::MouseEvent& event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
   void OnDragDone() override;
   void ViewHierarchyChanged(
@@ -150,12 +147,6 @@
   // tab.
   bool wants_to_run_;
 
-  // Whether the mouse is currently pressed. We store this separately, since
-  // the button state doesn't correspond to the mouse pressed state for
-  // draggable menu buttons (i.e., they don't enter a pushed state in
-  // OnMouseDown).
-  bool is_mouse_pressed_;
-
   // Responsible for converting the context menu model into |menu_|.
   std::unique_ptr<views::MenuModelAdapter> menu_adapter_;
 
diff --git a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
index d46c710..1f3766c 100644
--- a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
+++ b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -88,7 +88,7 @@
       return false;
 #endif
     case ntp_tiles::TileSource::CUSTOM_LINKS:
-      return ntp_tiles::IsMDCustomLinksEnabled();
+      return ntp_tiles::IsCustomLinksEnabled();
   }
   NOTREACHED();
   return false;
diff --git a/chrome/common/extensions/api/downloads.idl b/chrome/common/extensions/api/downloads.idl
index 3f62e35f..bd0c9b4 100644
--- a/chrome/common/extensions/api/downloads.idl
+++ b/chrome/common/extensions/api/downloads.idl
@@ -63,6 +63,7 @@
     SERVER_FORBIDDEN,
     SERVER_UNREACHABLE,
     SERVER_CONTENT_LENGTH_MISMATCH,
+    SERVER_CROSS_ORIGIN_REDIRECT,
     USER_CANCELED,
     USER_SHUTDOWN,
     CRASH};
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl
index e79d21b..40a2409 100644
--- a/chrome/common/extensions/api/file_manager_private.idl
+++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -72,6 +72,13 @@
   error
 };
 
+// The response when starting installing a Linux package.
+enum InstallLinuxPackageResponse {
+  started,
+  failed,
+  install_already_active
+};
+
 // Specifies type of event that is raised.
 enum FileWatchEventType { changed, error };
 
@@ -731,6 +738,11 @@
 // |entries| Recently modified entries.
 callback GetRecentFilesCallback = void([instanceOf=Entry] object[] entries);
 
+// |status| Result of starting the install
+// |failure_reason| Reason for failure for a 'failed' status
+callback InstallLinuxPackageCallback = void(
+    InstallLinuxPackageResponse response, DOMString failure_reason);
+
 interface Functions {
   // Logout the current user for navigating to the re-authentication screen for
   // the Google account.
@@ -1104,6 +1116,11 @@
   // Starts and mounts crostini container.
   // |callback|
   static void mountCrostiniContainer(SimpleCallback callback);
+
+  // Starts installation of a Linux package.
+  [nocompile]
+  static void installLinuxPackage([instanceof=Entry] object entry,
+                                  InstallLinuxPackageCallback callback);
 };
 
 interface Events {
diff --git a/chrome/common/extensions/api/file_manager_private_internal.idl b/chrome/common/extensions/api/file_manager_private_internal.idl
index caeb61a..5a53b45 100644
--- a/chrome/common/extensions/api/file_manager_private_internal.idl
+++ b/chrome/common/extensions/api/file_manager_private_internal.idl
@@ -32,6 +32,9 @@
   callback ValidatePathNameLengthCallback = void(boolean result);
   callback GetDirectorySizeCallback = void(double size);
   callback GetRecentFilesCallback = void(EntryDescription[] entries);
+  callback InstallLinuxPackageCallback =
+      void(fileManagerPrivate.InstallLinuxPackageResponse response,
+           optional DOMString failure_reason);
 
   interface Functions {
     static void resolveIsolatedEntries(DOMString[] urls,
@@ -97,5 +100,7 @@
                                  GetDirectorySizeCallback callback);
     static void getRecentFiles(fileManagerPrivate.SourceRestriction restriction,
                                GetRecentFilesCallback callback);
+    static void installLinuxPackage(DOMString url,
+                                    InstallLinuxPackageCallback callback);
   };
 };
diff --git a/chrome/common/instant_struct_traits.h b/chrome/common/instant_struct_traits.h
index d841649..96f5c3c 100644
--- a/chrome/common/instant_struct_traits.h
+++ b/chrome/common/instant_struct_traits.h
@@ -62,6 +62,9 @@
 IPC_STRUCT_TRAITS_BEGIN(ThemeBackgroundInfo)
   IPC_STRUCT_TRAITS_MEMBER(using_default_theme)
   IPC_STRUCT_TRAITS_MEMBER(custom_background_url)
+  IPC_STRUCT_TRAITS_MEMBER(custom_background_attribution_line_1)
+  IPC_STRUCT_TRAITS_MEMBER(custom_background_attribution_line_2)
+  IPC_STRUCT_TRAITS_MEMBER(custom_background_attribution_action_url)
   IPC_STRUCT_TRAITS_MEMBER(background_color)
   IPC_STRUCT_TRAITS_MEMBER(text_color)
   IPC_STRUCT_TRAITS_MEMBER(link_color)
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 2b1ca7b..7ad9c3f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1442,6 +1442,7 @@
 
 // Set before autorestarting Chrome, cleared on clean exit.
 const char kWasRestarted[] = "was.restarted";
+
 #endif  // !defined(OS_ANDROID)
 
 // Whether Extensions are enabled.
@@ -1482,6 +1483,9 @@
     "ntp.content_suggestions.notifications.sent_day";
 const char kContentSuggestionsNotificationsSentCount[] =
     "ntp.content_suggestions.notifications.sent_count";
+#else
+// Holds info for New Tab Page custom background
+const char kNtpCustomBackgroundDict[] = "ntp.custom_background_dict";
 #endif  // defined(OS_ANDROID)
 
 // Which page should be visible on the new tab page v4
@@ -2593,10 +2597,6 @@
 
 // Holds URL patterns that specify URLs that will be allowed to autoplay.
 const char kAutoplayWhitelist[] = "media.autoplay_whitelist";
-
-// Holds URL for New Tab Page custom background
-const char kNTPCustomBackgroundURL[] = "new_tab_page.custom_background_url";
-
 #endif  // !defined(OS_ANDROID)
 
 // Integer that holds the value of the next persistent notification ID to be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 8066ed6b..387ef158 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -522,6 +522,8 @@
 extern const char kContentSuggestionsConsecutiveIgnoredPrefName[];
 extern const char kContentSuggestionsNotificationsSentDay[];
 extern const char kContentSuggestionsNotificationsSentCount[];
+#else
+extern const char kNtpCustomBackgroundDict[];
 #endif  // defined(OS_ANDROID)
 extern const char kNtpShownPage[];
 
@@ -914,7 +916,6 @@
 #if !defined(OS_ANDROID)
 extern const char kAutoplayAllowed[];
 extern const char kAutoplayWhitelist[];
-extern const char kNTPCustomBackgroundURL[];
 #endif
 
 extern const char kNotificationNextPersistentId[];
diff --git a/chrome/common/search.mojom b/chrome/common/search.mojom
index 567f776..216b817 100644
--- a/chrome/common/search.mojom
+++ b/chrome/common/search.mojom
@@ -73,6 +73,10 @@
 
   // Updates the NTP custom background preferences.
   SetCustomBackgroundURL(url.mojom.Url url);
+  SetCustomBackgroundURLWithAttributions(url.mojom.Url background_url,
+                                         string attribution_line_1,
+                                         string attribution_line_2,
+                                         url.mojom.Url action_url);
 
   // Let the user select a local file for the NTP background.
   SelectLocalBackgroundImage();
diff --git a/chrome/common/search/instant_types.cc b/chrome/common/search/instant_types.cc
index 3989a57..d4e907d 100644
--- a/chrome/common/search/instant_types.cc
+++ b/chrome/common/search/instant_types.cc
@@ -27,6 +27,9 @@
 ThemeBackgroundInfo::ThemeBackgroundInfo()
     : using_default_theme(true),
       custom_background_url(std::string()),
+      custom_background_attribution_line_1(std::string()),
+      custom_background_attribution_line_2(std::string()),
+      custom_background_attribution_action_url(std::string()),
       background_color(),
       text_color(),
       link_color(),
@@ -45,6 +48,12 @@
 bool ThemeBackgroundInfo::operator==(const ThemeBackgroundInfo& rhs) const {
   return using_default_theme == rhs.using_default_theme &&
          custom_background_url == rhs.custom_background_url &&
+         custom_background_attribution_line_1 ==
+             rhs.custom_background_attribution_line_1 &&
+         custom_background_attribution_line_2 ==
+             rhs.custom_background_attribution_line_2 &&
+         custom_background_attribution_action_url ==
+             rhs.custom_background_attribution_action_url &&
          background_color == rhs.background_color &&
          text_color == rhs.text_color && link_color == rhs.link_color &&
          text_color_light == rhs.text_color_light &&
diff --git a/chrome/common/search/instant_types.h b/chrome/common/search/instant_types.h
index 16fd685..63d3f72 100644
--- a/chrome/common/search/instant_types.h
+++ b/chrome/common/search/instant_types.h
@@ -70,6 +70,15 @@
   // Url of the custom background selected by the user.
   GURL custom_background_url;
 
+  // First attribution string for custom background.
+  std::string custom_background_attribution_line_1;
+
+  // Second attribution string for custom background.
+  std::string custom_background_attribution_line_2;
+
+  // Url to learn more info about the custom background.
+  GURL custom_background_attribution_action_url;
+
   // The theme background color in RGBA format always valid.
   RGBAColor background_color;
 
diff --git a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
index 9b94aa69..7335879 100644
--- a/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_manager_private_custom_bindings.js
@@ -221,6 +221,12 @@
       }));
     });
   });
+
+  apiFunctions.setHandleRequest('installLinuxPackage', function(
+        entry, callback) {
+    var url = fileManagerPrivateNatives.GetEntryURL(entry);
+    fileManagerPrivateInternal.installLinuxPackage(url, callback);
+  });
 });
 
 registerArgumentMassager('fileManagerPrivate.onDirectoryChanged',
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc
index 3186c6f0..86d1dfcd 100644
--- a/chrome/renderer/searchbox/searchbox.cc
+++ b/chrome/renderer/searchbox/searchbox.cc
@@ -318,6 +318,15 @@
   embedded_search_service_->SetCustomBackgroundURL(background_url);
 }
 
+void SearchBox::SetCustomBackgroundURLWithAttributions(
+    const GURL& background_url,
+    const std::string& attribution_line_1,
+    const std::string& attribution_line_2,
+    const GURL& action_url) {
+  embedded_search_service_->SetCustomBackgroundURLWithAttributions(
+      background_url, attribution_line_1, attribution_line_2, action_url);
+}
+
 void SearchBox::SelectLocalBackgroundImage() {
   embedded_search_service_->SelectLocalBackgroundImage();
 }
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h
index 83c36ab..143ca0f2 100644
--- a/chrome/renderer/searchbox/searchbox.h
+++ b/chrome/renderer/searchbox/searchbox.h
@@ -119,8 +119,14 @@
   // Sends UndoMostVisitedDeletion to the browser.
   void UndoMostVisitedDeletion(InstantRestrictedID most_visited_item_id);
 
-  // Updates the NTP custom background preferences.
+  // Updates the NTP custom background preferences, sometimes this includes
+  // image attributions.
   void SetCustomBackgroundURL(const GURL& background_url);
+  void SetCustomBackgroundURLWithAttributions(
+      const GURL& background_url,
+      const std::string& attribution_line_1,
+      const std::string& attribution_line_2,
+      const GURL& action_url);
 
   // Let the user select a local file for the NTP background.
   void SelectLocalBackgroundImage();
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index 6f54655..01bb7735 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -345,6 +345,12 @@
                 std::string(kCSSBackgroundPositionCenter));
     builder.Set("imageVerticalAlignment",
                 std::string(kCSSBackgroundPositionCenterCover));
+    builder.Set("attributionActionUrl",
+                theme_info.custom_background_attribution_action_url.spec());
+    builder.Set("attribution1",
+                theme_info.custom_background_attribution_line_1);
+    builder.Set("attribution2",
+                theme_info.custom_background_attribution_line_2);
   }
 
   return builder.Build();
@@ -594,6 +600,11 @@
       int tile_type,
       v8::Local<v8::Value> data_generation_time);
   static void SetCustomBackgroundURL(const std::string& background_url);
+  static void SetCustomBackgroundURLWithAttributions(
+      const std::string& background_url,
+      const std::string& attribution_line_1,
+      const std::string& attribution_line_2,
+      const std::string& attributionActionUrl);
   static void SelectLocalBackgroundImage();
 
   DISALLOW_COPY_AND_ASSIGN(NewTabPageBindings);
@@ -633,6 +644,8 @@
                  &NewTabPageBindings::LogMostVisitedNavigation)
       .SetMethod("setBackgroundURL",
                  &NewTabPageBindings::SetCustomBackgroundURL)
+      .SetMethod("setBackgroundURLWithAttributions",
+                 &NewTabPageBindings::SetCustomBackgroundURLWithAttributions)
       .SetMethod("selectLocalBackgroundImage",
                  &NewTabPageBindings::SelectLocalBackgroundImage);
 }
@@ -840,6 +853,18 @@
 }
 
 // static
+void NewTabPageBindings::SetCustomBackgroundURLWithAttributions(
+    const std::string& background_url,
+    const std::string& attribution_line_1,
+    const std::string& attribution_line_2,
+    const std::string& attribution_action_url) {
+  SearchBox* search_box = GetSearchBoxForCurrentContext();
+  search_box->SetCustomBackgroundURLWithAttributions(
+      GURL(background_url), attribution_line_1, attribution_line_2,
+      GURL(attribution_action_url));
+}
+
+// static
 void NewTabPageBindings::SelectLocalBackgroundImage() {
   SearchBox* search_box = GetSearchBoxForCurrentContext();
   search_box->SelectLocalBackgroundImage();
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html
index 63575dd..d852252f 100644
--- a/chrome/test/data/local_ntp/local_ntp_browsertest.html
+++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -51,60 +51,63 @@
         <!-- The container for the tiles. The MV iframe goes in here. -->
         <div id="mv-tiles"></div>
         <!-- Notification shown when a tile is blacklisted. -->
-        <div id="mv-notice" class="mv-notice-hide">
-          <span id="mv-msg"></span>
-          <!-- Links in the notification. -->
-          <span id="mv-notice-links">
-            <span id="mv-undo" tabIndex="1"></span>
-            <span id="mv-restore" tabIndex="1"></span>
-            <button id="mv-notice-x" tabIndex="1" class="mv-x"></button>
-          </span>
+        <div id="mv-notice-container">
+          <div id="mv-notice" class="mv-notice-hide" role="alert">
+            <span id="mv-msg"></span>
+            <!-- Links in the notification. -->
+            <span id="mv-notice-links">
+              <span id="mv-undo" class="ripple" tabindex="0" role="button"></span>
+              <span id="mv-restore" class="ripple" tabindex="0" role="button">
+              </span>
+              <div id="mv-notice-x" tabindex="0" role="button"></div>
+            </span>
+          </div>
         </div>
       </div>
       <div id="attribution"><div id="attribution-text"></div></div>
 
-    <div id="edit-bg" hidden>
-      <button id="edit-bg-gear"></button>
-    </div>
-  </div>
-
-  <dialog div id="edit-bg-dialog">
-    <div id="edit-bg-title"></div>
-    <div id="edit-bg-google-photos" class="bg-option" tabindex="0">
-      <div class="bg-option-img"></div>
-      <div id="edit-bg-google-photos-text" class="bg-option-text"></div>
-    </div>
-    <div id="edit-bg-default-wallpapers" class="bg-option" tabindex="0">
-      <div class="bg-option-img"></div>
-      <div id="edit-bg-default-wallpapers-text" class="bg-option-text">
+      <div id="edit-bg" hidden>
+        <button id="edit-bg-gear"></button>
       </div>
     </div>
-    <div id="edit-bg-upload-image" class="bg-option" tabindex="0">
-      <div class="bg-option-img"></div>
-      <div id="edit-bg-upload-image-text" class="bg-option-text"></div>
-    </div>
-    <div id="edit-bg-restore-default" class="bg-option" tabindex="0">
-      <div class="bg-option-img"></div>
-      <div id="edit-bg-restore-default-text" class="bg-option-text"></div>
-    </div>
-  </dialog>
 
-  <dialog id="bg-sel-menu">
-    <div id="bg-sel-title-bar">
-    <div id="bg-sel-back"></div>
-    <div id="bg-sel-title"></div>
-    </div>
-    <div id="bg-sel-tiles"></div>
-    <div id="bg-sel-footer">
-      <label id="bg-daily-refresh" class="switch">
-        <input type="checkbox">
-        <span class="toggle"></span>
-      </label>
-      <div id="bg-sel-refresh-text"></div>
-      <div id="bg-sel-footer-cancel" class="bg-sel-footer-button ripple" tabindex="0"></div>
-      <div id="bg-sel-footer-done" class="bg-sel-footer-button ripple"></div>
-    </div>
-  </dialog>
+    <dialog div id="edit-bg-dialog">
+      <div id="edit-bg-title"></div>
+      <div id="edit-bg-google-photos" class="bg-option" tabindex="0">
+        <div class="bg-option-img"></div>
+        <div id="edit-bg-google-photos-text" class="bg-option-text"></div>
+      </div>
+      <div id="edit-bg-default-wallpapers" class="bg-option" tabindex="0">
+        <div class="bg-option-img"></div>
+        <div id="edit-bg-default-wallpapers-text" class="bg-option-text">
+        </div>
+      </div>
+      <div id="edit-bg-upload-image" class="bg-option" tabindex="0">
+        <div class="bg-option-img"></div>
+        <div id="edit-bg-upload-image-text" class="bg-option-text"></div>
+      </div>
+      <div id="edit-bg-restore-default" class="bg-option" tabindex="0">
+        <div class="bg-option-img"></div>
+        <div id="edit-bg-restore-default-text" class="bg-option-text"></div>
+      </div>
+    </dialog>
+
+    <dialog id="bg-sel-menu">
+      <div id="bg-sel-title-bar">
+      <div id="bg-sel-back"></div>
+      <div id="bg-sel-title"></div>
+      </div>
+      <div id="bg-sel-tiles"></div>
+      <div id="bg-sel-footer">
+        <label id="bg-daily-refresh" class="switch">
+          <input type="checkbox">
+          <span class="toggle"></span>
+        </label>
+        <div id="bg-sel-refresh-text"></div>
+        <div id="bg-sel-footer-cancel" class="bg-sel-footer-button ripple" tabindex="0"></div>
+        <div id="bg-sel-footer-done" class="bg-sel-footer-button ripple"></div>
+      </div>
+    </dialog>
 
     <dialog id="voice-overlay-dialog" class="overlay-dialog">
       <div id="voice-overlay" class="overlay-hidden">
@@ -136,6 +139,9 @@
         </div>
       </div>
     </dialog>
+
+    <iframe id="custom-links-edit" name="custom-links-edit"
+            src="chrome-search://most-visited/edit.html"></iframe>
   </template>
 </head>
 <body>
diff --git a/chrome/test/data/media/picture-in-picture/window-size.html b/chrome/test/data/media/picture-in-picture/window-size.html
index 7c27e3b..da7a136 100644
--- a/chrome/test/data/media/picture-in-picture/window-size.html
+++ b/chrome/test/data/media/picture-in-picture/window-size.html
@@ -49,6 +49,10 @@
         document.title = 'left';
       }, { once: true });
 
+      video.addEventListener('pictureinpicturecontrolclick', function(event) {
+        document.title = event.id;
+      }, { once: true });
+
       window.domAutomationController.send(true);
     })
     .catch(e => {
diff --git a/chrome/test/data/webui/settings/privacy_page_test.js b/chrome/test/data/webui/settings/privacy_page_test.js
index ab7e2e40..9a8ae94 100644
--- a/chrome/test/data/webui/settings/privacy_page_test.js
+++ b/chrome/test/data/webui/settings/privacy_page_test.js
@@ -186,7 +186,9 @@
         actionButton.click();
 
         return testBrowserProxy.whenCalled('clearBrowsingData')
-            .then(function([dataTypes, timePeriod]) {
+            .then(function(args) {
+              const dataTypes = args[0];
+              const timePeriod = args[1];
               assertEquals(1, dataTypes.length);
               assertEquals('browser.clear_data.cookies_basic', dataTypes[0]);
               assertTrue(element.$$('#clearBrowsingDataDialog').open);
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 6435354..caf0382 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -37,8 +37,6 @@
     "intent_helper/link_handler_model.cc",
     "intent_helper/link_handler_model.h",
     "intent_helper/open_url_delegate.h",
-    "intent_helper/page_transition_util.cc",
-    "intent_helper/page_transition_util.h",
     "lock_screen/arc_lock_screen_bridge.cc",
     "lock_screen/arc_lock_screen_bridge.h",
     "metrics/arc_metrics_service.cc",
@@ -284,7 +282,6 @@
     "intent_helper/font_size_util_unittest.cc",
     "intent_helper/intent_filter_unittest.cc",
     "intent_helper/link_handler_model_unittest.cc",
-    "intent_helper/page_transition_util_unittest.cc",
     "metrics/arc_metrics_service_unittest.cc",
     "power/arc_power_bridge_unittest.cc",
     "timer/arc_timer_bridge_unittest.cc",
diff --git a/components/download/internal/common/BUILD.gn b/components/download/internal/common/BUILD.gn
index 7e0ffb3..5121397 100644
--- a/components/download/internal/common/BUILD.gn
+++ b/components/download/internal/common/BUILD.gn
@@ -48,6 +48,7 @@
     "save_package_download_job.h",
     "stream_handle_input_stream.cc",
     "url_download_handler_factory.cc",
+    "url_download_request_handle.cc",
   ]
 
   public_deps = [
diff --git a/components/download/internal/common/download_create_info.cc b/components/download/internal/common/download_create_info.cc
index 11ee224..ebc8df19 100644
--- a/components/download/internal/common/download_create_info.cc
+++ b/components/download/internal/common/download_create_info.cc
@@ -17,6 +17,8 @@
     const base::Time& start_time,
     std::unique_ptr<DownloadSaveInfo> save_info)
     : is_new_download(true),
+      referrer_policy(net::URLRequest::
+                          CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
       start_time(start_time),
       total_bytes(0),
       offset(0),
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc
index 134af6c..8c4705f3 100644
--- a/components/download/internal/common/download_item_impl.cc
+++ b/components/download/internal/common/download_item_impl.cc
@@ -1147,6 +1147,7 @@
     case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
     case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
     case DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
+    case DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT:
     case DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE:
       return ResumeMode::INVALID;
   }
diff --git a/components/download/internal/common/download_response_handler.cc b/components/download/internal/common/download_response_handler.cc
index c57935b..a0080bd0 100644
--- a/components/download/internal/common/download_response_handler.cc
+++ b/components/download/internal/common/download_response_handler.cc
@@ -64,6 +64,7 @@
       url_chain_(std::move(url_chain)),
       method_(resource_request->method),
       referrer_(resource_request->referrer),
+      referrer_policy_(resource_request->referrer_policy),
       is_transient_(is_transient),
       fetch_error_body_(fetch_error_body),
       follow_cross_origin_redirects_(follow_cross_origin_redirects),
@@ -132,6 +133,7 @@
   create_info->connection_info = head.connection_info;
   create_info->url_chain = url_chain_;
   create_info->referrer_url = referrer_;
+  create_info->referrer_policy = referrer_policy_;
   create_info->transient = is_transient_;
   create_info->response_headers = head.headers;
   create_info->offset = create_info->save_info->offset;
@@ -151,8 +153,13 @@
   if (!follow_cross_origin_redirects_ &&
       !first_origin_.IsSameOriginWith(
           url::Origin::Create(redirect_info.new_url))) {
-    // TODO(jochen): Abort download and instead navigate.
-    DVLOG(1) << "Download encountered cross origin redirect.";
+    abort_reason_ = DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT;
+    url_chain_.push_back(redirect_info.new_url);
+    method_ = redirect_info.new_method;
+    referrer_ = GURL(redirect_info.new_referrer);
+    referrer_policy_ = redirect_info.new_referrer_policy;
+    OnComplete(network::URLLoaderCompletionStatus(net::OK));
+    return;
   }
   if (is_partial_request_) {
     // A redirect while attempting a partial resumption indicates a potential
@@ -165,6 +172,7 @@
   url_chain_.push_back(redirect_info.new_url);
   method_ = redirect_info.new_method;
   referrer_ = GURL(redirect_info.new_referrer);
+  referrer_policy_ = redirect_info.new_referrer_policy;
   delegate_->OnReceiveRedirect();
 }
 
@@ -202,8 +210,10 @@
         ConvertInterruptReasonToMojoNetworkRequestStatus(reason));
   }
 
-  if (started_)
+  if (started_) {
+    delegate_->OnResponseCompleted();
     return;
+  }
 
   // OnComplete() called without OnReceiveResponse(). This should only
   // happen when the request was aborted.
@@ -211,6 +221,7 @@
   create_info_->result = reason;
 
   OnResponseStarted(mojom::DownloadStreamHandlePtr());
+  delegate_->OnResponseCompleted();
 }
 
 void DownloadResponseHandler::OnResponseStarted(
diff --git a/components/download/internal/common/in_progress_download_manager.cc b/components/download/internal/common/in_progress_download_manager.cc
index cd9c07ee..ca5a426d 100644
--- a/components/download/internal/common/in_progress_download_manager.cc
+++ b/components/download/internal/common/in_progress_download_manager.cc
@@ -374,7 +374,10 @@
     const DownloadUrlParameters::OnStartedCallback& on_started) {
   DCHECK(info);
 
-  if (info->is_new_download && info->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
+  if (info->is_new_download &&
+      (info->result == DOWNLOAD_INTERRUPT_REASON_NONE ||
+       info->result ==
+           DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT)) {
     if (delegate_ && delegate_->InterceptDownload(*info)) {
       GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release());
       return;
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc
index 6cc8757..5d958e9 100644
--- a/components/download/internal/common/resource_downloader.cc
+++ b/components/download/internal/common/resource_downloader.cc
@@ -8,6 +8,7 @@
 
 #include "components/download/public/common/download_url_loader_factory_getter.h"
 #include "components/download/public/common/stream_handle_input_stream.h"
+#include "components/download/public/common/url_download_request_handle.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace network {
@@ -198,6 +199,8 @@
 void ResourceDownloader::OnResponseStarted(
     std::unique_ptr<DownloadCreateInfo> download_create_info,
     mojom::DownloadStreamHandlePtr stream_handle) {
+  download_create_info->request_handle.reset(new UrlDownloadRequestHandle(
+      weak_ptr_factory_.GetWeakPtr(), base::SequencedTaskRunnerHandle::Get()));
   download_create_info->is_new_download = is_new_download_;
   download_create_info->guid = guid_;
   download_create_info->site_url = site_url_;
@@ -219,4 +222,19 @@
   url_loader_->FollowRedirect(base::nullopt, base::nullopt);
 }
 
+void ResourceDownloader::OnResponseCompleted() {
+  Destroy();
+}
+
+void ResourceDownloader::CancelRequest() {
+  Destroy();
+}
+
+void ResourceDownloader::Destroy() {
+  delegate_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&UrlDownloadHandler::Delegate::OnUrlDownloadStopped,
+                     delegate_, this));
+}
+
 }  // namespace download
diff --git a/components/download/internal/common/resource_downloader.h b/components/download/internal/common/resource_downloader.h
index a3b144b..a3557f8 100644
--- a/components/download/internal/common/resource_downloader.h
+++ b/components/download/internal/common/resource_downloader.h
@@ -73,6 +73,7 @@
       std::unique_ptr<download::DownloadCreateInfo> download_create_info,
       download::mojom::DownloadStreamHandlePtr stream_handle) override;
   void OnReceiveRedirect() override;
+  void OnResponseCompleted() override;
 
  private:
   // Helper method to start the network request.
@@ -87,6 +88,12 @@
       net::CertStatus cert_status,
       network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints);
 
+  // UrlDownloadHandler implementations.
+  void CancelRequest() override;
+
+  // Ask the |delegate_| to destroy this object.
+  void Destroy();
+
   base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate_;
 
   // The ResourceRequest for this object.
diff --git a/components/download/internal/common/stream_handle_input_stream.cc b/components/download/internal/common/stream_handle_input_stream.cc
index 12a536b..c6c0c7f7 100644
--- a/components/download/internal/common/stream_handle_input_stream.cc
+++ b/components/download/internal/common/stream_handle_input_stream.cc
@@ -100,6 +100,11 @@
 
 void StreamHandleInputStream::OnStreamCompleted(
     mojom::NetworkRequestStatus status) {
+  // This method could get called again when the URLLoader is being destroyed.
+  // However, if the response is already completed, don't set the
+  // |completion_status_| again.
+  if (is_response_completed_)
+    return;
   // This can be called before or after data pipe is completely drained.
   completion_status_ = ConvertMojoNetworkRequestStatusToInterruptReason(status);
   is_response_completed_ = true;
diff --git a/components/download/internal/common/url_download_request_handle.cc b/components/download/internal/common/url_download_request_handle.cc
new file mode 100644
index 0000000..7fa6bd8
--- /dev/null
+++ b/components/download/internal/common/url_download_request_handle.cc
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/public/common/url_download_request_handle.h"
+
+namespace download {
+
+UrlDownloadRequestHandle::UrlDownloadRequestHandle(
+    base::WeakPtr<UrlDownloadHandler> downloader,
+    scoped_refptr<base::SequencedTaskRunner> downloader_task_runner)
+    : downloader_(downloader),
+      downloader_task_runner_(downloader_task_runner) {}
+
+UrlDownloadRequestHandle::UrlDownloadRequestHandle(
+    UrlDownloadRequestHandle&& other)
+    : downloader_(std::move(other.downloader_)),
+      downloader_task_runner_(std::move(other.downloader_task_runner_)) {}
+
+UrlDownloadRequestHandle& UrlDownloadRequestHandle::operator=(
+    UrlDownloadRequestHandle&& other) {
+  downloader_ = std::move(other.downloader_);
+  downloader_task_runner_ = std::move(other.downloader_task_runner_);
+  return *this;
+}
+
+UrlDownloadRequestHandle::~UrlDownloadRequestHandle() = default;
+
+void UrlDownloadRequestHandle::PauseRequest() {
+  downloader_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&UrlDownloadHandler::PauseRequest, downloader_));
+}
+
+void UrlDownloadRequestHandle::ResumeRequest() {
+  downloader_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&UrlDownloadHandler::ResumeRequest, downloader_));
+}
+
+void UrlDownloadRequestHandle::CancelRequest(bool user_cancel) {
+  downloader_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&UrlDownloadHandler::CancelRequest, downloader_));
+}
+
+}  // namespace download
diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn
index 00453df..5c8c8717 100644
--- a/components/download/public/common/BUILD.gn
+++ b/components/download/public/common/BUILD.gn
@@ -57,6 +57,7 @@
     "resume_mode.h",
     "stream_handle_input_stream.h",
     "url_download_handler_factory.h",
+    "url_download_request_handle.h",
   ]
 
   configs += [ ":components_download_implementation" ]
diff --git a/components/download/public/common/download_create_info.h b/components/download/public/common/download_create_info.h
index 72264788..7c826954 100644
--- a/components/download/public/common/download_create_info.h
+++ b/components/download/public/common/download_create_info.h
@@ -23,6 +23,7 @@
 #include "components/download/public/common/download_source.h"
 #include "components/download/public/common/download_url_parameters.h"
 #include "net/http/http_response_info.h"
+#include "net/url_request/url_request.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
@@ -53,8 +54,9 @@
   // The chain of redirects that leading up to and including the final URL.
   std::vector<GURL> url_chain;
 
-  // The URL that referred us.
+  // The URL and referrer policy that referred us.
   GURL referrer_url;
+  net::URLRequest::ReferrerPolicy referrer_policy;
 
   // Site URL for the site instance that initiated the download.
   GURL site_url;
diff --git a/components/download/public/common/download_interrupt_reason_values.h b/components/download/public/common/download_interrupt_reason_values.h
index 02cd84e..5b8da46 100644
--- a/components/download/public/common/download_interrupt_reason_values.h
+++ b/components/download/public/common/download_interrupt_reason_values.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// no-include-guard-because-multiply-included
+
 // Note that the embedder is welcome to persist these values across
 // invocations of the browser, and possibly across browser versions.
 // Thus individual errors may be deprecated and new errors added, but
@@ -122,6 +124,9 @@
 // Otherwise, it is treated as finished.
 INTERRUPT_REASON(SERVER_CONTENT_LENGTH_MISMATCH, 38)
 
+// An unexpected cross-origin redirect happened.
+INTERRUPT_REASON(SERVER_CROSS_ORIGIN_REDIRECT, 39)
+
 // User input.
 
 // The user canceled the download.
diff --git a/components/download/public/common/download_response_handler.h b/components/download/public/common/download_response_handler.h
index db38793..0948745 100644
--- a/components/download/public/common/download_response_handler.h
+++ b/components/download/public/common/download_response_handler.h
@@ -26,13 +26,14 @@
 class COMPONENTS_DOWNLOAD_EXPORT DownloadResponseHandler
     : public network::mojom::URLLoaderClient {
  public:
-  // Class for handling the stream once response starts.
+  // Class for handling the stream response.
   class Delegate {
    public:
     virtual void OnResponseStarted(
         std::unique_ptr<DownloadCreateInfo> download_create_info,
         mojom::DownloadStreamHandlePtr stream_handle) = 0;
     virtual void OnReceiveRedirect() = 0;
+    virtual void OnResponseCompleted() = 0;
   };
 
   DownloadResponseHandler(
@@ -80,6 +81,7 @@
   std::vector<GURL> url_chain_;
   std::string method_;
   GURL referrer_;
+  net::URLRequest::ReferrerPolicy referrer_policy_;
   bool is_transient_;
   bool fetch_error_body_;
   bool follow_cross_origin_redirects_;
diff --git a/components/download/public/common/url_download_handler.h b/components/download/public/common/url_download_handler.h
index ce059d923..7972520 100644
--- a/components/download/public/common/url_download_handler.h
+++ b/components/download/public/common/url_download_handler.h
@@ -40,6 +40,15 @@
   UrlDownloadHandler() = default;
   virtual ~UrlDownloadHandler() = default;
 
+  // Called on the io thread to pause the url request.
+  virtual void PauseRequest() {}
+
+  // Called on the io thread to resume the url request.
+  virtual void ResumeRequest() {}
+
+  // Called on the io thread to cancel the url request.
+  virtual void CancelRequest() {}
+
   DISALLOW_COPY_AND_ASSIGN(UrlDownloadHandler);
 };
 
diff --git a/components/download/public/common/url_download_request_handle.h b/components/download/public/common/url_download_request_handle.h
new file mode 100644
index 0000000..46c7756
--- /dev/null
+++ b/components/download/public/common/url_download_request_handle.h
@@ -0,0 +1,40 @@
+// 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_DOWNLOAD_PUBLIC_COMMON_URL_DOWNLOAD_REQUEST_HANDLE_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_URL_DOWNLOAD_REQUEST_HANDLE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/download/public/common/download_export.h"
+#include "components/download/public/common/download_request_handle_interface.h"
+#include "components/download/public/common/url_download_handler.h"
+
+namespace download {
+
+// Implementation of the DownloadRequestHandleInterface to handle url download.
+class COMPONENTS_DOWNLOAD_EXPORT UrlDownloadRequestHandle
+    : public DownloadRequestHandleInterface {
+ public:
+  UrlDownloadRequestHandle(
+      base::WeakPtr<UrlDownloadHandler> downloader,
+      scoped_refptr<base::SequencedTaskRunner> downloader_task_runner);
+  UrlDownloadRequestHandle(UrlDownloadRequestHandle&& other);
+  UrlDownloadRequestHandle& operator=(UrlDownloadRequestHandle&& other);
+  ~UrlDownloadRequestHandle() override;
+
+  // DownloadRequestHandleInterface
+  void PauseRequest() override;
+  void ResumeRequest() override;
+  void CancelRequest(bool user_cancel) override;
+
+ private:
+  base::WeakPtr<UrlDownloadHandler> downloader_;
+  scoped_refptr<base::SequencedTaskRunner> downloader_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlDownloadRequestHandle);
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_URL_DOWNLOAD_REQUEST_HANDLE_H_
diff --git a/components/feed/features.gni b/components/feed/features.gni
index 73f73c7..d61856bd8 100644
--- a/components/feed/features.gni
+++ b/components/feed/features.gni
@@ -3,5 +3,6 @@
 # found in the LICENSE file.
 
 declare_args() {
-  enable_feed_in_chrome = is_android
+  # Temporarily compile out Feed while M69 branches to avoid bloating binary.
+  enable_feed_in_chrome = false
 }
diff --git a/components/history/content/browser/content_history_backend_db_unittest.cc b/components/history/content/browser/content_history_backend_db_unittest.cc
index ecac62e..d189ba0 100644
--- a/components/history/content/browser/content_history_backend_db_unittest.cc
+++ b/components/history/content/browser/content_history_backend_db_unittest.cc
@@ -77,6 +77,7 @@
     {"SERVER_FORBIDDEN", 36},
     {"SERVER_UNREACHABLE", 37},
     {"SERVER_CONTENT_LENGTH_MISMATCH", 38},
+    {"SERVER_CROSS_ORIGIN_REDIRECT", 39},
     {"USER_CANCELED", 40},
     {"USER_SHUTDOWN", 41},
     {"CRASH", 50},
diff --git a/components/ntp_tiles/constants.cc b/components/ntp_tiles/constants.cc
index 8604e84..3def594 100644
--- a/components/ntp_tiles/constants.cc
+++ b/components/ntp_tiles/constants.cc
@@ -40,7 +40,7 @@
 #endif
 }
 
-bool IsMDCustomLinksEnabled() {
+bool IsCustomLinksEnabled() {
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   return base::FeatureList::IsEnabled(kNtpCustomLinks) ||
          base::FeatureList::IsEnabled(features::kExperimentalUi);
diff --git a/components/ntp_tiles/constants.h b/components/ntp_tiles/constants.h
index 36c923c..508f456 100644
--- a/components/ntp_tiles/constants.h
+++ b/components/ntp_tiles/constants.h
@@ -40,7 +40,7 @@
 bool IsMDIconsEnabled();
 
 // Returns whether the custom links is enabled.
-bool IsMDCustomLinksEnabled();
+bool IsCustomLinksEnabled();
 
 }  // namespace ntp_tiles
 
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index 8ed638e..5c63d5e 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -572,7 +572,7 @@
 
 void MostVisitedSites::BuildCustomLinks(
     const std::vector<CustomLinksManager::Link>& links) {
-  DCHECK(IsMDCustomLinksEnabled());
+  DCHECK(IsCustomLinksEnabled());
 
   NTPTilesVector tiles;
   size_t num_tiles = std::min(links.size(), max_num_sites_);
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 1325b60..c0613901 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -72,6 +72,10 @@
     "clipboard_url_provider.h",
     "contextual_suggestions_service.cc",
     "contextual_suggestions_service.h",
+    "document_provider.cc",
+    "document_provider.h",
+    "document_suggestions_service.cc",
+    "document_suggestions_service.h",
     "favicon_cache.cc",
     "favicon_cache.h",
     "history_match.cc",
@@ -298,6 +302,7 @@
     "bookmark_provider_unittest.cc",
     "builtin_provider_unittest.cc",
     "clipboard_url_provider_unittest.cc",
+    "document_provider_unittest.cc",
     "favicon_cache_unittest.cc",
     "history_provider_unittest.cc",
     "history_quick_provider_unittest.cc",
diff --git a/components/omnibox/browser/autocomplete_classifier.cc b/components/omnibox/browser/autocomplete_classifier.cc
index 3b6df6b..36d709fc 100644
--- a/components/omnibox/browser/autocomplete_classifier.cc
+++ b/components/omnibox/browser/autocomplete_classifier.cc
@@ -13,6 +13,7 @@
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_provider.h"
+#include "components/omnibox/browser/document_provider.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "url/gurl.h"
@@ -44,6 +45,9 @@
       (base::FeatureList::IsEnabled(omnibox::kEnableClipboardProvider)
            ? AutocompleteProvider::TYPE_CLIPBOARD_URL
            : 0) |
+      (base::FeatureList::IsEnabled(omnibox::kDocumentProvider)
+           ? AutocompleteProvider::TYPE_DOCUMENT
+           : 0) |
       AutocompleteProvider::TYPE_BOOKMARK | AutocompleteProvider::TYPE_BUILTIN |
       AutocompleteProvider::TYPE_HISTORY_QUICK |
       AutocompleteProvider::TYPE_HISTORY_URL |
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc
index 08bf4a0..7865d5b 100644
--- a/components/omnibox/browser/autocomplete_controller.cc
+++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -29,6 +29,7 @@
 #include "components/omnibox/browser/bookmark_provider.h"
 #include "components/omnibox/browser/builtin_provider.h"
 #include "components/omnibox/browser/clipboard_url_provider.h"
+#include "components/omnibox/browser/document_provider.h"
 #include "components/omnibox/browser/history_quick_provider.h"
 #include "components/omnibox/browser/history_url_provider.h"
 #include "components/omnibox/browser/keyword_provider.h"
@@ -200,6 +201,7 @@
     int provider_types)
     : delegate_(delegate),
       provider_client_(std::move(provider_client)),
+      document_provider_(nullptr),
       history_url_provider_(nullptr),
       keyword_provider_(nullptr),
       search_provider_(nullptr),
@@ -237,6 +239,10 @@
     if (zero_suggest_provider_)
       providers_.push_back(zero_suggest_provider_);
   }
+  if (provider_types & AutocompleteProvider::TYPE_DOCUMENT) {
+    document_provider_ = DocumentProvider::Create(provider_client_.get(), this);
+    providers_.push_back(document_provider_);
+  }
   if (provider_types & AutocompleteProvider::TYPE_CLIPBOARD_URL) {
 #if !defined(OS_IOS)
     // On iOS, a global ClipboardRecentContent should've been created by now
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 0490ffe..ecc0c3f 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -23,6 +23,7 @@
 #include "components/omnibox/browser/autocomplete_result.h"
 
 class AutocompleteControllerDelegate;
+class DocumentProvider;
 class HistoryURLProvider;
 class KeywordProvider;
 class SearchProvider;
@@ -216,6 +217,8 @@
   // A list of all providers.
   Providers providers_;
 
+  DocumentProvider* document_provider_;
+
   HistoryURLProvider* history_url_provider_;
 
   KeywordProvider* keyword_provider_;
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index fb36902..ed1689f 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -223,6 +223,7 @@
     case Type::PHYSICAL_WEB_DEPRECATED:
     case Type::PHYSICAL_WEB_OVERFLOW_DEPRECATED:
     case Type::TAB_SEARCH_DEPRECATED:
+    case Type::DOCUMENT_SUGGESTION:
       if (is_refresh_ui)
         return omnibox::kMdPageIcon;
       else if (is_touch_ui)
diff --git a/components/omnibox/browser/autocomplete_match_type.cc b/components/omnibox/browser/autocomplete_match_type.cc
index 65145ee2..18e4e5db 100644
--- a/components/omnibox/browser/autocomplete_match_type.cc
+++ b/components/omnibox/browser/autocomplete_match_type.cc
@@ -41,6 +41,7 @@
     "physical-web",
     "physical-web-overflow",
     "tab-search",
+    "document",
   };
   // clang-format on
   static_assert(arraysize(strings) == AutocompleteMatchType::NUM_TYPES,
@@ -98,6 +99,7 @@
       0,                               // PHYSICAL_WEB_DEPRECATED
       0,                               // PHYSICAL_WEB_OVERFLOW_DEPRECATED
       IDS_ACC_AUTOCOMPLETE_HISTORY,    // TAB_SEARCH_DEPRECATED
+      0,                               // DOCUMENT_SUGGESTION
   };
   static_assert(arraysize(message_ids) == AutocompleteMatchType::NUM_TYPES,
                 "message_ids must have NUM_TYPES elements");
diff --git a/components/omnibox/browser/autocomplete_match_type.h b/components/omnibox/browser/autocomplete_match_type.h
index fbc8f58..9c0684596 100644
--- a/components/omnibox/browser/autocomplete_match_type.h
+++ b/components/omnibox/browser/autocomplete_match_type.h
@@ -63,6 +63,7 @@
                                        // (deprecated).
     TAB_SEARCH_DEPRECATED       = 23,  // A suggested open tab, based on its
                                        // URL or title, via HQP (deprecated).
+    DOCUMENT_SUGGESTION         = 24,  // A suggested document.
     NUM_TYPES,
   };
   // clang-format on
diff --git a/components/omnibox/browser/autocomplete_provider.cc b/components/omnibox/browser/autocomplete_provider.cc
index 755da299b..7ff72b3 100644
--- a/components/omnibox/browser/autocomplete_provider.cc
+++ b/components/omnibox/browser/autocomplete_provider.cc
@@ -30,6 +30,8 @@
       return "Bookmark";
     case TYPE_BUILTIN:
       return "Builtin";
+    case TYPE_DOCUMENT:
+      return "Document";
     case TYPE_HISTORY_QUICK:
       return "HistoryQuick";
     case TYPE_HISTORY_URL:
@@ -66,6 +68,8 @@
       return metrics::OmniboxEventProto::BOOKMARK;
     case TYPE_BUILTIN:
       return metrics::OmniboxEventProto::BUILTIN;
+    case TYPE_DOCUMENT:
+      return metrics::OmniboxEventProto::DOCUMENT;
     case TYPE_HISTORY_QUICK:
       return metrics::OmniboxEventProto::HISTORY_QUICK;
     case TYPE_HISTORY_URL:
diff --git a/components/omnibox/browser/autocomplete_provider.h b/components/omnibox/browser/autocomplete_provider.h
index 1ecf01e4..57e3886 100644
--- a/components/omnibox/browser/autocomplete_provider.h
+++ b/components/omnibox/browser/autocomplete_provider.h
@@ -63,6 +63,7 @@
 // Search Secondary Provider (past query in history)                   |  200*
 // Search Secondary Provider (navigational suggestion)                 |  150++
 // Search Secondary Provider (suggestion)                              |  100++
+// Document Suggestions (*experimental): value controlled by Finch     |    *
 //
 // URL input type:
 // --------------------------------------------------------------------|-----
@@ -130,15 +131,16 @@
  public:
   // Different AutocompleteProvider implementations.
   enum Type {
-    TYPE_BOOKMARK         = 1 << 0,
-    TYPE_BUILTIN          = 1 << 1,
-    TYPE_HISTORY_QUICK    = 1 << 2,
-    TYPE_HISTORY_URL      = 1 << 3,
-    TYPE_KEYWORD          = 1 << 4,
-    TYPE_SEARCH           = 1 << 5,
-    TYPE_SHORTCUTS        = 1 << 6,
-    TYPE_ZERO_SUGGEST     = 1 << 7,
-    TYPE_CLIPBOARD_URL    = 1 << 8,
+    TYPE_BOOKMARK = 1 << 0,
+    TYPE_BUILTIN = 1 << 1,
+    TYPE_HISTORY_QUICK = 1 << 2,
+    TYPE_HISTORY_URL = 1 << 3,
+    TYPE_KEYWORD = 1 << 4,
+    TYPE_SEARCH = 1 << 5,
+    TYPE_SHORTCUTS = 1 << 6,
+    TYPE_ZERO_SUGGEST = 1 << 7,
+    TYPE_CLIPBOARD_URL = 1 << 8,
+    TYPE_DOCUMENT = 1 << 9,
   };
 
   explicit AutocompleteProvider(Type type);
diff --git a/components/omnibox/browser/autocomplete_provider_client.h b/components/omnibox/browser/autocomplete_provider_client.h
index bfbc474..fd907dca 100644
--- a/components/omnibox/browser/autocomplete_provider_client.h
+++ b/components/omnibox/browser/autocomplete_provider_client.h
@@ -22,6 +22,7 @@
 class AutocompleteClassifier;
 class AutocompleteSchemeClassifier;
 class ContextualSuggestionsService;
+class DocumentSuggestionsService;
 class GURL;
 class InMemoryURLIndex;
 class KeywordProvider;
@@ -62,6 +63,8 @@
   virtual const TemplateURLService* GetTemplateURLService() const = 0;
   virtual ContextualSuggestionsService* GetContextualSuggestionsService(
       bool create_if_necessary) const = 0;
+  virtual DocumentSuggestionsService* GetDocumentSuggestionsService(
+      bool create_if_necessary) const = 0;
   virtual const SearchTermsData& GetSearchTermsData() const = 0;
   virtual scoped_refptr<ShortcutsBackend> GetShortcutsBackend() = 0;
   virtual scoped_refptr<ShortcutsBackend> GetShortcutsBackendIfExists() = 0;
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc
new file mode 100644
index 0000000..7a3c2f41
--- /dev/null
+++ b/components/omnibox/browser/document_provider.cc
@@ -0,0 +1,240 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/omnibox/browser/document_provider.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/json/json_reader.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/autocomplete_provider_client.h"
+#include "components/omnibox/browser/autocomplete_provider_listener.h"
+#include "components/omnibox/browser/document_suggestions_service.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/omnibox/browser/search_provider.h"
+#include "components/prefs/pref_service.h"
+#include "components/search_engines/search_engine_type.h"
+#include "components/search_engines/template_url_service.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
+#include "url/gurl.h"
+
+namespace {
+// TODO(skare): Pull the enum in search_provider.cc into its .h file, and switch
+// this file and zero_suggest_provider.cc to use it.
+enum DocumentRequestsHistogramValue {
+  DOCUMENT_REQUEST_SENT = 1,
+  DOCUMENT_REQUEST_INVALIDATED = 2,
+  DOCUMENT_REPLY_RECEIVED = 3,
+  DOCUMENT_MAX_REQUEST_HISTOGRAM_VALUE
+};
+
+void LogOmniboxDocumentRequest(DocumentRequestsHistogramValue request_value) {
+  UMA_HISTOGRAM_ENUMERATION("Omnibox.DocumentSuggest.Requests", request_value,
+                            DOCUMENT_MAX_REQUEST_HISTOGRAM_VALUE);
+}
+
+}  // namespace
+
+// static
+DocumentProvider* DocumentProvider::Create(
+    AutocompleteProviderClient* client,
+    AutocompleteProviderListener* listener) {
+  return new DocumentProvider(client, listener);
+}
+
+bool DocumentProvider::IsDocumentProviderAllowed(
+    PrefService* prefs,
+    bool is_incognito,
+    bool is_authenticated,
+    const TemplateURLService* template_url_service) {
+  // Feature must be on.
+  if (!base::FeatureList::IsEnabled(omnibox::kDocumentProvider))
+    return false;
+
+  // No incognito.
+  if (is_incognito)
+    return false;
+
+  // User must be signed in.
+  if (!is_authenticated)
+    return false;
+
+  // Google must be set as default search provider; we mix results which may
+  // change placement.
+  if (template_url_service == nullptr)
+    return false;
+  const TemplateURL* default_provider =
+      template_url_service->GetDefaultSearchProvider();
+  return default_provider != nullptr &&
+         default_provider->GetEngineType(
+             template_url_service->search_terms_data()) == SEARCH_ENGINE_GOOGLE;
+}
+
+void DocumentProvider::Start(const AutocompleteInput& input,
+                             bool minimal_changes) {
+  TRACE_EVENT0("omnibox", "DocumentProvider::Start");
+  matches_.clear();
+
+  // TODO(skare): get from identitymanager, to short-circuit sooner.
+  bool is_authenticated = true;
+  if (!IsDocumentProviderAllowed(client_->GetPrefs(), client_->IsOffTheRecord(),
+                                 is_authenticated,
+                                 client_->GetTemplateURLService())) {
+    return;
+  }
+
+  // We currently only provide asynchronous matches.
+  if (!input.want_asynchronous_matches()) {
+    return;
+  }
+
+  Stop(true, false);
+
+  // Create a request for suggestions, routing completion to
+  base::BindOnce(&DocumentProvider::OnDocumentSuggestionsLoaderAvailable,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(&DocumentProvider::OnURLLoadComplete,
+                     base::Unretained(this) /* own SimpleURLLoader */);
+
+  done_ = false;  // Set true in callbacks.
+  client_->GetDocumentSuggestionsService(/*create_if_necessary=*/true)
+      ->CreateDocumentSuggestionsRequest(
+          input.text(), client_->GetTemplateURLService(),
+          base::BindOnce(
+              &DocumentProvider::OnDocumentSuggestionsLoaderAvailable,
+              weak_ptr_factory_.GetWeakPtr()),
+          base::BindOnce(
+              &DocumentProvider::OnURLLoadComplete,
+              base::Unretained(this) /* this owns SimpleURLLoader */));
+}
+
+void DocumentProvider::Stop(bool clear_cached_results,
+                            bool due_to_user_inactivity) {
+  TRACE_EVENT0("omnibox", "DocumentProvider::Stop");
+  if (loader_)
+    LogOmniboxDocumentRequest(DOCUMENT_REQUEST_INVALIDATED);
+  loader_.reset();
+  auto* document_suggestions_service =
+      client_->GetDocumentSuggestionsService(/*create_if_necessary=*/false);
+  if (document_suggestions_service != nullptr) {
+    document_suggestions_service->StopCreatingDocumentSuggestionsRequest();
+  }
+
+  done_ = true;
+
+  if (clear_cached_results) {
+    matches_.clear();
+  }
+}
+
+void DocumentProvider::DeleteMatch(const AutocompleteMatch& match) {
+  // Not supported by this provider.
+  return;
+}
+
+void DocumentProvider::AddProviderInfo(ProvidersInfo* provider_info) const {
+  // TODO(skare): Verify that we don't lose metrics based on what
+  // zero_suggest_provider and BaseSearchProvider add.
+  return;
+}
+
+DocumentProvider::DocumentProvider(AutocompleteProviderClient* client,
+                                   AutocompleteProviderListener* listener)
+    : AutocompleteProvider(AutocompleteProvider::TYPE_DOCUMENT),
+      client_(client),
+      listener_(listener),
+      weak_ptr_factory_(this) {}
+
+DocumentProvider::~DocumentProvider() {}
+
+void DocumentProvider::OnURLLoadComplete(
+    const network::SimpleURLLoader* source,
+    std::unique_ptr<std::string> response_body) {
+  DCHECK(!done_);
+  DCHECK_EQ(loader_.get(), source);
+
+  LogOmniboxDocumentRequest(DOCUMENT_REPLY_RECEIVED);
+
+  const bool results_updated =
+      response_body && source->NetError() == net::OK &&
+      (source->ResponseInfo() && source->ResponseInfo()->headers &&
+       source->ResponseInfo()->headers->response_code() == 200) &&
+      UpdateResults(SearchSuggestionParser::ExtractJsonData(
+          source, std::move(response_body)));
+  loader_.reset();
+  done_ = true;
+  listener_->OnProviderUpdate(results_updated);
+}
+
+bool DocumentProvider::UpdateResults(const std::string& json_data) {
+  std::unique_ptr<base::DictionaryValue> response =
+      base::DictionaryValue::From(base::JSONReader::Read(json_data));
+  if (!response)
+    return false;
+
+  return ParseDocumentSearchResults(*response, &matches_);
+}
+
+void DocumentProvider::OnDocumentSuggestionsLoaderAvailable(
+    std::unique_ptr<network::SimpleURLLoader> loader) {
+  loader_ = std::move(loader);
+  LogOmniboxDocumentRequest(DOCUMENT_REQUEST_SENT);
+}
+
+bool DocumentProvider::ParseDocumentSearchResults(const base::Value& root_val,
+                                                  ACMatches* matches) {
+  const base::DictionaryValue* root_dict = nullptr;
+  const base::ListValue* results_list = nullptr;
+  if (!root_val.GetAsDictionary(&root_dict)) {
+    return false;
+  }
+  if (!root_dict->GetList("results", &results_list)) {
+    return false;
+  }
+  size_t num_results = results_list->GetSize();
+  UMA_HISTOGRAM_COUNTS("Omnibox.DocumentSuggest.ResultCount", num_results);
+
+  // Clear the previous results now that new results are available.
+  matches->clear();
+  for (size_t i = 0; i < num_results; i++) {
+    const base::DictionaryValue* result = nullptr;
+    if (!results_list->GetDictionary(i, &result)) {
+      return false;
+    }
+    base::string16 title;
+    base::string16 url;
+    result->GetString("title", &title);
+    result->GetString("url", &url);
+    if (title.empty() || url.empty()) {
+      continue;
+    }
+    // Create a synthetic score. Eventually we'll have signals from the API.
+    // For now, first result gets some max store, subsequent results are
+    // penalized incrementally and linearly.
+    // TODO(skare): Use experiment params once a formal study file exists.
+    const unsigned int baseValue = 1100;
+    const int penalty = 100;
+    int relevance = baseValue - i * penalty;
+    AutocompleteMatch match(this, relevance, false,
+                            AutocompleteMatchType::DOCUMENT_SUGGESTION);
+    match.destination_url = GURL(url);
+    match.contents = title;
+    match.transition = ui::PAGE_TRANSITION_GENERATED;
+    matches->push_back(match);
+  }
+  return true;
+}
diff --git a/components/omnibox/browser/document_provider.h b/components/omnibox/browser/document_provider.h
new file mode 100644
index 0000000..42cc5cf0
--- /dev/null
+++ b/components/omnibox/browser/document_provider.h
@@ -0,0 +1,99 @@
+// 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.
+//
+// This file contains the document autocomplete provider. This experimental
+// provider uses an experimental API with keys and endpoint provided at
+// developer build-time, so it is feature-flagged off by default.
+
+#ifndef COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_PROVIDER_H_
+#define COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_PROVIDER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/omnibox/browser/autocomplete_provider.h"
+#include "components/omnibox/browser/search_provider.h"
+#include "third_party/metrics_proto/omnibox_event.pb.h"
+
+class AutocompleteProviderListener;
+class AutocompleteProviderClient;
+class PrefService;
+
+namespace base {
+class Value;
+}
+
+namespace network {
+class SimpleURLLoader;
+}
+
+// Autocomplete provider for personalized documents owned or readable by the
+// signed-in user. In practice this is a second request in parallel with that
+// to the default search provider.
+class DocumentProvider : public AutocompleteProvider {
+ public:
+  // Creates and returns an instance of this provider.
+  static DocumentProvider* Create(AutocompleteProviderClient* client,
+                                  AutocompleteProviderListener* listener);
+
+  // AutocompleteProvider:
+  void Start(const AutocompleteInput& input, bool minimal_changes) override;
+  void Stop(bool clear_cached_results, bool due_to_user_inactivity) override;
+  void DeleteMatch(const AutocompleteMatch& match) override;
+  void AddProviderInfo(ProvidersInfo* provider_info) const override;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(DocumentProviderTest, CheckFeatureBehindFlag);
+  FRIEND_TEST_ALL_PREFIXES(DocumentProviderTest, CheckFeaturePrerequisites);
+  FRIEND_TEST_ALL_PREFIXES(DocumentProviderTest, ParseDocumentSearchResults);
+  DocumentProvider(AutocompleteProviderClient* client,
+                   AutocompleteProviderListener* listener);
+
+  ~DocumentProvider() override;
+
+  // Using this provider requires the user is signed-in and has Google set as
+  // default search engine.
+  bool IsDocumentProviderAllowed(
+      PrefService* prefs,
+      bool is_incognito,
+      bool is_authenticated,
+      const TemplateURLService* template_url_service);
+
+  // Called when loading is complete.
+  void OnURLLoadComplete(const network::SimpleURLLoader* source,
+                         std::unique_ptr<std::string> response_body);
+
+  // The function updates |matches_| with data parsed from |json_data|.
+  // The update is not performed if |json_data| is invalid.
+  // Returns whether |matches_| changed.
+  bool UpdateResults(const std::string& json_data);
+
+  // Callback for when the loader is available with a valid token.
+  void OnDocumentSuggestionsLoaderAvailable(
+      std::unique_ptr<network::SimpleURLLoader> loader);
+
+  // Parses document search result JSON.
+  bool ParseDocumentSearchResults(const base::Value& root_val,
+                                  ACMatches* matches);
+
+  // Client for accessing TemplateUrlService, prefs, etc.
+  AutocompleteProviderClient* client_;
+
+  // Listener to notify when results are available.
+  AutocompleteProviderListener* listener_;
+
+  // Loader used to retrieve results.
+  std::unique_ptr<network::SimpleURLLoader> loader_;
+
+  // For callbacks that may be run after destruction. Must be declared last.
+  base::WeakPtrFactory<DocumentProvider> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DocumentProvider);
+};
+
+#endif  // COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_PROVIDER_H_
diff --git a/components/omnibox/browser/document_provider_unittest.cc b/components/omnibox/browser/document_provider_unittest.cc
new file mode 100644
index 0000000..21a77c0
--- /dev/null
+++ b/components/omnibox/browser/document_provider_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/omnibox/browser/document_provider.h"
+
+#include "base/json/json_reader.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/values.h"
+#include "components/omnibox/browser/autocomplete_provider.h"
+#include "components/omnibox/browser/autocomplete_provider_listener.h"
+#include "components/omnibox/browser/mock_autocomplete_provider_client.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class FakeAutocompleteProviderClient : public MockAutocompleteProviderClient {
+ public:
+  FakeAutocompleteProviderClient()
+      : template_url_service_(new TemplateURLService(nullptr, 0)) {}
+
+  bool SearchSuggestEnabled() const override { return true; }
+
+  TemplateURLService* GetTemplateURLService() override {
+    return template_url_service_.get();
+  }
+
+  TemplateURLService* GetTemplateURLService() const override {
+    return template_url_service_.get();
+  }
+
+  PrefService* GetPrefs() override { return &pref_service_; }
+
+ private:
+  std::unique_ptr<TemplateURLService> template_url_service_;
+  TestingPrefServiceSimple pref_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeAutocompleteProviderClient);
+};
+
+}  // namespace
+
+class DocumentProviderTest : public testing::Test,
+                             public AutocompleteProviderListener {
+ public:
+  DocumentProviderTest();
+
+  void SetUp() override;
+
+ protected:
+  // AutocompleteProviderListener:
+  void OnProviderUpdate(bool updated_matches) override;
+
+  std::unique_ptr<FakeAutocompleteProviderClient> client_;
+  scoped_refptr<DocumentProvider> provider_;
+  TemplateURL* default_template_url_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DocumentProviderTest);
+};
+
+DocumentProviderTest::DocumentProviderTest() {}
+
+void DocumentProviderTest::SetUp() {
+  client_.reset(new FakeAutocompleteProviderClient());
+
+  TemplateURLService* turl_model = client_->GetTemplateURLService();
+  turl_model->Load();
+
+  TemplateURLData data;
+  data.SetShortName(base::ASCIIToUTF16("t"));
+  data.SetURL("https://www.google.com/?q={searchTerms}");
+  data.suggestions_url = "https://www.google.com/complete/?q={searchTerms}";
+  default_template_url_ = turl_model->Add(std::make_unique<TemplateURL>(data));
+  turl_model->SetUserSelectedDefaultSearchProvider(default_template_url_);
+
+  provider_ = DocumentProvider::Create(client_.get(), this);
+}
+
+void DocumentProviderTest::OnProviderUpdate(bool updated_matches) {
+  // No action required.
+}
+
+TEST_F(DocumentProviderTest, CheckFeatureBehindFlag) {
+  PrefService* fake_prefs = client_->GetPrefs();
+  TemplateURLService* template_url_service = client_->GetTemplateURLService();
+  bool is_incognito = false;
+  bool is_authenticated = true;
+
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(omnibox::kDocumentProvider);
+  EXPECT_FALSE(provider_->IsDocumentProviderAllowed(
+      fake_prefs, is_incognito, is_authenticated, template_url_service));
+}
+
+TEST_F(DocumentProviderTest, CheckFeaturePrerequisites) {
+  PrefService* fake_prefs = client_->GetPrefs();
+  TemplateURLService* template_url_service = client_->GetTemplateURLService();
+
+  // Make sure feature is turned on when prereqs are met, then turn them off
+  // one at a time and ensure each defeats the feature.
+  bool is_incognito = false;
+  bool is_authenticated = true;
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(omnibox::kDocumentProvider);
+  EXPECT_TRUE(provider_->IsDocumentProviderAllowed(
+      fake_prefs, is_incognito, is_authenticated, template_url_service));
+
+  // Don't allow in incognito mode.
+  is_incognito = true;
+  EXPECT_FALSE(provider_->IsDocumentProviderAllowed(
+      fake_prefs, is_incognito, is_authenticated, template_url_service));
+  is_incognito = false;
+
+  // Don't allow if Google is not DSE.
+  TemplateURLData data;
+  data.SetShortName(base::ASCIIToUTF16("t"));
+  data.SetURL("https://www.notgoogle.com/?q={searchTerms}");
+  data.suggestions_url = "https://www.notgoogle.com/complete/?q={searchTerms}";
+  TemplateURL* new_default_provider =
+      template_url_service->Add(std::make_unique<TemplateURL>(data));
+  template_url_service->SetUserSelectedDefaultSearchProvider(
+      new_default_provider);
+  EXPECT_FALSE(provider_->IsDocumentProviderAllowed(
+      fake_prefs, is_incognito, is_authenticated, template_url_service));
+  template_url_service->SetUserSelectedDefaultSearchProvider(
+      default_template_url_);
+  template_url_service->Remove(new_default_provider);
+
+  // Prereqs are met again; verify we're able to get suggestions.
+  EXPECT_TRUE(provider_->IsDocumentProviderAllowed(
+      fake_prefs, is_incognito, is_authenticated, template_url_service));
+}
+
+TEST_F(DocumentProviderTest, ParseDocumentSearchResults) {
+  const char kGoodJSONResponse[] = R"({
+      "results": [
+        {
+          "title": "Document 1",
+          "url": "https://documentprovider.tld/doc?id=1"
+        },
+        {
+          "title": "Document 2",
+          "url": "https://documentprovider.tld/doc?id=2"
+        }
+      ]
+     })";
+
+  std::unique_ptr<base::DictionaryValue> response =
+      base::DictionaryValue::From(base::JSONReader::Read(kGoodJSONResponse));
+  ASSERT_TRUE(response != nullptr);
+
+  ACMatches matches;
+  provider_->ParseDocumentSearchResults(*response, &matches);
+  EXPECT_EQ(matches.size(), 2u);
+  EXPECT_EQ(matches[0].contents, base::ASCIIToUTF16("Document 1"));
+  EXPECT_EQ(matches[0].destination_url,
+            GURL("https://documentprovider.tld/doc?id=1"));
+  EXPECT_EQ(matches[1].contents, base::ASCIIToUTF16("Document 2"));
+  EXPECT_EQ(matches[1].destination_url,
+            GURL("https://documentprovider.tld/doc?id=2"));
+}
diff --git a/components/omnibox/browser/document_suggestions_service.cc b/components/omnibox/browser/document_suggestions_service.cc
new file mode 100644
index 0000000..7906a090
--- /dev/null
+++ b/components/omnibox/browser/document_suggestions_service.cc
@@ -0,0 +1,181 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/omnibox/browser/document_suggestions_service.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/feature_list.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/omnibox/browser/document_provider.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/variations/variations_associated_data.h"
+#include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace {
+
+// Builds a document search request body. Inputs are:
+//   |query|: Current query text.
+// The format of the request is:
+//     {
+//       query: "the search text",
+//       start: 0,
+//       pageSize: 10,
+//       sourceOptions: [{source: {predefinedSource: "GOOGLE_DRIVE"}}]
+//     }
+std::string BuildDocumentSuggestionRequest(const base::string16& query) {
+  base::Value root(base::Value::Type::DICTIONARY);
+  root.SetKey("query", base::Value(query));
+  root.SetKey("start", base::Value(0));
+  root.SetKey("pageSize", base::Value(10));
+
+  base::Value::ListStorage storage_options_list;
+  base::Value source_definition(base::Value::Type::DICTIONARY);
+  source_definition.SetPath({"source", "predefinedSource"},
+                            base::Value("GOOGLE_DRIVE"));
+  storage_options_list.emplace_back(std::move(source_definition));
+  root.SetKey("sourceOptions", base::Value(std::move(storage_options_list)));
+
+  std::string result;
+  base::JSONWriter::Write(root, &result);
+  return result;
+}
+
+}  // namespace
+
+DocumentSuggestionsService::DocumentSuggestionsService(
+    identity::IdentityManager* identity_manager,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : url_loader_factory_(url_loader_factory),
+      identity_manager_(identity_manager),
+      token_fetcher_(nullptr) {
+  DCHECK(url_loader_factory);
+}
+
+DocumentSuggestionsService::~DocumentSuggestionsService() {}
+
+void DocumentSuggestionsService::CreateDocumentSuggestionsRequest(
+    const base::string16& query,
+    const TemplateURLService* template_url_service,
+    StartCallback start_callback,
+    CompletionCallback completion_callback) {
+  std::string endpoint = variations::GetVariationParamValueByFeature(
+      omnibox::kDocumentProvider, "Endpoint");
+  const GURL suggest_url = GURL(endpoint);
+  DCHECK(suggest_url.is_valid());
+
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("omnibox_documentsuggest", R"(
+        semantics {
+          sender: "Omnibox"
+          description:
+            "Request for Google Drive document suggestions from the omnibox."
+            "User must be signed in and have default search provider set to "
+            "Google."
+          trigger: "Signed-in user enters text in the omnibox."
+          data: "The query string from the omnibox."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: YES
+          cookies_store: "user"
+          setting:
+            "Coupled to Google default search plus signed-in"
+          chrome_policy {
+            SearchSuggestEnabled {
+                policy_options {mode: MANDATORY}
+                SearchSuggestEnabled: false
+            }
+          }
+        })");
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = suggest_url;
+  request->method = "POST";
+  std::string request_body = BuildDocumentSuggestionRequest(query);
+  request->load_flags = net::LOAD_DO_NOT_SAVE_COOKIES;
+  // TODO(https://crbug.com/808498) re-add data use measurement once
+  // SimpleURLLoader supports it.
+  // We should attach data_use_measurement::DataUseUserData::OMNIBOX.
+  StartDownloadAndTransferLoader(std::move(request), std::string(),
+                                 traffic_annotation, std::move(start_callback),
+                                 std::move(completion_callback));
+
+  // TODO(skare): Include code to catch token fetch in-progress; otherwise
+  // we'll lose one set of results.
+
+  // Create and fetch an OAuth2 token.
+  std::string scope = base::GetFieldTrialParamValueByFeature(
+      omnibox::kDocumentProvider, "OAuth2Scope");
+  OAuth2TokenService::ScopeSet scopes;
+  scopes.insert(scope);
+  token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
+      "document_suggestions_service", identity_manager_, scopes,
+      base::BindOnce(&DocumentSuggestionsService::AccessTokenAvailable,
+                     base::Unretained(this), std::move(request),
+                     std::move(request_body), traffic_annotation,
+                     std::move(start_callback), std::move(completion_callback)),
+      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
+}
+
+void DocumentSuggestionsService::StopCreatingDocumentSuggestionsRequest() {
+  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
+      token_fetcher_deleter(std::move(token_fetcher_));
+}
+
+void DocumentSuggestionsService::AccessTokenAvailable(
+    std::unique_ptr<network::ResourceRequest> request,
+    std::string request_body,
+    net::NetworkTrafficAnnotationTag traffic_annotation,
+    StartCallback start_callback,
+    CompletionCallback completion_callback,
+    GoogleServiceAuthError error,
+    identity::AccessTokenInfo access_token_info) {
+  DCHECK(token_fetcher_);
+  token_fetcher_.reset();
+
+  // If there were no errors obtaining the access token, append it to the
+  // request as a header.
+  if (error.state() == GoogleServiceAuthError::NONE) {
+    DCHECK(!access_token_info.token.empty());
+    request->headers.SetHeader(
+        "Authorization",
+        base::StringPrintf("Bearer %s", access_token_info.token.c_str()));
+  }
+
+  StartDownloadAndTransferLoader(std::move(request), std::move(request_body),
+                                 traffic_annotation, std::move(start_callback),
+                                 std::move(completion_callback));
+}
+
+void DocumentSuggestionsService::StartDownloadAndTransferLoader(
+    std::unique_ptr<network::ResourceRequest> request,
+    std::string request_body,
+    net::NetworkTrafficAnnotationTag traffic_annotation,
+    StartCallback start_callback,
+    CompletionCallback completion_callback) {
+  std::unique_ptr<network::SimpleURLLoader> loader =
+      network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
+  if (!request_body.empty()) {
+    loader->AttachStringForUpload(request_body, "application/json");
+  }
+  loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory_.get(),
+      base::BindOnce(std::move(completion_callback), loader.get()));
+
+  std::move(start_callback).Run(std::move(loader));
+}
diff --git a/components/omnibox/browser/document_suggestions_service.h b/components/omnibox/browser/document_suggestions_service.h
new file mode 100644
index 0000000..960fff4
--- /dev/null
+++ b/components/omnibox/browser/document_suggestions_service.h
@@ -0,0 +1,86 @@
+// 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_OMNIBOX_BROWSER_DOCUMENT_SUGGESTIONS_SERVICE_H_
+#define COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_SUGGESTIONS_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "services/identity/public/cpp/access_token_info.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "url/gurl.h"
+
+namespace identity {
+class IdentityManager;
+class PrimaryAccountAccessTokenFetcher;
+}  // namespace identity
+
+class GoogleServiceAuthError;
+class TemplateURLService;
+
+// A service to fetch suggestions from a remote endpoint given a URL.
+class DocumentSuggestionsService : public KeyedService {
+ public:
+  // null may be passed for params, but no request will be issued.
+  DocumentSuggestionsService(
+      identity::IdentityManager* identity_manager,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+
+  ~DocumentSuggestionsService() override;
+
+  using StartCallback = base::OnceCallback<void(
+      std::unique_ptr<network::SimpleURLLoader> loader)>;
+
+  using CompletionCallback =
+      base::OnceCallback<void(const network::SimpleURLLoader* source,
+                              std::unique_ptr<std::string> response_body)>;
+
+  // Creates and starts a document suggestion request for |query|.
+  // May obtain an OAuth2 token for the signed-in user.
+  void CreateDocumentSuggestionsRequest(
+      const base::string16& query,
+      const TemplateURLService* template_url_service,
+      StartCallback start_callback,
+      CompletionCallback completion_callback);
+
+  // Advises the service to stop any process that creates a suggestion request.
+  void StopCreatingDocumentSuggestionsRequest();
+
+ private:
+  // Called when an access token request completes (successfully or not).
+  void AccessTokenAvailable(std::unique_ptr<network::ResourceRequest> request,
+                            std::string request_body,
+                            net::NetworkTrafficAnnotationTag traffic_annotation,
+                            StartCallback start_callback,
+                            CompletionCallback completion_callback,
+                            GoogleServiceAuthError error,
+                            identity::AccessTokenInfo access_token_info);
+
+  // Activates a loader for |request|, wiring it up to |completion_callback|,
+  // and calls |start_callback|. If |request_body| isn't empty, it will be
+  // attached as upload bytes.
+  void StartDownloadAndTransferLoader(
+      std::unique_ptr<network::ResourceRequest> request,
+      std::string request_body,
+      net::NetworkTrafficAnnotationTag traffic_annotation,
+      StartCallback start_callback,
+      CompletionCallback completion_callback);
+
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+  identity::IdentityManager* identity_manager_;
+
+  // Helper for fetching OAuth2 access tokens. Non-null when we have a token
+  // available, or while a token fetch is in progress.
+  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(DocumentSuggestionsService);
+};
+
+#endif  // COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_SUGGESTIONS_SERVICE_H_
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.cc b/components/omnibox/browser/mock_autocomplete_provider_client.cc
index 87d0e24..3ea1bb7 100644
--- a/components/omnibox/browser/mock_autocomplete_provider_client.cc
+++ b/components/omnibox/browser/mock_autocomplete_provider_client.cc
@@ -14,6 +14,8 @@
   contextual_suggestions_service_ =
       std::make_unique<ContextualSuggestionsService>(
           /*identity_manager=*/nullptr, GetURLLoaderFactory());
+  document_suggestions_service_ = std::make_unique<DocumentSuggestionsService>(
+      /*identity_manager=*/nullptr, GetURLLoaderFactory());
 }
 
 MockAutocompleteProviderClient::~MockAutocompleteProviderClient() {
diff --git a/components/omnibox/browser/mock_autocomplete_provider_client.h b/components/omnibox/browser/mock_autocomplete_provider_client.h
index 2c5b267..cc9db66 100644
--- a/components/omnibox/browser/mock_autocomplete_provider_client.h
+++ b/components/omnibox/browser/mock_autocomplete_provider_client.h
@@ -14,6 +14,7 @@
 #include "components/omnibox/browser/autocomplete_provider_client.h"
 #include "components/omnibox/browser/autocomplete_scheme_classifier.h"
 #include "components/omnibox/browser/contextual_suggestions_service.h"
+#include "components/omnibox/browser/document_suggestions_service.h"
 #include "components/search_engines/search_terms_data.h"
 #include "components/search_engines/template_url_service.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -56,6 +57,10 @@
       bool create_if_necessary) const override {
     return contextual_suggestions_service_.get();
   }
+  DocumentSuggestionsService* GetDocumentSuggestionsService(
+      bool create_if_necessary) const override {
+    return document_suggestions_service_.get();
+  }
 
   MOCK_CONST_METHOD0(GetSearchTermsData, const SearchTermsData&());
 
@@ -110,6 +115,7 @@
   scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
 
   std::unique_ptr<ContextualSuggestionsService> contextual_suggestions_service_;
+  std::unique_ptr<DocumentSuggestionsService> document_suggestions_service_;
   std::unique_ptr<TemplateURLService> template_url_service_;
 
   DISALLOW_COPY_AND_ASSIGN(MockAutocompleteProviderClient);
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 5df1f24..8d10885 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -143,6 +143,9 @@
 const base::Feature kBreakWordsAtUnderscores{"OmniboxBreakWordsAtUnderscores",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature used to fetch document suggestions.
+const base::Feature kDocumentProvider{"OmniboxDocumentProvider",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
 }  // namespace omnibox
 
 namespace {
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 6fadbaf1..f209b72 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -43,6 +43,7 @@
 extern const base::Feature kUIExperimentVerticalMargin;
 extern const base::Feature kSpeculativeServiceWorkerStartOnQueryInput;
 extern const base::Feature kBreakWordsAtUnderscores;
+extern const base::Feature kDocumentProvider;
 
 }  // namespace omnibox
 
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc
index 6d360b6..f6043a05 100644
--- a/components/omnibox/browser/omnibox_metrics_provider.cc
+++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -64,6 +64,8 @@
       return OmniboxEventProto::Suggestion::NAVSUGGEST_PERSONALIZED;
     case AutocompleteMatchType::CLIPBOARD:
       return OmniboxEventProto::Suggestion::CLIPBOARD;
+    case AutocompleteMatchType::DOCUMENT_SUGGESTION:
+      return OmniboxEventProto::Suggestion::DOCUMENT;
     case AutocompleteMatchType::VOICE_SUGGEST:
       // VOICE_SUGGEST matches are only used in Java and are not logged,
       // so we should never reach this case.
diff --git a/components/password_manager/content/common/credential_manager_mojom_traits.cc b/components/password_manager/content/common/credential_manager_mojom_traits.cc
index 78e6a2c..21cbdedd 100644
--- a/components/password_manager/content/common/credential_manager_mojom_traits.cc
+++ b/components/password_manager/content/common/credential_manager_mojom_traits.cc
@@ -85,11 +85,11 @@
           password_manager::CredentialManagerError::PASSWORDSTOREUNAVAILABLE;
       return true;
     case blink::mojom::CredentialManagerError::NOT_ALLOWED:
+    case blink::mojom::CredentialManagerError::ANDROID_NOT_SUPPORTED_ERROR:
+    case blink::mojom::CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED:
+    case blink::mojom::CredentialManagerError::ANDROID_EMPTY_ALLOW_CREDENTIALS:
     case blink::mojom::CredentialManagerError::
-        AUTHENTICATOR_CRITERIA_UNSUPPORTED:
-    case blink::mojom::CredentialManagerError::ALGORITHM_UNSUPPORTED:
-    case blink::mojom::CredentialManagerError::EMPTY_ALLOW_CREDENTIALS:
-    case blink::mojom::CredentialManagerError::USER_VERIFICATION_UNSUPPORTED:
+        ANDROID_USER_VERIFICATION_UNSUPPORTED:
     case blink::mojom::CredentialManagerError::INVALID_DOMAIN:
     case blink::mojom::CredentialManagerError::CREDENTIAL_EXCLUDED:
     case blink::mojom::CredentialManagerError::CREDENTIAL_NOT_RECOGNIZED:
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc
index 20a2c46..cc572c83 100644
--- a/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -48,6 +48,12 @@
     "PasswordProtection.Verdict.NonGaiaEnterprisePasswordEntry";
 const char kGSuiteSyncPasswordEntryVerdictHistogram[] =
     "PasswordProtection.Verdict.GSuiteSyncPasswordEntry";
+const char kReferrerChainSizeOfSafeVerdictHistogram[] =
+    "PasswordProtection.ReferrerChainSize.Safe";
+const char kReferrerChainSizeOfPhishingVerdictHistogram[] =
+    "PasswordProtection.ReferrerChainSize.Phishing";
+const char kReferrerChainSizeOfLowRepVerdictHistogram[] =
+    "PasswordProtection.ReferrerChainSize.LowReputation";
 
 PasswordProtectionRequest::PasswordProtectionRequest(
     WebContents* web_contents,
@@ -403,6 +409,11 @@
       default:
         NOTREACHED();
     }
+    int referrer_chain_size =
+        request_proto_->frames_size() > 0
+            ? request_proto_->frames(0).referrer_chain_size()
+            : 0;
+    LogReferrerChainSize(response->verdict_type(), referrer_chain_size);
   }
 
   password_protection_service_->RequestFinished(
@@ -433,4 +444,26 @@
   throttles_.clear();
 }
 
+void PasswordProtectionRequest::LogReferrerChainSize(
+    LoginReputationClientResponse::VerdictType verdict_type,
+    int referrer_chain_size) {
+  switch (verdict_type) {
+    case LoginReputationClientResponse::SAFE:
+      UMA_HISTOGRAM_COUNTS_100(kReferrerChainSizeOfSafeVerdictHistogram,
+                               referrer_chain_size);
+      return;
+    case LoginReputationClientResponse::LOW_REPUTATION:
+      UMA_HISTOGRAM_COUNTS_100(kReferrerChainSizeOfLowRepVerdictHistogram,
+                               referrer_chain_size);
+      return;
+    case LoginReputationClientResponse::PHISHING:
+      UMA_HISTOGRAM_COUNTS_100(kReferrerChainSizeOfPhishingVerdictHistogram,
+                               referrer_chain_size);
+      return;
+    case LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED:
+      break;
+  }
+  NOTREACHED();
+}
+
 }  // namespace safe_browsing
diff --git a/components/safe_browsing/password_protection/password_protection_request.h b/components/safe_browsing/password_protection/password_protection_request.h
index e19afb2..80cee479 100644
--- a/components/safe_browsing/password_protection/password_protection_request.h
+++ b/components/safe_browsing/password_protection/password_protection_request.h
@@ -30,6 +30,9 @@
 extern const char kProtectedPasswordEntryVerdictHistogram[];
 extern const char kEnterprisePasswordEntryVerdictHistogram[];
 extern const char kGSuiteSyncPasswordEntryVerdictHistogram[];
+extern const char kReferrerChainSizeOfSafeVerdictHistogram[];
+extern const char kReferrerChainSizeOfPhishingVerdictHistogram[];
+extern const char kReferrerChainSizeOfLowRepVerdictHistogram[];
 
 // A request for checking if an unfamiliar login form or a password reuse event
 // is safe. PasswordProtectionRequest objects are owned by
@@ -151,6 +154,12 @@
   void Finish(PasswordProtectionService::RequestOutcome outcome,
               std::unique_ptr<LoginReputationClientResponse> response);
 
+  // TODO(crbug.com/854314): Move this function to a separate util file.
+  // Logs the size of referrer chain by verdict type.
+  void LogReferrerChainSize(
+      LoginReputationClientResponse::VerdictType verdict_type,
+      int referrer_chain_size);
+
   // WebContents of the password protection event.
   content::WebContents* web_contents_;
 
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 32c4ae6..120b0641 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -739,6 +739,7 @@
       ElementsAre(base::Bucket(1 /* SUCCEEDED */, 1)));
   EXPECT_THAT(histograms_.GetAllSamples(kPasswordOnFocusVerdictHistogram),
               ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
+  histograms_.ExpectTotalCount(kReferrerChainSizeOfPhishingVerdictHistogram, 1);
   LoginReputationClientResponse* actual_response =
       password_protection_service_->latest_response();
   EXPECT_EQ(expected_response.verdict_type(), actual_response->verdict_type());
@@ -786,6 +787,7 @@
   EXPECT_THAT(
       histograms_.GetAllSamples(kProtectedPasswordEntryVerdictHistogram),
       ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
+  histograms_.ExpectTotalCount(kReferrerChainSizeOfPhishingVerdictHistogram, 1);
 }
 
 TEST_P(PasswordProtectionServiceTest,
@@ -823,6 +825,7 @@
   EXPECT_THAT(histograms_.GetAllSamples(kSyncPasswordEntryVerdictHistogram),
               ElementsAre(base::Bucket(3 /* PHISHING */, 1)));
   histograms_.ExpectTotalCount(kProtectedPasswordEntryVerdictHistogram, 0);
+  histograms_.ExpectTotalCount(kReferrerChainSizeOfPhishingVerdictHistogram, 1);
 }
 
 TEST_P(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
diff --git a/components/viz/common/surfaces/surface_range.cc b/components/viz/common/surfaces/surface_range.cc
index 8d1385e..4868767 100644
--- a/components/viz/common/surfaces/surface_range.cc
+++ b/components/viz/common/surfaces/surface_range.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/common/surfaces/surface_range.h"
 
+#include "base/strings/stringprintf.h"
+
 namespace viz {
 
 SurfaceRange::SurfaceRange() = default;
@@ -45,4 +47,14 @@
   return end_.local_surface_id().IsSameOrNewerThan(start_->local_surface_id());
 }
 
+std::string SurfaceRange::ToString() const {
+  return base::StringPrintf("SurfaceRange(start: %s, end: %s)",
+                            start_ ? start_->ToString().c_str() : "none",
+                            end_.ToString().c_str());
+}
+
+std::ostream& operator<<(std::ostream& out, const SurfaceRange& surface_range) {
+  return out << surface_range.ToString();
+}
+
 }  // namespace viz
diff --git a/components/viz/common/surfaces/surface_range.h b/components/viz/common/surfaces/surface_range.h
index 00bf9341d..b062cfc 100644
--- a/components/viz/common/surfaces/surface_range.h
+++ b/components/viz/common/surfaces/surface_range.h
@@ -41,6 +41,8 @@
 
   const SurfaceId& end() const { return end_; }
 
+  std::string ToString() const;
+
  private:
   friend struct mojo::StructTraits<mojom::SurfaceRangeDataView, SurfaceRange>;
 
@@ -48,6 +50,9 @@
   SurfaceId end_;
 };
 
+VIZ_COMMON_EXPORT std::ostream& operator<<(std::ostream& out,
+                                           const SurfaceRange& surface_range);
+
 }  // namespace viz
 
 #endif  // COMPONENTS_VIZ_COMMON_SURFACES_SURFACE_RANGE_H_
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index a7a9139..b7308e54 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1258,14 +1258,8 @@
   RunHtmlTest(FILE_PATH_LITERAL("iframe-presentational.html"));
 }
 
-#if defined(OS_WIN)
-// Flaky; https://crbug.com/856566.
-#define MAYBE_AccessibilityIframeTransform DISABLED_AccessibilityIframeTransform
-#else
-#define MAYBE_AccessibilityIframeTransform AccessibilityIframeTransform
-#endif
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityIframeTransform) {
+                       AccessibilityIframeTransform) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-transform.html"));
 }
 
@@ -1274,29 +1268,13 @@
   RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-cross-process.html"));
 }
 
-#if defined(OS_WIN)
-// Flaky; https://crbug.com/856566.
-#define MAYBE_AccessibilityIframeTransformNested \
-  DISABLED_AccessibilityIframeTransformNested
-#else
-#define MAYBE_AccessibilityIframeTransformNested \
-  AccessibilityIframeTransformNested
-#endif
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityIframeTransformNested) {
+                       AccessibilityIframeTransformNested) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-nested.html"));
 }
 
-#if defined(OS_WIN)
-// Flaky; https://crbug.com/856566.
-#define MAYBE_AccessibilityIframeTransformNestedCrossProcess \
-  DISABLED_AccessibilityIframeTransformNestedCrossProcess
-#else
-#define MAYBE_AccessibilityIframeTransformNestedCrossProcess \
-  AccessibilityIframeTransformNestedCrossProcess
-#endif
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
-                       MAYBE_AccessibilityIframeTransformNestedCrossProcess) {
+                       AccessibilityIframeTransformNestedCrossProcess) {
   RunHtmlTest(FILE_PATH_LITERAL("iframe-transform-nested-cross-process.html"));
 }
 
diff --git a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
index 4f7182d5..c4e83be 100644
--- a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
+++ b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.cc
@@ -23,8 +23,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchAbortEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
   last_developer_id_ = developer_id;
   last_unique_id_ = unique_id;
   last_fetches_ = fetches;
@@ -44,8 +43,7 @@
 void BackgroundFetchEmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
     const std::string& developer_id,
     mojom::BackgroundFetchState state,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchClickEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
   last_developer_id_ = developer_id;
   last_state_ = state;
 
@@ -65,8 +63,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchFailEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
   last_developer_id_ = developer_id;
   last_unique_id_ = unique_id;
   last_fetches_ = fetches;
@@ -87,8 +84,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::DispatchBackgroundFetchedEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback) {
   last_developer_id_ = developer_id;
   last_unique_id_ = unique_id;
   last_fetches_ = fetches;
diff --git a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
index 248b911..312debd 100644
--- a/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
+++ b/content/browser/background_fetch/background_fetch_embedded_worker_test_helper.h
@@ -70,25 +70,25 @@
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchAbortEventCallback callback) override;
+      mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback)
+      override;
   void OnBackgroundFetchClickEvent(
       const std::string& developer_id,
       mojom::BackgroundFetchState state,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchClickEventCallback callback) override;
+      mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback)
+      override;
   void OnBackgroundFetchFailEvent(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchFailEventCallback callback) override;
+      mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback)
+      override;
   void OnBackgroundFetchedEvent(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchedEventCallback callback) override;
+      mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback)
+      override;
 
  private:
   bool fail_abort_event_ = false;
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher.cc b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
index 8aeb19be..e80dd43 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
@@ -94,7 +94,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
-  service_worker_version->event_dispatcher()->DispatchBackgroundFetchAbortEvent(
+  service_worker_version->endpoint()->DispatchBackgroundFetchAbortEvent(
       developer_id, unique_id, fetches,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
@@ -118,7 +118,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
-  service_worker_version->event_dispatcher()->DispatchBackgroundFetchClickEvent(
+  service_worker_version->endpoint()->DispatchBackgroundFetchClickEvent(
       developer_id, state,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
@@ -144,7 +144,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
-  service_worker_version->event_dispatcher()->DispatchBackgroundFetchFailEvent(
+  service_worker_version->endpoint()->DispatchBackgroundFetchFailEvent(
       developer_id, unique_id, fetches,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
@@ -170,7 +170,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker_version,
     int request_id) {
   DCHECK(service_worker_version);
-  service_worker_version->event_dispatcher()->DispatchBackgroundFetchedEvent(
+  service_worker_version->endpoint()->DispatchBackgroundFetchedEvent(
       developer_id, unique_id, fetches,
       service_worker_version->CreateSimpleEventCallback(request_id));
 }
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 4668b39..1de24533 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -803,7 +803,7 @@
       parameters_->max_sync_event_duration,
       ServiceWorkerVersion::CONTINUE_ON_TIMEOUT);
 
-  active_version->event_dispatcher()->DispatchSyncEvent(
+  active_version->endpoint()->DispatchSyncEvent(
       tag, last_chance, parameters_->max_sync_event_duration,
       base::BindOnce(&OnSyncEventFinished, active_version, request_id,
                      std::move(repeating_callback)));
diff --git a/content/browser/cookie_store/cookie_store_manager.cc b/content/browser/cookie_store/cookie_store_manager.cc
index 628838379..717c5d0 100644
--- a/content/browser/cookie_store/cookie_store_manager.cc
+++ b/content/browser/cookie_store/cookie_store_manager.cc
@@ -514,7 +514,7 @@
   int request_id = active_version->StartRequest(
       ServiceWorkerMetrics::EventType::COOKIE_CHANGE, base::DoNothing());
 
-  active_version->event_dispatcher()->DispatchCookieChangeEvent(
+  active_version->endpoint()->DispatchCookieChangeEvent(
       cookie, cause, active_version->CreateSimpleEventCallback(request_id));
 }
 
diff --git a/content/browser/cookie_store/cookie_store_manager_unittest.cc b/content/browser/cookie_store/cookie_store_manager_unittest.cc
index 664c7f6..b694ae0 100644
--- a/content/browser/cookie_store/cookie_store_manager_unittest.cc
+++ b/content/browser/cookie_store/cookie_store_manager_unittest.cc
@@ -116,7 +116,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -129,15 +129,14 @@
 
     EmbeddedWorkerTestHelper::OnStartWorker(
         embedded_worker_id, service_worker_version_id, scope, script_url,
-        pause_after_download, std::move(dispatcher_request),
+        pause_after_download, std::move(service_worker_request),
         std::move(controller_request), std::move(instance_host),
         std::move(provider_info), std::move(installed_scripts_info));
   }
 
   // Cookie change subscriptions can only be created in this event handler.
   void OnInstallEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchInstallEventCallback callback) override {
     for (auto& subscriptions : install_subscription_batches_) {
       cookie_store_service_->AppendSubscriptions(
           service_worker_registration_id_, std::move(subscriptions),
@@ -152,8 +151,7 @@
 
   // Used to implement WaitForActivateEvent().
   void OnActivateEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchActivateEventCallback callback) override {
     if (quit_on_activate_) {
       quit_on_activate_->Quit();
       quit_on_activate_ = nullptr;
@@ -165,8 +163,8 @@
   void OnCookieChangeEvent(
       const net::CanonicalCookie& cookie,
       ::network::mojom::CookieChangeCause cause,
-      mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchCookieChangeEventCallback callback)
+      override {
     changes_.emplace_back(cookie, cause);
     std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                             base::Time::Now());
diff --git a/content/browser/do_not_track_browsertest.cc b/content/browser/do_not_track_browsertest.cc
index 63c48bd..c015d3f 100644
--- a/content/browser/do_not_track_browsertest.cc
+++ b/content/browser/do_not_track_browsertest.cc
@@ -34,11 +34,30 @@
 
 class DoNotTrackTest : public ContentBrowserTest {
  protected:
-  void EnableDoNotTrack() {
+  void TearDownOnMainThread() override {
+    if (original_client_)
+      SetBrowserClientForTesting(original_client_);
+  }
+
+  // Returns false if we cannot enable do not track. It happens only when
+  // Android Kitkat or older systems.
+  // TODO(crbug.com/864403): It seems that we call unsupported Android APIs on
+  // KitKat when we set a ContentBrowserClient. Don't call such APIs and make
+  // this test available on KitKat.
+  bool EnableDoNotTrack() {
+#if defined(OS_ANDROID)
+    int32_t major_version = 0, minor_version = 0, bugfix_version = 0;
+    base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
+                                                 &bugfix_version);
+    if (major_version < 5)
+      return false;
+#endif
+    original_client_ = SetBrowserClientForTesting(&client_);
     RendererPreferences* prefs =
         shell()->web_contents()->GetMutableRendererPrefs();
     EXPECT_FALSE(prefs->enable_do_not_track);
     prefs->enable_do_not_track = true;
+    return true;
   }
 
   void ExpectPageTextEq(const std::string& expected_content) {
@@ -59,6 +78,10 @@
         &value));
     return value;
   }
+
+ private:
+  ContentBrowserClient* original_client_ = nullptr;
+  MockContentBrowserClient client_;
 };
 
 std::unique_ptr<net::test_server::HttpResponse> CaptureHeaderHandler(
@@ -88,7 +111,8 @@
 // Checks that the DNT header is sent when the corresponding preference is set.
 IN_PROC_BROWSER_TEST_F(DoNotTrackTest, Simple) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   GURL url = embedded_test_server()->GetURL("/echoheader?DNT");
   EXPECT_TRUE(NavigateToURL(shell(), url));
   ExpectPageTextEq("1");
@@ -100,7 +124,8 @@
   GURL final_url = embedded_test_server()->GetURL("/echoheader?DNT");
   GURL url = embedded_test_server()->GetURL(std::string("/server-redirect?") +
                                             final_url.spec());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   // We don't check the result NavigateToURL as it returns true only if the
   // final URL is equal to the passed URL.
   NavigateToURL(shell(), url);
@@ -111,7 +136,8 @@
 IN_PROC_BROWSER_TEST_F(DoNotTrackTest, DOMProperty) {
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url = embedded_test_server()->GetURL("/echo");
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   EXPECT_TRUE(NavigateToURL(shell(), url));
   EXPECT_EQ("1", GetDOMDoNotTrackProperty());
 }
@@ -124,7 +150,8 @@
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &CaptureHeaderHandler, "/capture", &header_map, loop.QuitClosure()));
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   const GURL url = embedded_test_server()->GetURL(
       std::string("/workers/create_worker.html?worker_url=/capture"));
   NavigateToURL(shell(), url);
@@ -143,7 +170,8 @@
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &CaptureHeaderHandler, "/capture", &header_map, loop.QuitClosure()));
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   const GURL url = embedded_test_server()->GetURL(
       std::string("/workers/create_shared_worker.html?worker_url=/capture"));
   NavigateToURL(shell(), url);
@@ -162,7 +190,8 @@
   embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
       &CaptureHeaderHandler, "/capture", &header_map, loop.QuitClosure()));
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   const GURL url = embedded_test_server()->GetURL(std::string(
       "/service_worker/create_service_worker.html?worker_url=/capture"));
   NavigateToURL(shell(), url);
@@ -176,7 +205,8 @@
 // worker.
 IN_PROC_BROWSER_TEST_F(DoNotTrackTest, FetchFromWorker) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   const GURL fetch_url = embedded_test_server()->GetURL("/echoheader?DNT");
   const GURL url = embedded_test_server()->GetURL(
       std::string("/workers/fetch_from_worker.html?url=") + fetch_url.spec());
@@ -190,10 +220,17 @@
 }
 
 // Checks that the DNT header is preserved when fetching from a shared worker.
-// Disabled due to crbug.com/853085.
-IN_PROC_BROWSER_TEST_F(DoNotTrackTest, DISABLED_FetchFromSharedWorker) {
+//
+// Disabled on Android since a shared worker is not available on Android.
+#if defined(OS_ANDROID)
+#define MAYBE_FetchFromSharedWorker DISABLED_FetchFromSharedWorker
+#else
+#define MAYBE_FetchFromSharedWorker FetchFromSharedWorker
+#endif
+IN_PROC_BROWSER_TEST_F(DoNotTrackTest, MAYBE_FetchFromSharedWorker) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   const GURL fetch_url = embedded_test_server()->GetURL("/echoheader?DNT");
   const GURL url = embedded_test_server()->GetURL(
       std::string("/workers/fetch_from_shared_worker.html?url=") +
@@ -209,21 +246,9 @@
 
 // Checks that the DNT header is preserved when fetching from a service worker.
 IN_PROC_BROWSER_TEST_F(DoNotTrackTest, FetchFromServiceWorker) {
-#if defined(OS_ANDROID)
-  // TODO(crbug.com/864403): It seems that we call unsupported Android APIs on
-  // KitKat when we set a ContentBrowserClient. Don't call such APIs and make
-  // this test available on KitKat.
-  int32_t major_version = 0, minor_version = 0, bugfix_version = 0;
-  base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
-                                               &bugfix_version);
-  if (major_version < 5)
-    return;
-#endif
-  MockContentBrowserClient client;
-  ContentBrowserClient* original_client = SetBrowserClientForTesting(&client);
-
   ASSERT_TRUE(embedded_test_server()->Start());
-  EnableDoNotTrack();
+  if (!EnableDoNotTrack())
+    return;
   const GURL fetch_url = embedded_test_server()->GetURL("/echoheader?DNT");
   const GURL url = embedded_test_server()->GetURL(
       std::string("/service_worker/fetch_from_service_worker.html?url=") +
@@ -235,7 +260,6 @@
   EXPECT_EQ(title, watcher.WaitAndGetTitle());
 
   ExpectPageTextEq("1");
-  SetBrowserClientForTesting(original_client);
 }
 
 }  // namespace
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 39c543ab..be1a8e4 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -2895,10 +2895,9 @@
   ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
 }
 
-// A filename suggestion specified via a @download attribute should be effective
-// if the final download URL is in the same origin as the initial download URL.
-// Test that this holds even if there are cross origin redirects in the middle
-// of the redirect chain.
+// A filename suggestion specified via a @download attribute should not be
+// effective if there are cross origin redirects in the middle of the redirect
+// chain.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest,
                        DownloadAttributeSameOriginRedirect) {
   net::EmbeddedTestServer origin_one;
@@ -2941,12 +2940,60 @@
   DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
   ASSERT_EQ(1u, downloads.size());
 
-  EXPECT_EQ(FILE_PATH_LITERAL("suggested-filename"),
+  EXPECT_EQ(FILE_PATH_LITERAL("download"),
             downloads[0]->GetTargetFilePath().BaseName().value());
   ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
   ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
 }
 
+// A file type that Blink can handle should not be downloaded if there are cross
+// origin redirects in the middle of the redirect chain.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest,
+                       DownloadAttributeSameOriginRedirectNavigation) {
+  net::EmbeddedTestServer origin_one;
+  net::EmbeddedTestServer origin_two;
+  ASSERT_TRUE(origin_one.InitializeAndListen());
+  ASSERT_TRUE(origin_two.InitializeAndListen());
+
+  // The download-attribute.html page contains an anchor element whose href is
+  // set to the value of the query parameter (specified as |target| in the URL
+  // below). The suggested filename for the anchor is 'suggested-filename'. When
+  // the page is loaded, a script simulates a click on the anchor, triggering a
+  // download of the target URL.
+  //
+  // We construct two test servers; origin_one and origin_two. Once started, the
+  // server URLs will differ by the port number. Therefore they will be in
+  // different origins.
+  GURL download_url = origin_one.GetURL("/ping");
+  GURL referrer_url = origin_one.GetURL(
+      std::string("/download-attribute.html?target=") + download_url.spec());
+  origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
+
+  // <origin_one>/download-attribute.html initiates a download of
+  // <origin_one>/ping, which redirects to <origin_two>/download. The latter
+  // serves an HTML document.
+  origin_one.RegisterRequestHandler(
+      CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
+  origin_two.RegisterRequestHandler(
+      CreateBasicResponseHandler("/download", net::HTTP_OK, base::StringPairs(),
+                                 "text/html", "<title>hello</title>"));
+
+  origin_one.StartAcceptingConnections();
+  origin_two.StartAcceptingConnections();
+
+  base::string16 expected_title(base::UTF8ToUTF16("hello"));
+  TitleWatcher observer(shell()->web_contents(), expected_title);
+  NavigateToURL(shell(), referrer_url);
+  ASSERT_EQ(expected_title, observer.WaitAndGetTitle());
+
+  std::vector<download::DownloadItem*> downloads;
+  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+  ASSERT_EQ(0u, downloads.size());
+
+  ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
+  ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
+}
+
 // Test that the suggested filename for data: URLs works.
 IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeDataUrl) {
   net::EmbeddedTestServer server;
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index ae4e5585..16f7420d 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -436,6 +436,23 @@
     const download::DownloadCreateInfo& info) {
   WebContents* web_contents = WebContentsImpl::FromRenderFrameHostID(
       info.render_process_id, info.render_frame_id);
+  if (info.is_new_download &&
+      info.result ==
+          download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT) {
+    if (web_contents) {
+      std::vector<GURL> url_chain(info.url_chain);
+      GURL url = url_chain.back();
+      url_chain.pop_back();
+      NavigationController::LoadURLParams params(url);
+      params.has_user_gesture = info.has_user_gesture;
+      params.referrer = Referrer(
+          info.referrer_url, Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
+                                 info.referrer_policy));
+      params.redirect_chain = url_chain;
+      web_contents->GetController().LoadURLWithParams(params);
+    }
+    return true;
+  }
   if (!delegate_ ||
       !delegate_->InterceptDownloadIfApplicable(
           info.url(), info.mime_type, info.request_origin, web_contents)) {
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index a40c5c80..fb6a33b 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -227,6 +227,7 @@
   create_info->connection_info = request()->response_info().connection_info;
   create_info->url_chain = request()->url_chain();
   create_info->referrer_url = GURL(request()->referrer());
+  create_info->referrer_policy = request()->referrer_policy();
   create_info->result = result;
   create_info->is_new_download = is_new_download_;
   create_info->guid = guid_;
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc
index 00b4d62a..752cc1a 100644
--- a/content/browser/download/download_resource_handler.cc
+++ b/content/browser/download/download_resource_handler.cc
@@ -119,6 +119,24 @@
 void DeleteOnUIThread(
     std::unique_ptr<DownloadResourceHandler::DownloadTabInfo> tab_info) {}
 
+void NavigateOnUIThread(
+    const GURL& url,
+    const std::vector<GURL> url_chain,
+    const Referrer& referrer,
+    bool has_user_gesture,
+    const ResourceRequestInfo::WebContentsGetter& wc_getter) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  WebContents* web_contents = wc_getter.Run();
+  if (web_contents) {
+    NavigationController::LoadURLParams params(url);
+    params.has_user_gesture = has_user_gesture;
+    params.referrer = referrer;
+    params.redirect_chain = url_chain;
+    web_contents->GetController().LoadURLWithParams(params);
+  }
+}
+
 }  // namespace
 
 DownloadResourceHandler::DownloadResourceHandler(
@@ -182,8 +200,17 @@
   url::Origin new_origin(url::Origin::Create(redirect_info.new_url));
   if (!follow_cross_origin_redirects_ &&
       !first_origin_.IsSameOriginWith(new_origin)) {
-    // TODO(jochen): Abort download and instead navigate.
-    DVLOG(1) << "Download encountered cross origin redirect.";
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::BindOnce(
+            &NavigateOnUIThread, redirect_info.new_url, request()->url_chain(),
+            Referrer(GURL(redirect_info.new_referrer),
+                     Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
+                         redirect_info.new_referrer_policy)),
+            GetRequestInfo()->HasUserGesture(),
+            GetRequestInfo()->GetWebContentsGetterForRequest()));
+    controller->Cancel();
+    return;
   }
   if (core_.OnRequestRedirected()) {
     controller->Resume();
diff --git a/content/browser/download/url_downloader.cc b/content/browser/download/url_downloader.cc
index 034fadd..e44234a3 100644
--- a/content/browser/download/url_downloader.cc
+++ b/content/browser/download/url_downloader.cc
@@ -13,6 +13,7 @@
 #include "components/download/public/common/download_interrupt_reasons.h"
 #include "components/download/public/common/download_request_handle_interface.h"
 #include "components/download/public/common/download_url_parameters.h"
+#include "components/download/public/common/url_download_request_handle.h"
 #include "content/browser/byte_stream.h"
 #include "content/browser/download/byte_stream_input_stream.h"
 #include "content/public/browser/browser_thread.h"
@@ -25,43 +26,6 @@
 
 namespace content {
 
-class UrlDownloader::RequestHandle
-    : public download::DownloadRequestHandleInterface {
- public:
-  RequestHandle(base::WeakPtr<UrlDownloader> downloader,
-                scoped_refptr<base::SequencedTaskRunner> downloader_task_runner)
-      : downloader_(downloader),
-        downloader_task_runner_(downloader_task_runner) {}
-  RequestHandle(RequestHandle&& other)
-      : downloader_(std::move(other.downloader_)),
-        downloader_task_runner_(std::move(other.downloader_task_runner_)) {}
-  RequestHandle& operator=(RequestHandle&& other) {
-    downloader_ = std::move(other.downloader_);
-    downloader_task_runner_ = std::move(other.downloader_task_runner_);
-    return *this;
-  }
-
-  // DownloadRequestHandleInterface
-  void PauseRequest() override {
-    downloader_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&UrlDownloader::PauseRequest, downloader_));
-  }
-  void ResumeRequest() override {
-    downloader_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&UrlDownloader::ResumeRequest, downloader_));
-  }
-  void CancelRequest(bool user_cancel) override {
-    downloader_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&UrlDownloader::CancelRequest, downloader_));
-  }
-
- private:
-  base::WeakPtr<UrlDownloader> downloader_;
-  scoped_refptr<base::SequencedTaskRunner> downloader_task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(RequestHandle);
-};
-
 // static
 std::unique_ptr<UrlDownloader> UrlDownloader::BeginDownload(
     base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
@@ -221,7 +185,7 @@
     std::unique_ptr<download::DownloadCreateInfo> create_info,
     std::unique_ptr<ByteStreamReader> stream_reader,
     const download::DownloadUrlParameters::OnStartedCallback& callback) {
-  create_info->request_handle.reset(new RequestHandle(
+  create_info->request_handle.reset(new download::UrlDownloadRequestHandle(
       weak_ptr_factory_.GetWeakPtr(), base::SequencedTaskRunnerHandle::Get()));
 
   BrowserThread::PostTask(
diff --git a/content/browser/download/url_downloader.h b/content/browser/download/url_downloader.h
index 0ee10fe..e5b7289 100644
--- a/content/browser/download/url_downloader.h
+++ b/content/browser/download/url_downloader.h
@@ -42,8 +42,6 @@
       bool is_parallel_request);
 
  private:
-  class RequestHandle;
-
   void Start();
 
   // URLRequest::Delegate:
@@ -64,9 +62,10 @@
       override;
   void OnReadyToRead() override;
 
-  void PauseRequest();
-  void ResumeRequest();
-  void CancelRequest();
+  // UrlDownloadHandler implementations.
+  void PauseRequest() override;
+  void ResumeRequest() override;
+  void CancelRequest() override;
 
   // Called when the UrlDownloader is done with the request. Posts a task to
   // remove itself from its download manager, which in turn would cause the
diff --git a/content/browser/frame_host/origin_policy_throttle.cc b/content/browser/frame_host/origin_policy_throttle.cc
index 219cb36..ab13723 100644
--- a/content/browser/frame_host/origin_policy_throttle.cc
+++ b/content/browser/frame_host/origin_policy_throttle.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/frame_host/origin_policy_throttle.h"
 
+#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/no_destructor.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
@@ -11,6 +12,7 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
 #include "net/http/http_request_headers.h"
 #include "services/network/network_context.h"
 #include "services/network/network_service.h"
@@ -173,6 +175,9 @@
       network::mojom::URLLoaderFactoryParams::New();
   url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
   url_loader_factory_params->is_corb_enabled = false;
+  url_loader_factory_params->disable_web_security =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableWebSecurity);
   network_context_ptr_->CreateURLLoaderFactory(
       mojo::MakeRequest(&url_loader_factory_),
       std::move(url_loader_factory_params));
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 5b35b26c..f046cb8 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -828,6 +828,9 @@
   network::mojom::URLLoaderFactoryParamsPtr params =
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = GetProcess()->GetID();
+  params->disable_web_security =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableWebSecurity);
   SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get());
 
   auto* context = GetSiteInstance()->GetBrowserContext();
diff --git a/content/browser/loader/cors_file_origin_browsertest.cc b/content/browser/loader/cors_file_origin_browsertest.cc
index af3ed28..2b0e7a60 100644
--- a/content/browser/loader/cors_file_origin_browsertest.cc
+++ b/content/browser/loader/cors_file_origin_browsertest.cc
@@ -12,7 +12,10 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
 #include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -24,6 +27,7 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/test/embedded_test_server/request_handler_util.h"
 #include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -37,11 +41,20 @@
 
 // Tests end to end Origin header and CORS check behaviors without
 // --allow-file-access-from-files flag.
-class CORSFileOriginBrowserTest : public ContentBrowserTest {
+class CORSFileOriginBrowserTest : public ContentBrowserTest,
+                                  public testing::WithParamInterface<bool> {
  public:
   CORSFileOriginBrowserTest()
       : pass_string_(base::ASCIIToUTF16("PASS")),
-        fail_string_(base::ASCIIToUTF16("FAIL")) {}
+        fail_string_(base::ASCIIToUTF16("FAIL")) {
+    if (GetParam()) {
+      scoped_feature_list_.InitAndEnableFeature(
+          network::features::kOutOfBlinkCORS);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(
+          network::features::kOutOfBlinkCORS);
+    }
+  }
   ~CORSFileOriginBrowserTest() override = default;
 
  protected:
@@ -84,7 +97,15 @@
 
  private:
   bool AllowFileAccessFromFiles() const override { return false; }
+  virtual bool IsWebSecurityEnabled() const { return true; }
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    if (!IsWebSecurityEnabled()) {
+      command_line->AppendSwitch(switches::kDisableWebSecurity);
+    }
+
+    ContentBrowserTest::SetUpCommandLine(command_line);
+  }
   void SetUpOnMainThread() override {
     base::AutoLock lock(lock_);
 
@@ -147,6 +168,9 @@
   const base::string16 pass_string_;
   const base::string16 fail_string_;
 
+  base::test::ScopedFeatureList scoped_command_line_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+
   DISALLOW_COPY_AND_ASSIGN(CORSFileOriginBrowserTest);
 };
 
@@ -158,7 +182,16 @@
   bool AllowFileAccessFromFiles() const override { return true; }
 };
 
-IN_PROC_BROWSER_TEST_F(CORSFileOriginBrowserTest,
+// Tests end to end Origin header and CORS check behaviors with
+// --disable-web-security flag.
+class CORSFileOriginBrowserTestWithDisableWebSecurity
+    : public CORSFileOriginBrowserTest {
+ private:
+  bool AllowFileAccessFromFiles() const override { return false; }
+  bool IsWebSecurityEnabled() const override { return false; }
+};
+
+IN_PROC_BROWSER_TEST_P(CORSFileOriginBrowserTest,
                        AccessControlAllowOriginIsNull) {
   std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
@@ -170,7 +203,7 @@
   EXPECT_TRUE(is_preflight_requested());
 }
 
-IN_PROC_BROWSER_TEST_F(CORSFileOriginBrowserTest,
+IN_PROC_BROWSER_TEST_P(CORSFileOriginBrowserTest,
                        AccessControlAllowOriginIsFile) {
   std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
@@ -182,7 +215,7 @@
   EXPECT_TRUE(is_preflight_requested());
 }
 
-IN_PROC_BROWSER_TEST_F(CORSFileOriginBrowserTestWithAllowFileAccessFromFiles,
+IN_PROC_BROWSER_TEST_P(CORSFileOriginBrowserTestWithAllowFileAccessFromFiles,
                        AccessControlAllowOriginIsNull) {
   std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
@@ -194,7 +227,7 @@
   EXPECT_TRUE(is_preflight_requested());
 }
 
-IN_PROC_BROWSER_TEST_F(CORSFileOriginBrowserTestWithAllowFileAccessFromFiles,
+IN_PROC_BROWSER_TEST_P(CORSFileOriginBrowserTestWithAllowFileAccessFromFiles,
                        AccessControlAllowOriginIsFile) {
   std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
@@ -206,6 +239,47 @@
   EXPECT_TRUE(is_preflight_requested());
 }
 
+IN_PROC_BROWSER_TEST_P(CORSFileOriginBrowserTestWithDisableWebSecurity,
+                       AccessControlAllowOriginIsNull) {
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), CreateTestDataURL(base::StringPrintf(
+                   "cors_file_origin_test.html?port=%d&allow=%s&origin=%s",
+                   port(), "unused", ""))));
+
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle());
+  EXPECT_FALSE(is_preflight_requested());
+}
+
+IN_PROC_BROWSER_TEST_P(CORSFileOriginBrowserTestWithDisableWebSecurity,
+                       AccessControlAllowOriginIsFile) {
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
+  EXPECT_TRUE(NavigateToURL(
+      shell(), CreateTestDataURL(base::StringPrintf(
+                   "cors_file_origin_test.html?port=%d&allow=%s&origin=%s",
+                   port(), "unused", ""))));
+
+  EXPECT_EQ(pass_string(), watcher->WaitAndGetTitle());
+  EXPECT_FALSE(is_preflight_requested());
+}
+
+// --allow-file-access-from-files is currently not supported by OOR-CORS.
+// We may remove the feature.
+INSTANTIATE_TEST_CASE_P(
+    /* No test prefix */,
+    CORSFileOriginBrowserTest,
+    ::testing::Values(false));
+
+INSTANTIATE_TEST_CASE_P(
+    /* No test prefix */,
+    CORSFileOriginBrowserTestWithAllowFileAccessFromFiles,
+    ::testing::Values(false));
+
+INSTANTIATE_TEST_CASE_P(
+    /* No test prefix */,
+    CORSFileOriginBrowserTestWithDisableWebSecurity,
+    ::testing::Values(false, true));
+
 }  // namespace
 
 }  // namespace content
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index b84a58e92..538274d 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -104,7 +104,7 @@
   }
 
  private:
-  void DeleteURLLoader(network::URLLoader* url_loader) {
+  void DeleteURLLoader(network::mojom::URLLoader* url_loader) {
     DCHECK_EQ(url_loader_.get(), url_loader);
     url_loader_.reset();
   }
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc
index abe1f3445..2f531f5 100644
--- a/content/browser/loader/resource_message_filter.cc
+++ b/content/browser/loader/resource_message_filter.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/loader/resource_message_filter.h"
 
-#include "base/feature_list.h"
+#include "base/command_line.h"
 #include "base/logging.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
@@ -18,9 +18,8 @@
 #include "content/common/resource_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_context.h"
-#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
 #include "services/network/cors/cors_url_loader_factory.h"
-#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "storage/browser/fileapi/file_system_context.h"
 
@@ -179,15 +178,13 @@
   // The WeakPtr of the filter must be created on the IO thread. So sets the
   // WeakPtr of |requester_info_| now.
   requester_info_->set_filter(GetWeakPtr());
-  url_loader_factory_ = std::make_unique<URLLoaderFactoryImpl>(requester_info_);
-
-  if (base::FeatureList::IsEnabled(network::features::kOutOfBlinkCORS)) {
-    url_loader_factory_ = std::make_unique<network::cors::CORSURLLoaderFactory>(
-        std::move(url_loader_factory_),
-        base::BindRepeating(&ResourceDispatcherHostImpl::CancelRequest,
-                            base::Unretained(ResourceDispatcherHostImpl::Get()),
-                            requester_info_->child_id()));
-  }
+  url_loader_factory_ = std::make_unique<network::cors::CORSURLLoaderFactory>(
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableWebSecurity),
+      std::make_unique<URLLoaderFactoryImpl>(requester_info_),
+      base::BindRepeating(&ResourceDispatcherHostImpl::CancelRequest,
+                          base::Unretained(ResourceDispatcherHostImpl::Get()),
+                          requester_info_->child_id()));
 
   std::vector<network::mojom::URLLoaderFactoryRequest> requests =
       std::move(queued_clone_requests_);
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index 64747b8..879ab76 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -223,7 +223,7 @@
   if (action_index.has_value())
     action_index_int = action_index.value();
 
-  service_worker->event_dispatcher()->DispatchNotificationClickEvent(
+  service_worker->endpoint()->DispatchNotificationClickEvent(
       notification_database_data.notification_id,
       notification_database_data.notification_data, action_index_int, reply,
       service_worker->CreateSimpleEventCallback(request_id));
@@ -296,7 +296,7 @@
   int request_id = service_worker->StartRequest(
       ServiceWorkerMetrics::EventType::NOTIFICATION_CLOSE, std::move(callback));
 
-  service_worker->event_dispatcher()->DispatchNotificationCloseEvent(
+  service_worker->endpoint()->DispatchNotificationCloseEvent(
       notification_database_data.notification_id,
       notification_database_data.notification_data,
       service_worker->CreateSimpleEventCallback(request_id));
diff --git a/content/browser/payments/payment_app_content_unittest_base.cc b/content/browser/payments/payment_app_content_unittest_base.cc
index 8450d60..c8210a3 100644
--- a/content/browser/payments/payment_app_content_unittest_base.cc
+++ b/content/browser/payments/payment_app_content_unittest_base.cc
@@ -66,7 +66,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -78,7 +78,7 @@
     last_sw_scope_ = scope;
     EmbeddedWorkerTestHelper::OnStartWorker(
         embedded_worker_id, service_worker_version_id, scope, script_url,
-        pause_after_download, std::move(dispatcher_request),
+        pause_after_download, std::move(service_worker_request),
         std::move(controller_request), std::move(instance_host),
         std::move(provider_info), std::move(installed_scripts_info));
   }
@@ -86,8 +86,8 @@
   void OnPaymentRequestEvent(
       payments::mojom::PaymentRequestEventDataPtr event_data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchPaymentRequestEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback)
+      override {
     if (respond_payment_request_immediately) {
       EmbeddedWorkerTestHelper::OnPaymentRequestEvent(
           std::move(event_data), std::move(response_callback),
@@ -102,8 +102,8 @@
   void OnCanMakePaymentEvent(
       payments::mojom::CanMakePaymentEventDataPtr event_data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback)
+      override {
     EmbeddedWorkerTestHelper::OnCanMakePaymentEvent(
         std::move(event_data), std::move(response_callback),
         std::move(callback));
@@ -111,8 +111,8 @@
 
   void OnAbortPaymentEvent(
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback)
+      override {
     EmbeddedWorkerTestHelper::OnAbortPaymentEvent(std::move(response_callback),
                                                   std::move(callback));
   }
diff --git a/content/browser/payments/payment_app_provider_impl.cc b/content/browser/payments/payment_app_provider_impl.cc
index 011ba40..3cfa0bd 100644
--- a/content/browser/payments/payment_app_provider_impl.cc
+++ b/content/browser/payments/payment_app_provider_impl.cc
@@ -268,7 +268,7 @@
       browser_context, ServiceWorkerMetrics::EventType::ABORT_PAYMENT,
       active_version, std::move(callback));
 
-  active_version->event_dispatcher()->DispatchAbortPaymentEvent(
+  active_version->endpoint()->DispatchAbortPaymentEvent(
       invocation_callbacks->CreateInterfacePtrAndBind(),
       active_version->CreateSimpleEventCallback(event_finish_id));
 }
@@ -297,7 +297,7 @@
       browser_context, ServiceWorkerMetrics::EventType::CAN_MAKE_PAYMENT,
       active_version, std::move(callback));
 
-  active_version->event_dispatcher()->DispatchCanMakePaymentEvent(
+  active_version->endpoint()->DispatchCanMakePaymentEvent(
       std::move(event_data), invocation_callbacks->CreateInterfacePtrAndBind(),
       active_version->CreateSimpleEventCallback(event_finish_id));
 }
@@ -328,7 +328,7 @@
       browser_context, ServiceWorkerMetrics::EventType::PAYMENT_REQUEST,
       active_version, std::move(callback));
 
-  active_version->event_dispatcher()->DispatchPaymentRequestEvent(
+  active_version->endpoint()->DispatchPaymentRequestEvent(
       std::move(event_data), invocation_callbacks->CreateInterfacePtrAndBind(),
       active_version->CreateSimpleEventCallback(event_finish_id));
 }
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index 69c0da0a..eb9c846 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -73,14 +73,14 @@
   return window_->GetBounds().size();
 }
 
-void PictureInPictureWindowControllerImpl::ClickCustomControl() {
+void PictureInPictureWindowControllerImpl::ClickCustomControl(
+    const std::string& control_id) {
   DCHECK(window_);
-  DCHECK(media_player_id_.has_value());
 
   media_player_id_->render_frame_host->Send(
       new MediaPlayerDelegateMsg_ClickPictureInPictureControl(
           media_player_id_->render_frame_host->GetRoutingID(),
-          media_player_id_->delegate_id));
+          media_player_id_->delegate_id, control_id));
 }
 
 void PictureInPictureWindowControllerImpl::Close(bool should_pause_video) {
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
index 9cae8ed..8cd191f 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -36,7 +36,8 @@
   // PictureInPictureWindowController:
   CONTENT_EXPORT gfx::Size Show() override;
   CONTENT_EXPORT void Close(bool should_pause_video) override;
-  CONTENT_EXPORT void ClickCustomControl() override;
+  CONTENT_EXPORT void ClickCustomControl(
+      const std::string& control_id) override;
   CONTENT_EXPORT void EmbedSurface(const viz::SurfaceId& surface_id,
                                    const gfx::Size& natural_size) override;
   CONTENT_EXPORT OverlayWindow* GetWindowForTesting() override;
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc
index 1c75f85..a648b5d 100644
--- a/content/browser/push_messaging/push_messaging_router.cc
+++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -126,7 +126,7 @@
       base::TimeDelta::FromSeconds(mojom::kPushEventTimeoutSeconds),
       ServiceWorkerVersion::KILL_ON_TIMEOUT);
 
-  service_worker->event_dispatcher()->DispatchPushEvent(
+  service_worker->endpoint()->DispatchPushEvent(
       payload, service_worker->CreateSimpleEventCallback(request_id));
 }
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 19ee3f9..3887d68c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2309,6 +2309,9 @@
   network::mojom::URLLoaderFactoryParamsPtr params =
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = id_;
+  params->disable_web_security =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableWebSecurity);
   SiteIsolationPolicy::PopulateURLLoaderFactoryParamsPtrForCORB(params.get());
   storage_partition_impl_->GetNetworkContext()->CreateURLLoaderFactory(
       std::move(request), std::move(params));
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 113f9e18..7e5a9bd 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -696,7 +696,7 @@
     scoped_refptr<network::SharedURLLoaderFactory> factory,
     blink::mojom::CacheStoragePtrInfo cache_storage) {
   DCHECK(context_);
-  DCHECK(params->dispatcher_request.is_pending());
+  DCHECK(params->service_worker_request.is_pending());
   DCHECK(params->controller_request.is_pending());
   DCHECK(!instance_host_binding_.is_bound());
   instance_host_binding_.Bind(mojo::MakeRequest(&params->instance_host));
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index 5af2051b..a7a9a31 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -217,7 +217,7 @@
     params->pause_after_download = false;
     params->is_installed = false;
 
-    params->dispatcher_request = CreateEventDispatcher();
+    params->service_worker_request = CreateServiceWorker();
     params->controller_request = CreateController();
     params->installed_scripts_info = GetInstalledScriptsInfoPtr();
     return params;
@@ -236,9 +236,9 @@
                           base::Unretained(this));
   }
 
-  mojom::ServiceWorkerEventDispatcherRequest CreateEventDispatcher() {
-    dispatchers_.emplace_back();
-    return mojo::MakeRequest(&dispatchers_.back());
+  mojom::ServiceWorkerRequest CreateServiceWorker() {
+    service_workers_.emplace_back();
+    return mojo::MakeRequest(&service_workers_.back());
   }
 
   mojom::ControllerServiceWorkerRequest CreateController() {
@@ -276,7 +276,7 @@
   }
 
   // Mojo endpoints.
-  std::vector<mojom::ServiceWorkerEventDispatcherPtr> dispatchers_;
+  std::vector<mojom::ServiceWorkerPtr> service_workers_;
   std::vector<mojom::ControllerServiceWorkerPtr> controllers_;
   std::vector<blink::mojom::ServiceWorkerInstalledScriptsManagerPtr>
       installed_scripts_managers_;
@@ -306,7 +306,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -320,7 +320,7 @@
     }
     EmbeddedWorkerTestHelper::OnStartWorker(
         embedded_worker_id, service_worker_version_id, scope, script_url,
-        pause_after_download, std::move(dispatcher_request),
+        pause_after_download, std::move(service_worker_request),
         std::move(controller_request), std::move(instance_host),
         std::move(provider_info), std::move(installed_scripts_info));
   }
@@ -915,7 +915,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -924,7 +924,7 @@
     had_cache_storage_ = !!provider_info->cache_storage;
     EmbeddedWorkerTestHelper::OnStartWorker(
         embedded_worker_id, service_worker_version_id, scope, script_url,
-        pause_after_download, std::move(dispatcher_request),
+        pause_after_download, std::move(service_worker_request),
         std::move(controller_request), std::move(instance_host),
         std::move(provider_info), std::move(installed_scripts_info));
   }
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 87d7911..3c22ac6 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -44,8 +44,7 @@
 
 void OnFetchEventCommon(
     mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-        finish_callback) {
+    mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) {
   response_callback->OnResponse(
       ServiceWorkerResponse(
           std::make_unique<std::vector<GURL>>(), 200, "OK",
@@ -179,23 +178,22 @@
     client->binding_.Bind(std::move(request));
 }
 
-class EmbeddedWorkerTestHelper::MockServiceWorkerEventDispatcher
-    : public mojom::ServiceWorkerEventDispatcher {
+class EmbeddedWorkerTestHelper::MockServiceWorker
+    : public mojom::ServiceWorker {
  public:
   static void Create(const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
                      int embedded_worker_id,
-                     mojom::ServiceWorkerEventDispatcherRequest request) {
-    mojo::MakeStrongBinding(std::make_unique<MockServiceWorkerEventDispatcher>(
-                                helper, embedded_worker_id),
-                            std::move(request));
+                     mojom::ServiceWorkerRequest request) {
+    mojo::MakeStrongBinding(
+        std::make_unique<MockServiceWorker>(helper, embedded_worker_id),
+        std::move(request));
   }
 
-  MockServiceWorkerEventDispatcher(
-      const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
-      int embedded_worker_id)
+  MockServiceWorker(const base::WeakPtr<EmbeddedWorkerTestHelper>& helper,
+                    int embedded_worker_id)
       : helper_(helper), embedded_worker_id_(embedded_worker_id) {}
 
-  ~MockServiceWorkerEventDispatcher() override {}
+  ~MockServiceWorker() override {}
 
   void InitializeGlobalScope(
       blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
@@ -531,15 +529,15 @@
     const GURL& scope,
     const GURL& script_url,
     bool pause_after_download,
-    mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+    mojom::ServiceWorkerRequest service_worker_request,
     mojom::ControllerServiceWorkerRequest controller_request,
     mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
     mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
     blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info) {
   EmbeddedWorkerInstance* worker = registry()->GetWorker(embedded_worker_id);
   ASSERT_TRUE(worker);
-  MockServiceWorkerEventDispatcher::Create(AsWeakPtr(), embedded_worker_id,
-                                           std::move(dispatcher_request));
+  MockServiceWorker::Create(AsWeakPtr(), embedded_worker_id,
+                            std::move(service_worker_request));
   embedded_worker_id_service_worker_version_id_map_[embedded_worker_id] =
       service_worker_version_id;
   embedded_worker_id_instance_host_ptr_map_[embedded_worker_id].Bind(
@@ -579,8 +577,7 @@
 }
 
 void EmbeddedWorkerTestHelper::OnActivateEvent(
-    mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchActivateEventCallback callback) {
   dispatched_events()->push_back(Event::Activate);
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
@@ -590,8 +587,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchAbortEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
@@ -599,8 +595,7 @@
 void EmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent(
     const std::string& developer_id,
     mojom::BackgroundFetchState state,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchClickEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
@@ -609,8 +604,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchFailEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
@@ -619,8 +613,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::DispatchBackgroundFetchedEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
@@ -628,23 +621,20 @@
 void EmbeddedWorkerTestHelper::OnCookieChangeEvent(
     const net::CanonicalCookie& cookie,
     ::network::mojom::CookieChangeCause cause,
-    mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchCookieChangeEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
 
 void EmbeddedWorkerTestHelper::OnExtendableMessageEvent(
     mojom::ExtendableMessageEventPtr event,
-    mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchExtendableMessageEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
 
 void EmbeddedWorkerTestHelper::OnInstallEvent(
-    mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchInstallEventCallback callback) {
   dispatched_events()->push_back(Event::Install);
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           true /* has_fetch_handler */, base::Time::Now());
@@ -655,15 +645,14 @@
     const network::ResourceRequest& /* request */,
     blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
     mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-        finish_callback) {
+    mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) {
   // TODO(falken): In-line common into here.
   OnFetchEventCommon(std::move(response_callback), std::move(finish_callback));
 }
 
 void EmbeddedWorkerTestHelper::OnPushEvent(
     const PushEventPayload& payload,
-    mojom::ServiceWorkerEventDispatcher::DispatchPushEventCallback callback) {
+    mojom::ServiceWorker::DispatchPushEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
@@ -673,8 +662,7 @@
     const PlatformNotificationData& notification_data,
     int action_index,
     const base::Optional<base::string16>& reply,
-    mojom::ServiceWorkerEventDispatcher::DispatchNotificationClickEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchNotificationClickEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
@@ -682,16 +670,14 @@
 void EmbeddedWorkerTestHelper::OnNotificationCloseEvent(
     const std::string& notification_id,
     const PlatformNotificationData& notification_data,
-    mojom::ServiceWorkerEventDispatcher::DispatchNotificationCloseEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
 }
 
 void EmbeddedWorkerTestHelper::OnAbortPaymentEvent(
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchAbortPaymentEventCallback callback) {
   response_callback->OnResponseForAbortPayment(true, base::Time::Now());
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
@@ -700,8 +686,7 @@
 void EmbeddedWorkerTestHelper::OnCanMakePaymentEvent(
     payments::mojom::CanMakePaymentEventDataPtr event_data,
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback) {
   bool can_make_payment = false;
   for (const auto& method_data : event_data->method_data) {
     if (method_data->supported_method == "test-method") {
@@ -718,8 +703,7 @@
 void EmbeddedWorkerTestHelper::OnPaymentRequestEvent(
     payments::mojom::PaymentRequestEventDataPtr event_data,
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchPaymentRequestEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback) {
   response_callback->OnResponseForPaymentRequest(
       payments::mojom::PaymentHandlerResponse::New(), base::Time::Now());
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
@@ -842,7 +826,7 @@
           &EmbeddedWorkerTestHelper::OnStartWorker, AsWeakPtr(),
           params->embedded_worker_id, params->service_worker_version_id,
           params->scope, params->script_url, params->pause_after_download,
-          std::move(params->dispatcher_request),
+          std::move(params->service_worker_request),
           std::move(params->controller_request),
           std::move(params->instance_host), std::move(params->provider_info),
           std::move(params->installed_scripts_info)));
@@ -865,8 +849,7 @@
 }
 
 void EmbeddedWorkerTestHelper::OnActivateEventStub(
-    mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchActivateEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnActivateEvent,
                                 AsWeakPtr(), std::move(callback)));
@@ -876,8 +859,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchAbortEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchAbortEvent,
@@ -888,8 +870,7 @@
 void EmbeddedWorkerTestHelper::OnBackgroundFetchClickEventStub(
     const std::string& developer_id,
     mojom::BackgroundFetchState state,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchClickEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchClickEvent,
@@ -900,8 +881,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::
-        DispatchBackgroundFetchFailEventCallback callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchFailEvent,
@@ -913,8 +893,7 @@
     const std::string& developer_id,
     const std::string& unique_id,
     const std::vector<BackgroundFetchSettledFetch>& fetches,
-    mojom::ServiceWorkerEventDispatcher::DispatchBackgroundFetchedEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnBackgroundFetchedEvent,
@@ -925,8 +904,7 @@
 void EmbeddedWorkerTestHelper::OnCookieChangeEventStub(
     const net::CanonicalCookie& cookie,
     ::network::mojom::CookieChangeCause cause,
-    mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchCookieChangeEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnCookieChangeEvent,
@@ -935,8 +913,7 @@
 
 void EmbeddedWorkerTestHelper::OnExtendableMessageEventStub(
     mojom::ExtendableMessageEventPtr event,
-    mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchExtendableMessageEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnExtendableMessageEvent,
@@ -944,8 +921,7 @@
 }
 
 void EmbeddedWorkerTestHelper::OnInstallEventStub(
-    mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchInstallEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnInstallEvent,
                                 AsWeakPtr(), std::move(callback)));
@@ -956,8 +932,7 @@
     const network::ResourceRequest& request,
     blink::mojom::FetchEventPreloadHandlePtr preload_handle,
     mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-        finish_callback) {
+    mojom::ServiceWorker::DispatchFetchEventCallback finish_callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnFetchEvent, AsWeakPtr(),
@@ -970,8 +945,7 @@
     const PlatformNotificationData& notification_data,
     int action_index,
     const base::Optional<base::string16>& reply,
-    mojom::ServiceWorkerEventDispatcher::DispatchNotificationClickEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchNotificationClickEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnNotificationClickEvent,
@@ -982,8 +956,7 @@
 void EmbeddedWorkerTestHelper::OnNotificationCloseEventStub(
     const std::string& notification_id,
     const PlatformNotificationData& notification_data,
-    mojom::ServiceWorkerEventDispatcher::DispatchNotificationCloseEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnNotificationCloseEvent,
@@ -993,7 +966,7 @@
 
 void EmbeddedWorkerTestHelper::OnPushEventStub(
     const PushEventPayload& payload,
-    mojom::ServiceWorkerEventDispatcher::DispatchPushEventCallback callback) {
+    mojom::ServiceWorker::DispatchPushEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnPushEvent,
                                 AsWeakPtr(), payload, std::move(callback)));
@@ -1001,8 +974,7 @@
 
 void EmbeddedWorkerTestHelper::OnAbortPaymentEventStub(
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchAbortPaymentEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(&EmbeddedWorkerTestHelper::OnAbortPaymentEvent,
                                 AsWeakPtr(), std::move(response_callback),
@@ -1012,8 +984,7 @@
 void EmbeddedWorkerTestHelper::OnCanMakePaymentEventStub(
     payments::mojom::CanMakePaymentEventDataPtr event_data,
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnCanMakePaymentEvent,
@@ -1024,8 +995,7 @@
 void EmbeddedWorkerTestHelper::OnPaymentRequestEventStub(
     payments::mojom::PaymentRequestEventDataPtr event_data,
     payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-    mojom::ServiceWorkerEventDispatcher::DispatchPaymentRequestEventCallback
-        callback) {
+    mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&EmbeddedWorkerTestHelper::OnPaymentRequestEvent,
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index ad86a0f..7f7b5916 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -149,14 +149,14 @@
  protected:
   // StartWorker IPC handler routed through MockEmbeddedWorkerInstanceClient.
   // This simulates behaviors in the renderer process. Binds
-  // |dispatcher_request| to MockServiceWorkerEventDispatcher by default.
+  // |service_worker_request| to MockServiceWorker by default.
   virtual void OnStartWorker(
       int embedded_worker_id,
       int64_t service_worker_version_id,
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -170,79 +170,65 @@
   // On*Event handlers. By default they just return success via
   // SimulateSendReplyToBrowser.
   virtual void OnActivateEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchActivateEventCallback callback);
   virtual void OnBackgroundFetchAbortEvent(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchAbortEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback);
   virtual void OnBackgroundFetchClickEvent(
       const std::string& developer_id,
       mojom::BackgroundFetchState state,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchClickEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback);
   virtual void OnBackgroundFetchFailEvent(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchFailEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback);
   virtual void OnBackgroundFetchedEvent(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchedEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback);
   virtual void OnCookieChangeEvent(
       const net::CanonicalCookie& cookie,
       ::network::mojom::CookieChangeCause cause,
-      mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchCookieChangeEventCallback callback);
   virtual void OnExtendableMessageEvent(
       mojom::ExtendableMessageEventPtr event,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchExtendableMessageEventCallback callback);
+      mojom::ServiceWorker::DispatchExtendableMessageEventCallback callback);
   virtual void OnInstallEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchInstallEventCallback callback);
   virtual void OnFetchEvent(
       int embedded_worker_id,
       const network::ResourceRequest& request,
       blink::mojom::FetchEventPreloadHandlePtr preload_handle,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback);
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback);
   virtual void OnNotificationClickEvent(
       const std::string& notification_id,
       const PlatformNotificationData& notification_data,
       int action_index,
       const base::Optional<base::string16>& reply,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchNotificationClickEventCallback callback);
+      mojom::ServiceWorker::DispatchNotificationClickEventCallback callback);
   virtual void OnNotificationCloseEvent(
       const std::string& notification_id,
       const PlatformNotificationData& notification_data,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchNotificationCloseEventCallback callback);
+      mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback);
   virtual void OnPushEvent(
       const PushEventPayload& payload,
-      mojom::ServiceWorkerEventDispatcher::DispatchPushEventCallback callback);
+      mojom::ServiceWorker::DispatchPushEventCallback callback);
   virtual void OnAbortPaymentEvent(
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchAbortPaymentEventCallback callback);
   virtual void OnCanMakePaymentEvent(
       payments::mojom::CanMakePaymentEventDataPtr data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback);
   virtual void OnPaymentRequestEvent(
       payments::mojom::PaymentRequestEventDataPtr data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchPaymentRequestEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback);
 
   // These functions simulate making Mojo calls to the browser.
   void SimulateWorkerReadyForInspection(int embedded_worker_id);
@@ -264,7 +250,7 @@
 
  private:
   class MockNetworkURLLoaderFactory;
-  class MockServiceWorkerEventDispatcher;
+  class MockServiceWorker;
   class MockRendererInterface;
 
   void DidSimulateWorkerScriptCached(int embedded_worker_id,
@@ -278,79 +264,65 @@
   void OnResumeAfterDownloadStub(int embedded_worker_id);
   void OnStopWorkerStub(int embedded_worker_id);
   void OnActivateEventStub(
-      mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchActivateEventCallback callback);
   void OnBackgroundFetchAbortEventStub(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchAbortEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchAbortEventCallback callback);
   void OnBackgroundFetchClickEventStub(
       const std::string& developer_id,
       mojom::BackgroundFetchState state,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchClickEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchClickEventCallback callback);
   void OnBackgroundFetchFailEventStub(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchFailEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchFailEventCallback callback);
   void OnBackgroundFetchedEventStub(
       const std::string& developer_id,
       const std::string& unique_id,
       const std::vector<BackgroundFetchSettledFetch>& fetches,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchBackgroundFetchedEventCallback callback);
+      mojom::ServiceWorker::DispatchBackgroundFetchedEventCallback callback);
   void OnCookieChangeEventStub(
       const net::CanonicalCookie& cookie,
       ::network::mojom::CookieChangeCause cause,
-      mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchCookieChangeEventCallback callback);
   void OnExtendableMessageEventStub(
       mojom::ExtendableMessageEventPtr event,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchExtendableMessageEventCallback callback);
+      mojom::ServiceWorker::DispatchExtendableMessageEventCallback callback);
   void OnInstallEventStub(
-      mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchInstallEventCallback callback);
   void OnFetchEventStub(
       int embedded_worker_id,
       const network::ResourceRequest& request,
       blink::mojom::FetchEventPreloadHandlePtr preload_handle,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback);
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback);
   void OnNotificationClickEventStub(
       const std::string& notification_id,
       const PlatformNotificationData& notification_data,
       int action_index,
       const base::Optional<base::string16>& reply,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchNotificationClickEventCallback callback);
+      mojom::ServiceWorker::DispatchNotificationClickEventCallback callback);
   void OnNotificationCloseEventStub(
       const std::string& notification_id,
       const PlatformNotificationData& notification_data,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchNotificationCloseEventCallback callback);
+      mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback);
   void OnPushEventStub(
       const PushEventPayload& payload,
-      mojom::ServiceWorkerEventDispatcher::DispatchPushEventCallback callback);
+      mojom::ServiceWorker::DispatchPushEventCallback callback);
   void OnAbortPaymentEventStub(
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchAbortPaymentEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchAbortPaymentEventCallback callback);
   void OnCanMakePaymentEventStub(
       payments::mojom::CanMakePaymentEventDataPtr data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchCanMakePaymentEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchCanMakePaymentEventCallback callback);
   void OnPaymentRequestEventStub(
       payments::mojom::PaymentRequestEventDataPtr data,
       payments::mojom::PaymentHandlerResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchPaymentRequestEventCallback
-          callback);
+      mojom::ServiceWorker::DispatchPaymentRequestEventCallback callback);
 
   std::unique_ptr<TestBrowserContext> browser_context_;
   std::unique_ptr<MockRenderProcessHost> render_process_host_;
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 61c17d1..d8275ba 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -810,7 +810,7 @@
     int request_id =
         version_->StartRequest(ServiceWorkerMetrics::EventType::INSTALL,
                                CreateReceiver(BrowserThread::UI, done, result));
-    version_->event_dispatcher()->DispatchInstallEvent(
+    version_->endpoint()->DispatchInstallEvent(
         base::BindOnce(&self::ReceiveInstallEventOnIOThread,
                        base::Unretained(this), done, result, request_id));
   }
@@ -867,7 +867,7 @@
     int request_id =
         version_->StartRequest(ServiceWorkerMetrics::EventType::INSTALL,
                                CreateReceiver(BrowserThread::UI, done, result));
-    version_->event_dispatcher()->DispatchActivateEvent(
+    version_->endpoint()->DispatchActivateEvent(
         version_->CreateSimpleEventCallback(request_id));
   }
 
diff --git a/content/browser/service_worker/service_worker_context_unittest.cc b/content/browser/service_worker/service_worker_context_unittest.cc
index 9a4f211..52d1e62 100644
--- a/content/browser/service_worker/service_worker_context_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_unittest.cc
@@ -90,8 +90,7 @@
   RejectInstallTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
 
   void OnInstallEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchInstallEventCallback callback) override {
     dispatched_events()->push_back(Event::Install);
     std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
                             true /* has_fetch_handler */, base::Time::Now());
@@ -103,8 +102,7 @@
   RejectActivateTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
 
   void OnActivateEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchActivateEventCallback callback) override {
     dispatched_events()->push_back(Event::Activate);
     std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::REJECTED,
                             base::Time::Now());
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index 8faadf7..ede12c7 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "content/common/content_export.h"
-#include "content/common/service_worker/service_worker.mojom.h"
+#include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host_observer.h"
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 32a3d62..71d9109 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -607,11 +607,11 @@
   params->request_body_blob = request_body_blob_.PassInterface();
   params->client_id = client_id_;
   params->preload_handle = std::move(preload_handle_);
-  // |event_dispatcher| is owned by |version_|. So it is safe to pass the
+  // |endpoint()| is owned by |version_|. So it is safe to pass the
   // unretained raw pointer of |version_| to OnFetchEventFinished callback.
   // Pass |url_loader_assets_| to the callback to keep the URL loader related
   // assets alive while the FetchEvent is ongoing in the service worker.
-  version_->event_dispatcher()->DispatchFetchEvent(
+  version_->endpoint()->DispatchFetchEvent(
       std::move(params), std::move(response_callback_ptr),
       base::BindOnce(&ServiceWorkerFetchDispatcher::OnFetchEventFinished,
                      base::Unretained(version_.get()), event_finish_id,
diff --git a/content/browser/service_worker/service_worker_job_unittest.cc b/content/browser/service_worker/service_worker_job_unittest.cc
index dd6ea0e..724ffb5 100644
--- a/content/browser/service_worker/service_worker_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_job_unittest.cc
@@ -483,7 +483,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -949,7 +949,7 @@
       const GURL& scope,
       const GURL& script,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -1011,7 +1011,7 @@
     started_workers_.insert(embedded_worker_id);
     EmbeddedWorkerTestHelper::OnStartWorker(
         embedded_worker_id, version_id, scope, script, pause_after_download,
-        std::move(dispatcher_request), std::move(controller_request),
+        std::move(service_worker_request), std::move(controller_request),
         std::move(instance_host), std::move(provider_info),
         std::move(installed_scripts_info));
   }
@@ -1089,7 +1089,7 @@
       const GURL& scope,
       const GURL& script,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -1108,7 +1108,7 @@
     }
     UpdateJobTestHelper::OnStartWorker(
         embedded_worker_id, version_id, scope, script, pause_after_download,
-        std::move(dispatcher_request), std::move(controller_request),
+        std::move(service_worker_request), std::move(controller_request),
         std::move(instance_host), std::move(provider_info),
         std::move(installed_scripts_info));
   }
@@ -1610,8 +1610,7 @@
             blink::mojom::ServiceWorkerEventStatus::COMPLETED) {}
 
   void OnInstallEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchInstallEventCallback callback) override {
     if (!install_callback_.is_null())
       install_callback_.Run();
     std::move(callback).Run(install_event_result_, has_fetch_handler_,
@@ -1619,8 +1618,7 @@
   }
 
   void OnActivateEvent(
-      mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
-          callback) override {
+      mojom::ServiceWorker::DispatchActivateEventCallback callback) override {
     std::move(callback).Run(activate_event_result_, base::Time::Now());
   }
 
diff --git a/content/browser/service_worker/service_worker_metrics_unittest.cc b/content/browser/service_worker/service_worker_metrics_unittest.cc
index b154ddb..4a1afc8 100644
--- a/content/browser/service_worker/service_worker_metrics_unittest.cc
+++ b/content/browser/service_worker/service_worker_metrics_unittest.cc
@@ -8,6 +8,7 @@
 #include "content/browser/service_worker/embedded_worker_status.h"
 #include "content/test/test_content_browser_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 
 namespace content {
 
@@ -96,11 +97,15 @@
         kPreparationType, static_cast<int>(WorkerPreparationType::STARTING), 1);
     histogram_tester.ExpectTotalCount(
         kPreparationType + kNavigationPreloadSuffix, 0);
-    histogram_tester.ExpectTimeBucketCount(kPreparationTime, time, 1);
-    histogram_tester.ExpectTimeBucketCount(kPreparationTime + "_StartingWorker",
-                                           time, 1);
-    histogram_tester.ExpectTotalCount(
-        kPreparationTime + kNavigationPreloadSuffix, 0);
+
+    // We don't record .Time histograms when S13nServiceWorker is enabled.
+    if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+      histogram_tester.ExpectTimeBucketCount(kPreparationTime, time, 1);
+      histogram_tester.ExpectTimeBucketCount(
+          kPreparationTime + "_StartingWorker", time, 1);
+      histogram_tester.ExpectTotalCount(
+          kPreparationTime + kNavigationPreloadSuffix, 0);
+    }
   }
 
   {
@@ -115,11 +120,16 @@
     histogram_tester.ExpectUniqueSample(
         kPreparationType + kNavigationPreloadSuffix,
         static_cast<int>(WorkerPreparationType::START_DURING_STARTUP), 1);
-    histogram_tester.ExpectTimeBucketCount(kPreparationTime, time, 1);
-    histogram_tester.ExpectTimeBucketCount(
-        kPreparationTime + kNavigationPreloadSuffix, time, 1);
-    histogram_tester.ExpectTotalCount(
-        kPreparationTime + kWorkerStartOccurred + kNavigationPreloadSuffix, 1);
+
+    // We don't record .Time histograms when S13nServiceWorker is enabled.
+    if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+      histogram_tester.ExpectTimeBucketCount(kPreparationTime, time, 1);
+      histogram_tester.ExpectTimeBucketCount(
+          kPreparationTime + kNavigationPreloadSuffix, time, 1);
+      histogram_tester.ExpectTotalCount(
+          kPreparationTime + kWorkerStartOccurred + kNavigationPreloadSuffix,
+          1);
+    }
   }
 
   {
@@ -139,12 +149,16 @@
         static_cast<int>(
             WorkerPreparationType::START_IN_EXISTING_READY_PROCESS),
         1);
-    histogram_tester.ExpectTimeBucketCount(kPreparationTime, time, 1);
-    histogram_tester.ExpectTimeBucketCount(
-        kPreparationTime + kNavigationPreloadSuffix, time, 1);
-    histogram_tester.ExpectTimeBucketCount(
-        kPreparationTime + kWorkerStartOccurred + kNavigationPreloadSuffix,
-        time, 1);
+
+    // We don't record .Time histograms when S13nServiceWorker is enabled.
+    if (!blink::ServiceWorkerUtils::IsServicificationEnabled()) {
+      histogram_tester.ExpectTimeBucketCount(kPreparationTime, time, 1);
+      histogram_tester.ExpectTimeBucketCount(
+          kPreparationTime + kNavigationPreloadSuffix, time, 1);
+      histogram_tester.ExpectTimeBucketCount(
+          kPreparationTime + kWorkerStartOccurred + kNavigationPreloadSuffix,
+          time, 1);
+    }
   }
 
   // Suffixed metric test.
diff --git a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
index 1cad5b79..5517d86 100644
--- a/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader_unittest.cc
@@ -72,8 +72,7 @@
   NavigationPreloadLoaderClient(
       blink::mojom::FetchEventPreloadHandlePtr preload_handle,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback)
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
       : url_loader_(std::move(preload_handle->url_loader)),
         binding_(this, std::move(preload_handle->url_loader_client_request)),
         response_callback_(std::move(response_callback)),
@@ -144,8 +143,7 @@
 
   // Callbacks that complete Helper::OnFetchEvent().
   mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
-  mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-      finish_callback_;
+  mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(NavigationPreloadLoaderClient);
 };
@@ -233,8 +231,8 @@
       const network::ResourceRequest& request,
       blink::mojom::FetchEventPreloadHandlePtr preload_handle,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     // Basic checks on DispatchFetchEvent parameters.
     EXPECT_TRUE(ServiceWorkerUtils::IsMainResourceType(
         static_cast<ResourceType>(request.resource_type)));
@@ -319,7 +317,7 @@
         SimulateWorkerStopped(embedded_worker_id);
         // Finish the event by calling |finish_callback|.
         // This is the Mojo callback for
-        // mojom::ServiceWorkerEventDispatcher::DispatchFetchEvent().
+        // mojom::ServiceWorker::DispatchFetchEvent().
         // If this is not called, Mojo will complain. In production code,
         // ServiceWorkerContextClient would call this when it aborts all
         // callbacks after an unexpected stop.
@@ -388,8 +386,7 @@
   blink::mojom::ServiceWorkerStreamHandlePtr stream_handle_;
 
   // For ResponseMode::kEarlyResponse.
-  mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-      finish_callback_;
+  mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_;
 
   // For ResponseMode::kRedirect.
   GURL redirected_url_;
diff --git a/content/browser/service_worker/service_worker_object_host.cc b/content/browser/service_worker/service_worker_object_host.cc
index 234b3d9..0af7708f 100644
--- a/content/browser/service_worker/service_worker_object_host.cc
+++ b/content/browser/service_worker/service_worker_object_host.cc
@@ -54,7 +54,7 @@
     request_id = worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE,
                                       std::move(callback));
   }
-  worker->event_dispatcher()->DispatchExtendableMessageEvent(
+  worker->endpoint()->DispatchExtendableMessageEvent(
       std::move(event), worker->CreateSimpleEventCallback(request_id));
 }
 
diff --git a/content/browser/service_worker/service_worker_object_host_unittest.cc b/content/browser/service_worker/service_worker_object_host_unittest.cc
index eec3157..fd1ca22 100644
--- a/content/browser/service_worker/service_worker_object_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_object_host_unittest.cc
@@ -52,8 +52,8 @@
 
   void OnExtendableMessageEvent(
       mojom::ExtendableMessageEventPtr event,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchExtendableMessageEventCallback callback) override {
+      mojom::ServiceWorker::DispatchExtendableMessageEventCallback callback)
+      override {
     events_.push_back(std::move(event));
     std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                             base::Time::Now());
@@ -77,7 +77,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 7c558f6..8517418 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -288,9 +288,9 @@
   // ServiceWorkerRegistrationObjectHosts owned by |this|. Otherwise, this
   // destructor can trigger their Mojo connection error handlers, which would
   // call back into halfway destroyed |this|. This is because they are
-  // associated with the ServiceWorkerEventDispatcher interface, which can
-  // be destroyed while in this destructor (|running_hosted_version_|'s
-  // |event_dispatcher_|). See https://crbug.com/854993.
+  // associated with the ServiceWorker interface, which can be destroyed while
+  // in this destructor (|running_hosted_version_|'s |event_dispatcher_|). See
+  // https://crbug.com/854993.
   service_worker_object_hosts_.clear();
   registration_object_hosts_.clear();
 }
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index f2debd9..02f88cf 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -446,7 +446,7 @@
       base::BindOnce(&ServiceWorkerRegisterJob::OnInstallFailed,
                      weak_factory_.GetWeakPtr()));
 
-  new_version()->event_dispatcher()->DispatchInstallEvent(
+  new_version()->endpoint()->DispatchInstallEvent(
       base::BindOnce(&ServiceWorkerRegisterJob::OnInstallFinished,
                      weak_factory_.GetWeakPtr(), request_id));
 }
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc
index 0c029ee..dec3431 100644
--- a/content/browser/service_worker/service_worker_registration.cc
+++ b/content/browser/service_worker/service_worker_registration.cc
@@ -217,7 +217,7 @@
       // If the waiting worker is ready and the active worker needs to be
       // swapped out, ask the active worker to trigger idle timer as soon as
       // possible.
-      active_version()->event_dispatcher()->SetIdleTimerDelayToZero();
+      active_version()->endpoint()->SetIdleTimerDelayToZero();
     }
     StartLameDuckTimer();
   }
@@ -300,7 +300,7 @@
       // If the waiting worker is ready and the active worker needs to be
       // swapped out, ask the active worker to trigger idle timer as soon as
       // possible.
-      active_version()->event_dispatcher()->SetIdleTimerDelayToZero();
+      active_version()->endpoint()->SetIdleTimerDelayToZero();
     }
     StartLameDuckTimer();
   }
@@ -515,7 +515,7 @@
       ServiceWorkerMetrics::EventType::ACTIVATE,
       base::BindOnce(&ServiceWorkerRegistration::OnActivateEventFinished, this,
                      activating_version));
-  activating_version->event_dispatcher()->DispatchActivateEvent(
+  activating_version->endpoint()->DispatchActivateEvent(
       activating_version->CreateSimpleEventCallback(request_id));
 }
 
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 41459db1..ce237a44 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -497,7 +497,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -508,7 +508,7 @@
     scope_ = scope;
     script_url_ = script_url;
     pause_after_download_ = pause_after_download;
-    start_worker_request_ = std::move(dispatcher_request);
+    start_worker_request_ = std::move(service_worker_request);
     controller_request_ = std::move(controller_request);
     start_worker_instance_host_ = std::move(instance_host);
     provider_info_ = std::move(provider_info);
@@ -520,8 +520,8 @@
       const network::ResourceRequest& /* request */,
       blink::mojom::FetchEventPreloadHandlePtr preload_handle,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     embedded_worker_id_ = embedded_worker_id;
     response_callback_ = std::move(response_callback);
     finish_callback_ = std::move(finish_callback);
@@ -533,7 +533,7 @@
   GURL scope_;
   GURL script_url_;
   bool pause_after_download_;
-  mojom::ServiceWorkerEventDispatcherRequest start_worker_request_;
+  mojom::ServiceWorkerRequest start_worker_request_;
   mojom::ControllerServiceWorkerRequest controller_request_;
   mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo
       start_worker_instance_host_;
@@ -542,8 +542,7 @@
   int embedded_worker_id_ = 0;
   mojom::ServiceWorkerFetchResponseCallbackPtr response_callback_;
   blink::mojom::FetchEventPreloadHandlePtr preload_handle_;
-  mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-      finish_callback_;
+  mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_;
   ServiceWorkerURLRequestJobTest* test_;
   DISALLOW_COPY_AND_ASSIGN(DelayHelper);
 };
@@ -699,8 +698,8 @@
       const network::ResourceRequest& /* request */,
       blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     context()->RemoveProviderHost(mock_render_process_id(), kProviderID);
     response_callback->OnResponse(
         ServiceWorkerResponse(
@@ -789,8 +788,8 @@
       const network::ResourceRequest& /* request */,
       blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     response_callback->OnResponse(
         ServiceWorkerResponse(
             std::make_unique<std::vector<GURL>>(), 200, "OK",
@@ -890,8 +889,8 @@
       const network::ResourceRequest& /* request */,
       blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     ASSERT_FALSE(stream_handle_.is_null());
     response_callback->OnResponseStream(
         ServiceWorkerResponse(
@@ -1280,8 +1279,8 @@
       const network::ResourceRequest& /* request */,
       blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
       mojom::ServiceWorkerFetchResponseCallbackPtr /* response_callback */,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     SimulateWorkerStopped(embedded_worker_id);
     std::move(finish_callback)
         .Run(blink::mojom::ServiceWorkerEventStatus::ABORTED,
@@ -1373,8 +1372,8 @@
       const network::ResourceRequest& /* request */,
       blink::mojom::FetchEventPreloadHandlePtr /* preload_handle */,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
-      mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-          finish_callback) override {
+      mojom::ServiceWorker::DispatchFetchEventCallback finish_callback)
+      override {
     finish_callback_ = std::move(finish_callback);
     response_callback->OnResponse(
         ServiceWorkerResponse(
@@ -1391,8 +1390,7 @@
   }
 
  private:
-  mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
-      finish_callback_;
+  mojom::ServiceWorker::DispatchFetchEventCallback finish_callback_;
   DISALLOW_COPY_AND_ASSIGN(EarlyResponseHelper);
 };
 
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 25bde9d7..f6153f9b 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -145,8 +145,7 @@
   return trace_id;
 }
 
-void OnEventDispatcherConnectionError(
-    base::WeakPtr<EmbeddedWorkerInstance> embedded_worker) {
+void OnConnectionError(base::WeakPtr<EmbeddedWorkerInstance> embedded_worker) {
   if (!embedded_worker)
     return;
 
@@ -660,7 +659,7 @@
 ServiceWorkerVersion::SimpleEventCallback
 ServiceWorkerVersion::CreateSimpleEventCallback(int request_id) {
   // The weak reference to |this| is safe because storage of the callbacks, the
-  // inflight responses of the ServiceWorkerEventDispatcher, is owned by |this|.
+  // inflight responses of mojom::ServiceWorker messages, is owned by |this|.
   return base::BindOnce(&ServiceWorkerVersion::OnSimpleEventFinished,
                         base::Unretained(this), request_id);
 }
@@ -1486,12 +1485,12 @@
     installed_scripts_sender_->Start();
   }
 
-  params->dispatcher_request = mojo::MakeRequest(&event_dispatcher_);
+  params->service_worker_request = mojo::MakeRequest(&service_worker_ptr_);
   // TODO(horo): These CHECKs are for debugging crbug.com/759938.
-  CHECK(event_dispatcher_.is_bound());
-  CHECK(params->dispatcher_request.is_pending());
-  event_dispatcher_.set_connection_error_handler(base::BindOnce(
-      &OnEventDispatcherConnectionError, embedded_worker_->AsWeakPtr()));
+  CHECK(service_worker_ptr_.is_bound());
+  CHECK(params->service_worker_request.is_pending());
+  service_worker_ptr_.set_connection_error_handler(
+      base::BindOnce(&OnConnectionError, embedded_worker_->AsWeakPtr()));
   blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host;
   binding_.Close();
   binding_.Bind(mojo::MakeRequest(&service_worker_host));
@@ -1499,7 +1498,7 @@
       context_->GetLiveRegistration(registration_id_);
   DCHECK(registration);
   provider_host->SetDocumentUrl(script_url());
-  event_dispatcher_->InitializeGlobalScope(
+  service_worker_ptr_->InitializeGlobalScope(
       std::move(service_worker_host),
       provider_host->CreateServiceWorkerRegistrationObjectInfo(
           scoped_refptr<ServiceWorkerRegistration>(registration)));
@@ -1664,9 +1663,10 @@
   // TODO(horo): This CHECK is for debugging crbug.com/759938.
   CHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
         running_status() == EmbeddedWorkerStatus::RUNNING);
-  // base::Unretained here is safe because event_dispatcher is owned by |this|.
-  event_dispatcher()->Ping(base::BindOnce(
-      &ServiceWorkerVersion::OnPongFromWorker, base::Unretained(this)));
+  // base::Unretained here is safe because endpoint() is owned by
+  // |this|.
+  endpoint()->Ping(base::BindOnce(&ServiceWorkerVersion::OnPongFromWorker,
+                                  base::Unretained(this)));
 }
 
 void ServiceWorkerVersion::OnPingTimeout() {
@@ -1933,7 +1933,7 @@
   inflight_requests_.Clear();
   request_timeouts_.clear();
   external_request_uuid_to_request_id_.clear();
-  event_dispatcher_.reset();
+  service_worker_ptr_.reset();
   controller_ptr_.reset();
   DCHECK(!controller_request_.is_pending());
   installed_scripts_sender_.reset();
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index c7a756ca..c4316e97b 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -293,10 +293,10 @@
 
   // Same as StartRequest, but allows the caller to specify a custom timeout for
   // the event, as well as the behavior for when the request times out.
-  // S13nServiceWorker: |timeout| and |timeout_behavior| don't have any
-  // effect. They are just ignored. Timeouts can be added to the
-  // mojom::ServiceWorkerEventDispatcher interface instead (see
-  // DispatchSyncEvent for an example).
+  //
+  // S13nServiceWorker: |timeout| and |timeout_behavior| don't have any effect.
+  // They are just ignored. Timeouts can be added to the mojom::ServiceWorker
+  // interface instead (see DispatchSyncEvent for an example).
   int StartRequestWithCustomTimeout(ServiceWorkerMetrics::EventType event_type,
                                     StatusCallback error_callback,
                                     const base::TimeDelta& timeout,
@@ -324,19 +324,19 @@
   bool FinishExternalRequest(const std::string& request_uuid);
 
   // Creates a callback that is to be used for marking simple events dispatched
-  // through the ServiceWorkerEventDispatcher as finished for the |request_id|.
+  // through mojom::ServiceWorker as finished for the |request_id|.
   // Simple event means those events expecting a response with only a status
   // code and the dispatch time. See service_worker_event_dispatcher.mojom.
   SimpleEventCallback CreateSimpleEventCallback(int request_id);
 
   // This must be called when the worker is running.
-  mojom::ServiceWorkerEventDispatcher* event_dispatcher() {
+  mojom::ServiceWorker* endpoint() {
     DCHECK(running_status() == EmbeddedWorkerStatus::STARTING ||
            running_status() == EmbeddedWorkerStatus::RUNNING);
     // Temporarily CHECK for debugging https://crbug.com/817981.
-    CHECK(event_dispatcher_.is_bound());
-    CHECK(event_dispatcher_.get());
-    return event_dispatcher_.get();
+    CHECK(service_worker_ptr_.is_bound());
+    CHECK(service_worker_ptr_.get());
+    return service_worker_ptr_.get();
   }
 
   // S13nServiceWorker:
@@ -674,7 +674,7 @@
   void StartWorkerInternal();
 
   // Callback function for simple events dispatched through mojo interface
-  // mojom::ServiceWorkerEventDispatcher. Use CreateSimpleEventCallback() to
+  // mojom::ServiceWorker. Use CreateSimpleEventCallback() to
   // create a callback for a given |request_id|.
   void OnSimpleEventFinished(int request_id,
                              blink::mojom::ServiceWorkerEventStatus status,
@@ -777,7 +777,7 @@
   std::set<std::string> pending_external_requests_;
 
   // Connected to ServiceWorkerContextClient while the worker is running.
-  mojom::ServiceWorkerEventDispatcherPtr event_dispatcher_;
+  mojom::ServiceWorkerPtr service_worker_ptr_;
 
   // S13nServiceWorker: connected to the controller service worker.
   // |controller_request_| is non-null only when the |controller_ptr_| is
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 204bc1b..2b3f970 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -245,7 +245,7 @@
       const GURL& scope,
       const GURL& script_url,
       bool pause_after_download,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -257,8 +257,8 @@
         instance_host_ptr_map_[embedded_worker_id].Bind(
             std::move(instance_host));
         // Just keep the connection alive.
-        event_dispatcher_request_map_[embedded_worker_id] =
-            std::move(dispatcher_request);
+        service_worker_request_map_[embedded_worker_id] =
+            std::move(service_worker_request);
         controller_request_map_[embedded_worker_id] =
             std::move(controller_request);
         break;
@@ -271,7 +271,7 @@
       case StartMode::SUCCEED:
         MessageReceiver::OnStartWorker(
             embedded_worker_id, service_worker_version_id, scope, script_url,
-            pause_after_download, std::move(dispatcher_request),
+            pause_after_download, std::move(service_worker_request),
             std::move(controller_request), std::move(instance_host),
             std::move(provider_info), std::move(installed_scripts_info));
         break;
@@ -298,9 +298,8 @@
       int /* embedded_worker_id */,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtr /* instance_host_ptr */>
       instance_host_ptr_map_;
-  std::map<int /* embedded_worker_id */,
-           mojom::ServiceWorkerEventDispatcherRequest>
-      event_dispatcher_request_map_;
+  std::map<int /* embedded_worker_id */, mojom::ServiceWorkerRequest>
+      service_worker_request_map_;
   std::map<int /* embedded_worker_id */, mojom::ControllerServiceWorkerRequest>
       controller_request_map_;
   DISALLOW_COPY_AND_ASSIGN(MessageReceiverDisallowStart);
@@ -836,8 +835,8 @@
 
   void OnExtendableMessageEvent(
       mojom::ExtendableMessageEventPtr event,
-      mojom::ServiceWorkerEventDispatcher::
-          DispatchExtendableMessageEventCallback callback) override {
+      mojom::ServiceWorker::DispatchExtendableMessageEventCallback callback)
+      override {
     EXPECT_FALSE(extendable_message_event_callback_);
     extendable_message_event_callback_ = std::move(callback);
   }
@@ -853,7 +852,7 @@
     return !extendable_message_event_callback_.is_null();
   }
 
-  mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback
+  mojom::ServiceWorker::DispatchExtendableMessageEventCallback
   TakeExtendableMessageEventCallback() {
     return std::move(extendable_message_event_callback_);
   }
@@ -863,7 +862,7 @@
   }
 
  private:
-  mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback
+  mojom::ServiceWorker::DispatchExtendableMessageEventCallback
       extendable_message_event_callback_;
   base::OnceClosure stop_worker_callback_;
 };
@@ -881,7 +880,7 @@
         ->has_extendable_message_event_callback();
   }
 
-  mojom::ServiceWorkerEventDispatcher::DispatchExtendableMessageEventCallback
+  mojom::ServiceWorker::DispatchExtendableMessageEventCallback
   TakeExtendableMessageEventCallback() {
     return static_cast<MessageReceiverControlEvents*>(helper_.get())
         ->TakeExtendableMessageEventCallback();
@@ -909,7 +908,7 @@
 
   // Dispatch a dummy event whose response will be received by SWVersion.
   EXPECT_FALSE(has_extendable_message_event_callback());
-  version_->event_dispatcher()->DispatchExtendableMessageEvent(
+  version_->endpoint()->DispatchExtendableMessageEvent(
       mojom::ExtendableMessageEvent::New(),
       version_->CreateSimpleEventCallback(request_id));
 
diff --git a/content/browser/shared_worker/mock_shared_worker.cc b/content/browser/shared_worker/mock_shared_worker.cc
index d254552..829d18dc 100644
--- a/content/browser/shared_worker/mock_shared_worker.cc
+++ b/content/browser/shared_worker/mock_shared_worker.cc
@@ -98,6 +98,7 @@
     mojom::SharedWorkerInfoPtr info,
     bool pause_on_start,
     const base::UnguessableToken& devtools_worker_token,
+    const RendererPreferences& renderer_preferences,
     blink::mojom::WorkerContentSettingsProxyPtr content_settings,
     mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
         service_worker_provider_info,
diff --git a/content/browser/shared_worker/mock_shared_worker.h b/content/browser/shared_worker/mock_shared_worker.h
index 3bf4d4d..7d99113c 100644
--- a/content/browser/shared_worker/mock_shared_worker.h
+++ b/content/browser/shared_worker/mock_shared_worker.h
@@ -67,6 +67,7 @@
       mojom::SharedWorkerInfoPtr info,
       bool pause_on_start,
       const base::UnguessableToken& devtools_worker_token,
+      const RendererPreferences& renderer_preferences,
       blink::mojom::WorkerContentSettingsProxyPtr content_settings,
       mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
           service_worker_provider_info,
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index eff04c7..407310c 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -141,6 +141,11 @@
   devtools_handle_ = std::make_unique<ScopedDevToolsHandle>(
       this, &pause_on_start, &devtools_worker_token);
 
+  RendererPreferences renderer_preferences;
+  GetContentClient()->browser()->UpdateRendererPreferencesForWorker(
+      RenderProcessHost::FromID(process_id_)->GetBrowserContext(),
+      &renderer_preferences);
+
   // Set up content settings interface.
   blink::mojom::WorkerContentSettingsProxyPtr content_settings;
   content_settings_ = std::make_unique<SharedWorkerContentSettingsProxyImpl>(
@@ -183,9 +188,9 @@
   factory_ = std::move(factory);
   factory_->CreateSharedWorker(
       std::move(info), pause_on_start, devtools_worker_token,
-      std::move(content_settings), std::move(service_worker_provider_info),
-      std::move(script_loader_factory), std::move(factory_bundle),
-      std::move(host), std::move(worker_request_),
+      renderer_preferences, std::move(content_settings),
+      std::move(service_worker_provider_info), std::move(script_loader_factory),
+      std::move(factory_bundle), std::move(host), std::move(worker_request_),
       std::move(interface_provider));
 
   // Monitor the lifetime of the worker.
diff --git a/content/browser/shared_worker/shared_worker_host_unittest.cc b/content/browser/shared_worker/shared_worker_host_unittest.cc
index bf37fab..f90a0342 100644
--- a/content/browser/shared_worker/shared_worker_host_unittest.cc
+++ b/content/browser/shared_worker/shared_worker_host_unittest.cc
@@ -14,6 +14,8 @@
 #include "content/browser/shared_worker/shared_worker_connector_impl.h"
 #include "content/browser/shared_worker/shared_worker_instance.h"
 #include "content/browser/shared_worker/shared_worker_service_impl.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_storage_partition.h"
 #include "content/public/test/test_utils.h"
@@ -31,7 +33,8 @@
 class SharedWorkerHostTest : public testing::Test {
  public:
   SharedWorkerHostTest()
-      : service_(&storage_partition_, nullptr /* service_worker_context */) {
+      : mock_render_process_host_(&browser_context_),
+        service_(&storage_partition_, nullptr /* service_worker_context */) {
     storage_partition_.set_network_context(&network_context_);
   }
 
@@ -52,7 +55,7 @@
         content_security_policy_type, creation_address_space,
         creation_context_type);
     auto host = std::make_unique<SharedWorkerHost>(
-        &service_, std::move(instance), 11 /* dummy process_id */);
+        &service_, std::move(instance), mock_render_process_host_.GetID());
     auto weak_host = host->AsWeakPtr();
     service_.worker_hosts_.insert(std::move(host));
     return weak_host;
@@ -79,6 +82,8 @@
   TestBrowserThreadBundle test_browser_thread_bundle_;
   TestStoragePartition storage_partition_;
   network::TestNetworkContext network_context_;
+  TestBrowserContext browser_context_;
+  MockRenderProcessHost mock_render_process_host_;
 
   SharedWorkerServiceImpl service_;
 
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 0f7b70d..df77d7f 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -449,10 +449,30 @@
   // This is useful for cases like file URLs.
   if (!origin.unique()) {
     // Prefer to use the scheme of |origin| rather than |url|, to correctly
-    // cover blob: and filesystem: URIs (see also https://crbug.com/697111).
+    // cover blob:file: and filesystem:file: URIs (see also
+    // https://crbug.com/697111).
     DCHECK(!origin.scheme().empty());
     return GURL(origin.scheme() + ":");
   } else if (url.has_scheme()) {
+    // In some cases, it is not safe to use just the scheme as a site URL, as
+    // that might allow two URLs created by different sites to to share a
+    // process.  See https://crbug.com/863623.
+    //
+    // TODO(alexmos,creis): This should eventually be expanded to certain other
+    // schemes, such as data: and file:.
+    if (url.SchemeIsBlob()) {
+      // We get here for blob URLs of form blob:null/guid.  Use the full URL
+      // with the guid in that case, which isolates all blob URLs with unique
+      // origins from each other.  Remove hash from the URL, since
+      // same-document navigations shouldn't use a different site URL.
+      if (url.has_ref()) {
+        GURL::Replacements replacements;
+        replacements.ClearRef();
+        url = url.ReplaceComponents(replacements);
+      }
+      return url;
+    }
+
     DCHECK(!url.scheme().empty());
     return GURL(url.scheme() + ":");
   }
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index 6d32dbf..8e92db4 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -344,6 +344,17 @@
   EXPECT_EQ("file", site_url.scheme());
   EXPECT_FALSE(site_url.has_host());
 
+  // Blob URLs created from a unique origin use the full URL as the site URL,
+  // except for the hash.
+  test_url = GURL("blob:null/1029e5a4-2983-4b90-a585-ed217563acfeb");
+  site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+  EXPECT_EQ(site_url, test_url);
+  test_url = GURL("blob:null/1029e5a4-2983-4b90-a585-ed217563acfeb#foo");
+  site_url = SiteInstanceImpl::GetSiteForURL(nullptr, test_url);
+  EXPECT_NE(site_url, test_url);
+  EXPECT_FALSE(site_url.has_ref());
+  EXPECT_TRUE(site_url.EqualsIgnoringRef(test_url));
+
   // Private domains are preserved, appspot being such a site.
   test_url = GURL(
       "blob:http://www.example.appspot.com:44/"
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 6f457e9..7aa65cb6 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -12675,4 +12675,54 @@
             subframe->effective_frame_policy().sandbox_flags);
 }
 
+// Ensure that when two cross-site frames have subframes with unique origins,
+// and those subframes create blob URLs and navigate to them, the blob URLs end
+// up in different processes. See https://crbug.com/863623.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       TwoBlobURLsWithNullOriginDontShareProcess) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/navigation_controller/page_with_data_iframe.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+  FrameTreeNode* subframe = root->child_at(0);
+
+  // Create a blob URL in the subframe, and navigate to it.
+  TestNavigationObserver observer(shell()->web_contents());
+  std::string blob_script =
+      "var blob = new Blob(['foo'], {type : 'text/html'});"
+      "var url = URL.createObjectURL(blob);"
+      "location = url;";
+  EXPECT_TRUE(ExecuteScript(subframe, blob_script));
+  observer.Wait();
+  RenderFrameHostImpl* subframe_rfh = subframe->current_frame_host();
+  EXPECT_TRUE(subframe_rfh->GetLastCommittedURL().SchemeIsBlob());
+
+  // Open a cross-site popup and repeat these steps.
+  GURL popup_url(embedded_test_server()->GetURL(
+      "b.com", "/navigation_controller/page_with_data_iframe.html"));
+  Shell* new_shell = OpenPopup(root, popup_url, "");
+  FrameTreeNode* popup_root =
+      static_cast<WebContentsImpl*>(new_shell->web_contents())
+          ->GetFrameTree()
+          ->root();
+  FrameTreeNode* popup_subframe = popup_root->child_at(0);
+
+  TestNavigationObserver popup_observer(new_shell->web_contents());
+  EXPECT_TRUE(ExecuteScript(popup_subframe, blob_script));
+  popup_observer.Wait();
+  RenderFrameHostImpl* popup_subframe_rfh =
+      popup_subframe->current_frame_host();
+  EXPECT_TRUE(popup_subframe_rfh->GetLastCommittedURL().SchemeIsBlob());
+
+  // Ensure that the two blob subframes don't share a process or SiteInstance.
+  EXPECT_NE(subframe->current_frame_host()->GetSiteInstance(),
+            popup_subframe->current_frame_host()->GetSiteInstance());
+  EXPECT_NE(
+      subframe->current_frame_host()->GetSiteInstance()->GetProcess(),
+      popup_subframe->current_frame_host()->GetSiteInstance()->GetProcess());
+  EXPECT_NE(
+      subframe->current_frame_host()->GetSiteInstance()->GetSiteURL(),
+      popup_subframe->current_frame_host()->GetSiteInstance()->GetSiteURL());
+}
+
 }  // namespace content
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 1fdc0255..ab6a04d6 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1252,6 +1252,9 @@
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = network::mojom::kBrowserProcessId;
   params->is_corb_enabled = false;
+  params->disable_web_security =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableWebSecurity);
   if (g_url_loader_factory_callback_for_test.Get().is_null()) {
     auto request = mojo::MakeRequest(&url_loader_factory_for_browser_process_);
     GetContentClient()->browser()->WillCreateURLLoaderFactory(
diff --git a/content/browser/url_loader_factory_getter.cc b/content/browser/url_loader_factory_getter.cc
index cce04002..d3f0380 100644
--- a/content/browser/url_loader_factory_getter.cc
+++ b/content/browser/url_loader_factory_getter.cc
@@ -8,10 +8,12 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/lazy_instance.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/common/service_worker/service_worker_utils.h"
+#include "content/public/common/content_switches.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/network_service.mojom.h"
@@ -231,6 +233,9 @@
       network::mojom::URLLoaderFactoryParams::New();
   params->process_id = network::mojom::kBrowserProcessId;
   params->is_corb_enabled = false;
+  params->disable_web_security =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableWebSecurity);
   partition_->GetNetworkContext()->CreateURLLoaderFactory(
       std::move(network_factory_request), std::move(params));
 }
diff --git a/content/browser/web_package/signed_exchange_prologue.cc b/content/browser/web_package/signed_exchange_prologue.cc
index 3eb555f..8f45dc93 100644
--- a/content/browser/web_package/signed_exchange_prologue.cc
+++ b/content/browser/web_package/signed_exchange_prologue.cc
@@ -14,7 +14,7 @@
 
 constexpr char kSignedExchangeMagic[] = "sxg1-b1";
 constexpr size_t kMaximumSignatureHeaderFieldLength = 16 * 1024;
-constexpr size_t kMaximumCBORHeaderLength = 16 * 1024;
+constexpr size_t kMaximumCBORHeaderLength = 512 * 1024;
 
 }  // namespace
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index f592dc9..6ffce59 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -553,7 +553,6 @@
     "renderer_host.mojom",
     "service_worker/controller_service_worker.mojom",
     "service_worker/embedded_worker.mojom",
-    "service_worker/service_worker.mojom",
     "service_worker/service_worker_container.mojom",
     "service_worker/service_worker_event_dispatcher.mojom",
     "service_worker/service_worker_fetch_response_callback.mojom",
diff --git a/content/common/media/media_player_delegate_messages.h b/content/common/media/media_player_delegate_messages.h
index 490e067..0b82193e 100644
--- a/content/common/media/media_player_delegate_messages.h
+++ b/content/common/media/media_player_delegate_messages.h
@@ -59,8 +59,9 @@
 IPC_MESSAGE_ROUTED1(MediaPlayerDelegateMsg_EndPictureInPictureMode,
                     int /* delegate_id, distinguishes instances */)
 
-IPC_MESSAGE_ROUTED1(MediaPlayerDelegateMsg_ClickPictureInPictureControl,
-                    int /* delegate_id, distinguishes instances */)
+IPC_MESSAGE_ROUTED2(MediaPlayerDelegateMsg_ClickPictureInPictureControl,
+                    int /* delegate_id, distinguishes instances */,
+                    std::string /* control_id */)
 
 IPC_MESSAGE_ROUTED2(MediaPlayerDelegateMsg_OnPictureInPictureWindowResize,
                     int /* delegate_id, distinguishes instances */,
diff --git a/content/common/platform_notification_param_traits.h b/content/common/platform_notification_param_traits.h
index a474e2d..22d6b927 100644
--- a/content/common/platform_notification_param_traits.h
+++ b/content/common/platform_notification_param_traits.h
@@ -18,7 +18,7 @@
 #include "ipc/ipc_message_macros.h"
 
 // TODO(https://crbug.com/841329): Delete this legacy IPC code, use a pure
-// mojo struct instead from ServiceWorkerEventDispatcher mojo interface.
+// mojo struct instead from ServiceWorker mojo interface.
 IPC_ENUM_TRAITS_MAX_VALUE(content::PlatformNotificationData::Direction,
                           content::PlatformNotificationData::DIRECTION_LAST)
 
diff --git a/content/common/service_worker/controller_service_worker.mojom b/content/common/service_worker/controller_service_worker.mojom
index c8dcc1d..fc89294 100644
--- a/content/common/service_worker/controller_service_worker.mojom
+++ b/content/common/service_worker/controller_service_worker.mojom
@@ -23,16 +23,15 @@
 // service worker runs.
 //
 // The controllees use this interface to directly talk to the controller. This
-// implements a small subset of ServiceWorkerEventDispatcher, namely dispatch
+// implements a small subset of the ServiceWorker interface, namely dispatch
 // methods for Fetch and PostMessage, because ordering must be preserved
 // between them: controller.postMessage(...), controller.fetch(‘...’); from
 // the page must result in a message event then fetch event dispatched to the
 // service worker. They are believed to be the only events whose ordering
 // guarantee is observable from the page context.
-//
 interface ControllerServiceWorker {
   // Dispatches Fetch event for sub-resources. (Fetch for main resource is
-  // handled by ServiceWorkerEventDispatcher, as the fetch is initiated
+  // handled by the ServiceWorker interface, as the fetch is initiated
   // in the browser-process during the navigation)
   // The callback is called once the event finishes, which means the event
   // handler ran and all outstanding respondWith() and waitUntil() promises have
diff --git a/content/common/service_worker/embedded_worker.mojom b/content/common/service_worker/embedded_worker.mojom
index 04f9c97c..a7776766 100644
--- a/content/common/service_worker/embedded_worker.mojom
+++ b/content/common/service_worker/embedded_worker.mojom
@@ -51,8 +51,8 @@
   // Used to set up fetch requests.
   RendererPreferences renderer_preferences;
 
-  // Used to dispatch events from (via) the browser process.
-  ServiceWorkerEventDispatcher& dispatcher_request;
+  // Used to talk to the service worker from the browser process.
+  ServiceWorker& service_worker_request;
   // S13nServiceWorker: cloned and passed to each controllee to directly
   // dispatch events from the controllees.
   ControllerServiceWorker& controller_request;
diff --git a/content/common/service_worker/service_worker.mojom b/content/common/service_worker/service_worker.mojom
deleted file mode 100644
index 154f2af..0000000
--- a/content/common/service_worker/service_worker.mojom
+++ /dev/null
@@ -1,19 +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.
-
-module content.mojom;
-
-import "content/common/service_worker/service_worker_provider.mojom";
-
-// Per-process browser-side interface.
-// The renderer uses this interface to tell the browser when potential service
-// worker clients are created and when service workers are starting up.
-interface ServiceWorkerDispatcherHost {
-  // Creates a content::ServiceWorkerProviderHost on the browser
-  // process. |provider_info| has Mojo endpoints to connect the container host
-  // and the container on the renderer together. The lifetime of
-  // ServiceWorkerProviderHost will be tied to the
-  // mojom::ServiceWorkerContainerHost interface.
-  OnProviderCreated(ServiceWorkerProviderHostInfo provider_info);
-};
diff --git a/content/common/service_worker/service_worker_event_dispatcher.mojom b/content/common/service_worker/service_worker_event_dispatcher.mojom
index e67e43b..7fad040c 100644
--- a/content/common/service_worker/service_worker_event_dispatcher.mojom
+++ b/content/common/service_worker/service_worker_event_dispatcher.mojom
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(falken): Merge this file to service_worker.mojom.
+
 module content.mojom;
 
 import "content/common/service_worker/service_worker_fetch_response_callback.mojom";
@@ -52,23 +54,38 @@
 };
 
 // The number of seconds for which a 'push' event should be allowed to run.
-// This is not in the spec but for Chromium specific internal timeouts. Each
-// event dispatched to service workers has 5 minutes timeout in the Chrome
+// This is not in the spec but for a Chrome-specific timeout. Each
+// event dispatched to service workers has a 5 minute timeout in the Chrome
 // implementation, but this makes the timeout for push events shorter.
 const int32 kPushEventTimeoutSeconds = 90;
 
-// An interface for dispatching events to a ServiceWorker. This interface is
-// implemented by ServiceWorkerContextClient that lives in the renderer-side
-// to dispatch events from the browser-side.
+// An interface for talking to a running service worker thread. The browser
+// process uses this interface to request the renderer to do things like
+// dispatch events to the service worker. This interface is bound on the
+// service worker thread and is implemented by ServiceWorkerContextClient.
 //
-// Those events expecting such response
-// (blink.mojom.ServiceWorkerEventStatus, mojo_base.mojom.Time) are considered
-// 'simple events'. ServiceWorkerVersion::CreateSimpleEventCallback can be used
-// to create the callback for these.
-interface ServiceWorkerEventDispatcher {
+// This is the master interface for the Mojo message pipe between the browser
+// process and the service worker thread in the renderer process. Other service
+// worker-related interfaces bound on the service worker thread are associated
+// with this interface. These include:
+// - ServiceWorkerHost for this service worker.
+// - ServiceWorkerRegistrationObject(Host) for this service worker's
+//   self.registration property.
+// - ServiceWorkerObjects(Host) for that registration's properties.
+//
+// A similar (but non-associated) interface is ControllerServiceWorker. That
+// interface is used by service worker clients (inside renderer processes) to
+// talk directly to their controller service worker, without going through the
+// browser.
+//
+// USAGE TIP: Those DispatchEvent* messages expecting a
+// (blink.mojom.ServiceWorkerEventStatus, mojo_base.mojom.Time) callback are
+// considered 'simple events'. ServiceWorkerVersion::CreateSimpleEventCallback
+// can be used to create the callback for these.
+interface ServiceWorker {
   // The first message sent on this interface. It is used to associate service
   // worker-related interfaces together on the service worker thread, as
-  // ServiceWorkerEventDispatcher is the first interface available on the
+  // ServiceWorker is the first interface available on the
   // service worker thread. It establishes the |service_worker_host| connection
   // and passes information used to populate
   // ServiceWorkerGlobalScope#registration object. JavaScript execution of the
@@ -173,8 +190,7 @@
 
   // Pings the service worker to check if it is responsive. If the callback is
   // not called within a certain period of time, the browser will terminate the
-  // worker. Unlike the other functions in this interface, Ping() does not
-  // dispatch an event.
+  // worker.
   Ping() => ();
 
   // S13nServiceWorker:
diff --git a/content/common/service_worker/service_worker_fetch_response_callback.mojom b/content/common/service_worker/service_worker_fetch_response_callback.mojom
index 776c435..43f64fba1 100644
--- a/content/common/service_worker/service_worker_fetch_response_callback.mojom
+++ b/content/common/service_worker/service_worker_fetch_response_callback.mojom
@@ -12,8 +12,8 @@
 struct ServiceWorkerResponse;
 
 // Callback interface which is passed to a controller service worker through
-// DispatchFetchEvent (either via ServiceWorkerEventDispatcher or via
-// ControllerServiceWorker interface).
+// DispatchFetchEvent (either via ServiceWorker or via ControllerServiceWorker
+// interface).
 // The receiver service worker uses this interface to respond to a fetch event.
 interface ServiceWorkerFetchResponseCallback {
   // Responds to the request with |response|. The body is empty.
diff --git a/content/common/service_worker/service_worker_provider.mojom b/content/common/service_worker/service_worker_provider.mojom
index 3befe08..1ac547c5 100644
--- a/content/common/service_worker/service_worker_provider.mojom
+++ b/content/common/service_worker/service_worker_provider.mojom
@@ -123,3 +123,15 @@
   // Clones this host.
   CloneWorkerClientRegistry(ServiceWorkerWorkerClientRegistry& host);
 };
+
+// Per-process browser-side interface.
+// The renderer uses this interface to tell the browser when potential service
+// worker clients are created and when service workers are starting up.
+interface ServiceWorkerDispatcherHost {
+  // Creates a content::ServiceWorkerProviderHost on the browser
+  // process. |provider_info| has Mojo endpoints to connect the container host
+  // and the container on the renderer together. The lifetime of
+  // ServiceWorkerProviderHost will be tied to the
+  // mojom::ServiceWorkerContainerHost interface.
+  OnProviderCreated(ServiceWorkerProviderHostInfo provider_info);
+};
diff --git a/content/common/shared_worker/shared_worker_factory.mojom b/content/common/shared_worker/shared_worker_factory.mojom
index c993136..50332f4 100644
--- a/content/common/shared_worker/shared_worker_factory.mojom
+++ b/content/common/shared_worker/shared_worker_factory.mojom
@@ -4,6 +4,7 @@
 
 module content.mojom;
 
+import "content/common/native_types.mojom";
 import "content/common/service_worker/service_worker_provider.mojom";
 import "content/common/shared_worker/shared_worker.mojom";
 import "content/common/shared_worker/shared_worker_host.mojom";
@@ -31,6 +32,7 @@
       SharedWorkerInfo info,
       bool pause_on_start,
       mojo_base.mojom.UnguessableToken devtools_worker_token,
+      RendererPreferences renderer_preferences,
       blink.mojom.WorkerContentSettingsProxy content_settings,
 
       // S13nServiceWorker:
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h
index 20774ac..64f01043 100644
--- a/content/public/browser/picture_in_picture_window_controller.h
+++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_BROWSER_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_H_
 #define CONTENT_PUBLIC_BROWSER_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_H_
 
+#include <string>
 #include "content/common/content_export.h"
 
 namespace gfx {
@@ -38,7 +39,7 @@
   virtual gfx::Size Show() = 0;
 
   virtual void Close(bool should_pause_video) = 0;
-  virtual void ClickCustomControl() = 0;
+  virtual void ClickCustomControl(const std::string& control_id) = 0;
   virtual void EmbedSurface(const viz::SurfaceId& surface_id,
                             const gfx::Size& natural_size) = 0;
   virtual OverlayWindow* GetWindowForTesting() = 0;
diff --git a/content/public/test/DEPS b/content/public/test/DEPS
index 2d9bcea03..8acc5a4 100644
--- a/content/public/test/DEPS
+++ b/content/public/test/DEPS
@@ -10,6 +10,7 @@
   "+services/network",
   "+services/resource_coordinator",
   "+services/service_manager",
+  "+ui/ozone/public",
   "+v8/include/v8.h",
 ]
 
diff --git a/content/public/test/unittest_test_suite.cc b/content/public/test/unittest_test_suite.cc
index 805c77e..656a011d 100644
--- a/content/public/test/unittest_test_suite.cc
+++ b/content/public/test/unittest_test_suite.cc
@@ -21,18 +21,28 @@
 #include "ui/gfx/x/x11.h"
 #endif
 
+#if defined(OS_FUCHSIA)
+#include "ui/ozone/public/ozone_switches.h"
+#endif
+
 namespace content {
 
 UnitTestTestSuite::UnitTestTestSuite(base::TestSuite* test_suite)
     : test_suite_(test_suite) {
-  const base::CommandLine* command_line =
-      base::CommandLine::ForCurrentProcess();
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   std::string enabled =
       command_line->GetSwitchValueASCII(switches::kEnableFeatures);
   std::string disabled =
       command_line->GetSwitchValueASCII(switches::kDisableFeatures);
   feature_list_.InitFromCommandLine(enabled, disabled);
 
+#if defined(OS_FUCHSIA)
+  // Use headless ozone platform on Fuchsia by default.
+  // TODO(crbug.com/865172): Remove this flag.
+  if (!command_line->HasSwitch(switches::kOzonePlatform))
+    command_line->AppendSwitchASCII(switches::kOzonePlatform, "headless");
+#endif
+
 #if defined(USE_X11)
   XInitThreads();
 #endif
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 84076f7..f644a25 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -397,10 +397,11 @@
 }
 
 void RendererWebMediaPlayerDelegate::OnPictureInPictureControlClicked(
-    int player_id) {
+    int player_id,
+    const std::string& control_id) {
   Observer* observer = id_map_.Lookup(player_id);
   if (observer)
-    observer->OnPictureInPictureControlClicked();
+    observer->OnPictureInPictureControlClicked(control_id);
 }
 
 void RendererWebMediaPlayerDelegate::OnPictureInPictureModeEndedAck(
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h
index 9658b95..5897004 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.h
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -107,7 +107,8 @@
   void OnMediaDelegateVolumeMultiplierUpdate(int player_id, double multiplier);
   void OnMediaDelegateBecamePersistentVideo(int player_id, bool value);
   void OnPictureInPictureModeEnded(int player_id);
-  void OnPictureInPictureControlClicked(int player_id);
+  void OnPictureInPictureControlClicked(int player_id,
+                                        const std::string& control_id);
   void OnPictureInPictureModeEndedAck(int player_id, int request_id);
   void OnPictureInPictureModeStartedAck(int player_id,
                                         int request_id,
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
index ca704d7..8c2cf76 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -49,7 +49,7 @@
   MOCK_METHOD1(OnVolumeMultiplierUpdate, void(double));
   MOCK_METHOD1(OnBecamePersistentVideo, void(bool));
   MOCK_METHOD0(OnPictureInPictureModeEnded, void());
-  MOCK_METHOD0(OnPictureInPictureControlClicked, void());
+  MOCK_METHOD1(OnPictureInPictureControlClicked, void(const std::string&));
 };
 
 class RendererWebMediaPlayerDelegateTest : public content::RenderViewTest {
diff --git a/content/renderer/media/stream/webmediaplayer_ms.cc b/content/renderer/media/stream/webmediaplayer_ms.cc
index a6afa20..2d13eb7 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms.cc
@@ -922,7 +922,8 @@
   NOTIMPLEMENTED();
 }
 
-void WebMediaPlayerMS::OnPictureInPictureControlClicked() {
+void WebMediaPlayerMS::OnPictureInPictureControlClicked(
+    const std::string& control_id) {
   NOTIMPLEMENTED();
 }
 
diff --git a/content/renderer/media/stream/webmediaplayer_ms.h b/content/renderer/media/stream/webmediaplayer_ms.h
index c4a1e00e..4af7956 100644
--- a/content/renderer/media/stream/webmediaplayer_ms.h
+++ b/content/renderer/media/stream/webmediaplayer_ms.h
@@ -166,7 +166,7 @@
   void OnVolumeMultiplierUpdate(double multiplier) override;
   void OnBecamePersistentVideo(bool value) override;
   void OnPictureInPictureModeEnded() override;
-  void OnPictureInPictureControlClicked() override;
+  void OnPictureInPictureControlClicked(const std::string& control_id) override;
 
   bool CopyVideoTextureToPlatformTexture(
       gpu::gles2::GLES2Interface* gl,
diff --git a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
index 199529d4..a71ad9b6 100644
--- a/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/stream/webmediaplayer_ms_unittest.cc
@@ -561,7 +561,8 @@
   void MediaRemotingStopped(
       blink::WebLocalizedString::Name error_msg) override {}
   void PictureInPictureStopped() override {}
-  void PictureInPictureControlClicked() override {}
+  void PictureInPictureControlClicked(
+      const blink::WebString& control_id) override {}
   void RequestPlay() override {}
   void RequestPause() override {}
 
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 4030cd3b..b77c77c 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -41,7 +41,6 @@
 #include "content/public/common/webplugininfo.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/media_stream_utils.h"
-#include "content/public/renderer/platform_event_observer.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/renderer/blob_storage/webblobregistry_impl.h"
 #include "content/renderer/dom_storage/local_storage_cached_areas.h"
@@ -1051,14 +1050,6 @@
   GetContentClient()->renderer()->RecordRapporURL(metric, url);
 }
 
-void RendererBlinkPlatformImpl::SetPlatformEventObserverForTesting(
-    blink::WebPlatformEventType type,
-    std::unique_ptr<PlatformEventObserverBase> observer) {
-  if (platform_event_observers_.Lookup(type))
-    platform_event_observers_.Remove(type);
-  platform_event_observers_.AddWithID(std::move(observer), type);
-}
-
 service_manager::Connector* RendererBlinkPlatformImpl::GetConnector() {
   return connector_.get();
 }
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 4c09b20..e3626b2 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -59,7 +59,6 @@
 class BlinkInterfaceProviderImpl;
 class ChildURLLoaderFactoryBundle;
 class LocalStorageCachedAreas;
-class PlatformEventObserverBase;
 class ThreadSafeSender;
 class WebDatabaseObserverImpl;
 
@@ -199,14 +198,6 @@
   void WillStopWorkerThread() override;
   void WorkerContextCreated(const v8::Local<v8::Context>& worker) override;
 
-  // Set the PlatformEventObserverBase in |platform_event_observers_| associated
-  // with |type| to |observer|. If there was already an observer associated to
-  // the given |type|, it will be replaced.
-  // Note that |observer| will be owned by this object after the call.
-  void SetPlatformEventObserverForTesting(
-      blink::WebPlatformEventType type,
-      std::unique_ptr<PlatformEventObserverBase> observer);
-
   // Disables the WebSandboxSupport implementation for testing.
   // Tests that do not set up a full sandbox environment should call
   // SetSandboxEnabledForTesting(false) _before_ creating any instances
@@ -257,11 +248,6 @@
 
   // TODO(crbug.com/850997): Remove when Device*EventPump classes are
   // moved to blink
-  void InitDeviceSensorEventPump(blink::WebPlatformEventType type,
-                                 blink::WebPlatformEventListener* listener);
-
-  // TODO(crbug.com/850997): Remove when Device*EventPump classes are
-  // moved to blink
   void StopDeviceSensorEventPump(blink::WebPlatformEventType type);
 
   // Ensure that the WebDatabaseHost has been initialized.
@@ -299,9 +285,6 @@
 
   std::unique_ptr<WebDatabaseObserverImpl> web_database_observer_impl_;
 
-  base::IDMap<std::unique_ptr<PlatformEventObserverBase>>
-      platform_event_observers_;
-
   // NOT OWNED
   blink::scheduler::WebThreadScheduler* main_thread_scheduler_;
 
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 7bcd23f4..335e606 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -69,7 +69,7 @@
       params->scope, params->script_url,
       !params->installed_scripts_info.is_null(),
       std::move(params->renderer_preferences),
-      std::move(params->dispatcher_request),
+      std::move(params->service_worker_request),
       std::move(params->controller_request), std::move(params->instance_host),
       std::move(params->provider_info), std::move(temporal_self_),
       std::move(start_timing),
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index cc85122a..3cb6d31 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -462,7 +462,7 @@
 // worker thread.
 struct ServiceWorkerContextClient::WorkerContextData {
   explicit WorkerContextData(ServiceWorkerContextClient* owner)
-      : event_dispatcher_binding(owner),
+      : service_worker_binding(owner),
         weak_factory(owner),
         proxy_weak_factory(owner->proxy_) {}
 
@@ -473,10 +473,10 @@
   // Map from version id to JavaScript ServiceWorker object.
   std::map<int64_t, WebServiceWorkerImpl*> workers_;
 
-  mojo::Binding<mojom::ServiceWorkerEventDispatcher> event_dispatcher_binding;
+  mojo::Binding<mojom::ServiceWorker> service_worker_binding;
 
   // Bound by the first Mojo call received on the service worker thread
-  // ServiceWorkerEventDispatcher::InitializeGlobalScope().
+  // ServiceWorker::InitializeGlobalScope().
   blink::mojom::ServiceWorkerHostAssociatedPtr service_worker_host;
 
   // Maps for inflight event callbacks.
@@ -698,7 +698,7 @@
     const GURL& script_url,
     bool is_starting_installed_worker,
     RendererPreferences renderer_preferences,
-    mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+    mojom::ServiceWorkerRequest service_worker_request,
     mojom::ControllerServiceWorkerRequest controller_request,
     mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
     mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -713,7 +713,7 @@
       renderer_preferences_(std::move(renderer_preferences)),
       main_thread_task_runner_(std::move(main_thread_task_runner)),
       proxy_(nullptr),
-      pending_dispatcher_request_(std::move(dispatcher_request)),
+      pending_service_worker_request_(std::move(service_worker_request)),
       pending_controller_request_(std::move(controller_request)),
       embedded_worker_client_(std::move(embedded_worker_client)),
       start_timing_(std::move(start_timing)) {
@@ -841,12 +841,12 @@
   // willDestroyWorkerContext.
   context_.reset(new WorkerContextData(this));
 
-  DCHECK(pending_dispatcher_request_.is_pending());
+  DCHECK(pending_service_worker_request_.is_pending());
   DCHECK(pending_controller_request_.is_pending());
-  DCHECK(!context_->event_dispatcher_binding.is_bound());
+  DCHECK(!context_->service_worker_binding.is_bound());
   DCHECK(!context_->controller_impl);
-  context_->event_dispatcher_binding.Bind(
-      std::move(pending_dispatcher_request_));
+  context_->service_worker_binding.Bind(
+      std::move(pending_service_worker_request_));
 
   if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
     context_->controller_impl = std::make_unique<ControllerServiceWorkerImpl>(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 4cf7dd0..924cddd 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -73,7 +73,7 @@
 // called on the worker thread.
 class CONTENT_EXPORT ServiceWorkerContextClient
     : public blink::WebServiceWorkerContextClient,
-      public mojom::ServiceWorkerEventDispatcher {
+      public mojom::ServiceWorker {
  public:
   // Returns a thread-specific client instance.  This does NOT create a
   // new instance.
@@ -93,7 +93,7 @@
       const GURL& script_url,
       bool is_starting_installed_worker,
       RendererPreferences renderer_preferences,
-      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ServiceWorkerRequest service_worker_request,
       mojom::ControllerServiceWorkerRequest controller_request,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
@@ -274,7 +274,7 @@
 
   void SendWorkerStarted(blink::mojom::ServiceWorkerStartStatus status);
 
-  // Implements mojom::ServiceWorkerEventDispatcher.
+  // Implements mojom::ServiceWorker.
   void InitializeGlobalScope(
       blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
       blink::mojom::ServiceWorkerRegistrationObjectInfoPtr registration_info)
@@ -422,7 +422,7 @@
   blink::WebServiceWorkerContextProxy* proxy_;
 
   // These Mojo objects are bound on the worker thread.
-  mojom::ServiceWorkerEventDispatcherRequest pending_dispatcher_request_;
+  mojom::ServiceWorkerRequest pending_service_worker_request_;
   mojom::ControllerServiceWorkerRequest pending_controller_request_;
 
   // This is bound on the main thread.
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index 19f9049..fbd3fce 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -45,7 +45,7 @@
 // Pipes connected to the context client.
 struct ContextClientPipes {
   // From the browser to ServiceWorkerContextClient.
-  mojom::ServiceWorkerEventDispatcherPtr event_dispatcher;
+  mojom::ServiceWorkerPtr service_worker;
   mojom::ControllerServiceWorkerPtr controller;
   blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr registration;
 
@@ -265,8 +265,7 @@
   std::unique_ptr<ServiceWorkerContextClient> CreateContextClient(
       ContextClientPipes* out_pipes,
       blink::WebServiceWorkerContextProxy* proxy) {
-    auto event_dispatcher_request =
-        mojo::MakeRequest(&out_pipes->event_dispatcher);
+    auto service_worker_request = mojo::MakeRequest(&out_pipes->service_worker);
     auto controller_request = mojo::MakeRequest(&out_pipes->controller);
     mojom::EmbeddedWorkerInstanceHostAssociatedPtr embedded_worker_host_ptr;
     out_pipes->embedded_worker_host_request =
@@ -277,7 +276,7 @@
         std::make_unique<ServiceWorkerContextClient>(
             1 /* embedded_worker_id */, 1 /* service_worker_version_id */,
             kScope, kScript, false /* is_script_streaming */,
-            RendererPreferences(), std::move(event_dispatcher_request),
+            RendererPreferences(), std::move(service_worker_request),
             std::move(controller_request),
             embedded_worker_host_ptr.PassInterface(), CreateProviderInfo(),
             nullptr /* embedded_worker_client */,
@@ -298,7 +297,7 @@
     out_pipes->registration_host_request =
         mojo::MakeRequest(&registration_info->host_ptr_info);
     registration_info->request = mojo::MakeRequest(&out_pipes->registration);
-    out_pipes->event_dispatcher->InitializeGlobalScope(
+    out_pipes->service_worker->InitializeGlobalScope(
         std::move(service_worker_host), std::move(registration_info));
     task_runner()->RunUntilIdle();
     return context_client;
@@ -326,7 +325,7 @@
       CreateContextClient(&pipes, &mock_proxy);
 
   bool is_called = false;
-  pipes.event_dispatcher->Ping(CreateCallbackWithCalledFlag(&is_called));
+  pipes.service_worker->Ping(CreateCallbackWithCalledFlag(&is_called));
   task_runner()->RunUntilIdle();
   EXPECT_TRUE(is_called);
 }
@@ -348,7 +347,7 @@
   fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr);
   auto params = blink::mojom::DispatchFetchEventParams::New();
   params->request = *request;
-  pipes.event_dispatcher->DispatchFetchEvent(
+  pipes.service_worker->DispatchFetchEvent(
       std::move(params), std::move(fetch_callback_ptr),
       base::BindOnce(
           [](blink::mojom::ServiceWorkerEventStatus, base::Time) {}));
@@ -490,7 +489,7 @@
   }
   EXPECT_TRUE(mock_proxy.fetch_events().empty());
 
-  // Another event dispatched to mojom::ServiceWorkerEventDispatcher wakes up
+  // Another event dispatched to mojom::ServiceWorker wakes up
   // the context client.
   {
     mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr;
@@ -499,7 +498,7 @@
     request->url = expected_url_2;
     auto params = blink::mojom::DispatchFetchEventParams::New();
     params->request = *request;
-    pipes.event_dispatcher->DispatchFetchEvent(
+    pipes.service_worker->DispatchFetchEvent(
         std::move(params), std::move(fetch_callback_ptr),
         base::BindOnce(
             [](blink::mojom::ServiceWorkerEventStatus, base::Time) {}));
diff --git a/content/renderer/service_worker/service_worker_network_provider.h b/content/renderer/service_worker/service_worker_network_provider.h
index 9130a3c..bafbff83 100644
--- a/content/renderer/service_worker/service_worker_network_provider.h
+++ b/content/renderer/service_worker/service_worker_network_provider.h
@@ -16,7 +16,6 @@
 #include "base/supports_user_data.h"
 #include "content/common/content_export.h"
 #include "content/common/service_worker/controller_service_worker.mojom.h"
-#include "content/common/service_worker/service_worker.mojom.h"
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom.h"
diff --git a/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc b/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
index 76263bd..27396c1 100644
--- a/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
+++ b/content/renderer/service_worker/service_worker_timeout_timer_unittest.cc
@@ -273,7 +273,8 @@
 }
 
 TEST_F(ServiceWorkerTimeoutTimerTest, NonS13nServiceWorker) {
-  ASSERT_FALSE(blink::ServiceWorkerUtils::IsServicificationEnabled());
+  if (blink::ServiceWorkerUtils::IsServicificationEnabled())
+    return;
 
   MockEvent event;
   {
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 908d6a8..06a99673 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -194,6 +194,7 @@
     mojom::SharedWorkerInfoPtr info,
     bool pause_on_start,
     const base::UnguessableToken& devtools_worker_token,
+    const RendererPreferences& renderer_preferences,
     blink::mojom::WorkerContentSettingsProxyPtr content_settings,
     mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
         service_worker_provider_info,
@@ -206,7 +207,8 @@
     : binding_(this, std::move(request)),
       host_(std::move(host)),
       name_(info->name),
-      url_(info->url) {
+      url_(info->url),
+      renderer_preferences_(renderer_preferences) {
   impl_ = blink::WebSharedWorker::Create(this);
   if (pause_on_start) {
     // Pause worker context when it starts and wait until either DevTools client
@@ -375,11 +377,8 @@
   std::unique_ptr<network::SharedURLLoaderFactoryInfo> fallback_factory =
       loader_factories_->Clone();
 
-  // TODO(crbug.com/853085): Send the preference from the browser process.
-  RendererPreferences renderer_preferences;
-
   auto worker_fetch_context = std::make_unique<WebWorkerFetchContextImpl>(
-      std::move(renderer_preferences), std::move(worker_client_request),
+      std::move(renderer_preferences_), std::move(worker_client_request),
       std::move(worker_client_registry_ptr_info),
       std::move(container_host_ptr_info), loader_factories_->Clone(),
       std::move(fallback_factory),
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.h b/content/renderer/shared_worker/embedded_shared_worker_stub.h
index 115aea9..6014d199 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.h
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.h
@@ -15,6 +15,7 @@
 #include "content/common/shared_worker/shared_worker.mojom.h"
 #include "content/common/shared_worker/shared_worker_host.mojom.h"
 #include "content/common/shared_worker/shared_worker_info.mojom.h"
+#include "content/public/common/renderer_preferences.h"
 #include "ipc/ipc_listener.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -59,6 +60,7 @@
       mojom::SharedWorkerInfoPtr info,
       bool pause_on_start,
       const base::UnguessableToken& devtools_worker_token,
+      const RendererPreferences& renderer_preferences,
       blink::mojom::WorkerContentSettingsProxyPtr content_settings,
       mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
           service_worker_provider_info,
@@ -106,6 +108,7 @@
   const std::string name_;
   bool running_ = false;
   GURL url_;
+  RendererPreferences renderer_preferences_;
   std::unique_ptr<blink::WebSharedWorker> impl_;
 
   using PendingChannel =
diff --git a/content/renderer/shared_worker/shared_worker_factory_impl.cc b/content/renderer/shared_worker/shared_worker_factory_impl.cc
index f50730c..48a5091 100644
--- a/content/renderer/shared_worker/shared_worker_factory_impl.cc
+++ b/content/renderer/shared_worker/shared_worker_factory_impl.cc
@@ -24,6 +24,7 @@
     mojom::SharedWorkerInfoPtr info,
     bool pause_on_start,
     const base::UnguessableToken& devtools_worker_token,
+    const RendererPreferences& renderer_preferences,
     blink::mojom::WorkerContentSettingsProxyPtr content_settings,
     mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
         service_worker_provider_info,
@@ -36,7 +37,8 @@
   // Bound to the lifetime of the underlying blink::WebSharedWorker instance.
   new EmbeddedSharedWorkerStub(
       std::move(info), pause_on_start, devtools_worker_token,
-      std::move(content_settings), std::move(service_worker_provider_info),
+      renderer_preferences, std::move(content_settings),
+      std::move(service_worker_provider_info),
       std::move(script_loader_factory_ptr_info), std::move(subresource_loaders),
       std::move(host), std::move(request), std::move(interface_provider));
 }
diff --git a/content/renderer/shared_worker/shared_worker_factory_impl.h b/content/renderer/shared_worker/shared_worker_factory_impl.h
index 697eb45..78aef010 100644
--- a/content/renderer/shared_worker/shared_worker_factory_impl.h
+++ b/content/renderer/shared_worker/shared_worker_factory_impl.h
@@ -25,6 +25,7 @@
       mojom::SharedWorkerInfoPtr info,
       bool pause_on_start,
       const base::UnguessableToken& devtools_worker_token,
+      const RendererPreferences& renderer_preferences,
       blink::mojom::WorkerContentSettingsProxyPtr content_settings,
       mojom::ServiceWorkerProviderInfoForSharedWorkerPtr
           service_worker_provider_info,
diff --git a/content/test/data/accessibility/html/frame/box.html b/content/test/data/accessibility/html/frame/box.html
index df0441e..9fa83bf 100644
--- a/content/test/data/accessibility/html/frame/box.html
+++ b/content/test/data/accessibility/html/frame/box.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <html>
 <body style="margin: 10px; padding: 0px; border: 0px;">
-<div role="img" style="width: 200px; height: 200px; background-color: #fef;"></div>
+<div role="img" style="width: 100px; height: 50px; background-color: #fef;"></div>
 </body>
 </html>
diff --git a/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
index c1b1daea..0603c365 100644
--- a/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-cross-process-expected-blink.txt
@@ -1,7 +1,7 @@
 rootWebArea pageLocation=(0, 0)
 ++iframe pageLocation=(0, 0)
 ++++rootWebArea pageLocation=(0, 0)
-++++++image pageLocation=(10, 10) pageSize=(200, 200)
+++++++image pageLocation=(10, 10) pageSize=(100, 50)
 ++iframe pageLocation=(0, 250) transform
 ++++rootWebArea pageLocation=(0, 250)
-++++++image pageLocation=(15, 265) pageSize=(300, 300)
+++++++image pageLocation=(15, 265) pageSize=(150, 75)
diff --git a/content/test/data/accessibility/html/iframe-transform-cross-process.html b/content/test/data/accessibility/html/iframe-transform-cross-process.html
index 02d71ba..ea6bc26e 100644
--- a/content/test/data/accessibility/html/iframe-transform-cross-process.html
+++ b/content/test/data/accessibility/html/iframe-transform-cross-process.html
@@ -1,8 +1,16 @@
 <!--
 @BLINK-ALLOW:pageLocation*
-@BLINK-ALLOW:pageSize=(200, 200)
-@BLINK-ALLOW:pageSize=(300, 300)
+@BLINK-ALLOW:pageSize=(100, 50)
+@BLINK-ALLOW:pageSize=(150, 75)
 @BLINK-ALLOW:transform
+
+There are two iframes that each include box.html, one with no transform,
+and one with a transform of 1.5 applied. Both iframes are cross-process.
+
+The image in box.html is at (10, 10) size (100 x 50)
+Inside the first iframe it should be at (10, 10) size (100 x 50)
+Inside the second iframe it should be at (15, 265) size (150 x 75)
+
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
index c1b1daea..0603c365 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-blink.txt
@@ -1,7 +1,7 @@
 rootWebArea pageLocation=(0, 0)
 ++iframe pageLocation=(0, 0)
 ++++rootWebArea pageLocation=(0, 0)
-++++++image pageLocation=(10, 10) pageSize=(200, 200)
+++++++image pageLocation=(10, 10) pageSize=(100, 50)
 ++iframe pageLocation=(0, 250) transform
 ++++rootWebArea pageLocation=(0, 250)
-++++++image pageLocation=(15, 265) pageSize=(300, 300)
+++++++image pageLocation=(15, 265) pageSize=(150, 75)
diff --git a/content/test/data/accessibility/html/iframe-transform-expected-win.txt b/content/test/data/accessibility/html/iframe-transform-expected-win.txt
index 7d80ff56..db662996 100644
--- a/content/test/data/accessibility/html/iframe-transform-expected-win.txt
+++ b/content/test/data/accessibility/html/iframe-transform-expected-win.txt
@@ -1,7 +1,7 @@
-ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0) size=(800, 600)
-++IA2_ROLE_INTERNAL_FRAME READONLY location=(0, 0) size=(220, 220)
-++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0) size=(220, 220)
-++++++ROLE_SYSTEM_GRAPHIC READONLY location=(10, 10) size=(200, 200)
-++IA2_ROLE_INTERNAL_FRAME READONLY location=(0, 250) size=(330, 330)
-++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 250) size=(330, 330)
-++++++ROLE_SYSTEM_GRAPHIC READONLY location=(15, 265) size=(300, 300)
+ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
+++IA2_ROLE_INTERNAL_FRAME READONLY location=(0, 0)
+++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0)
+++++++ROLE_SYSTEM_GRAPHIC READONLY location=(10, 10) size=(100, 50)
+++IA2_ROLE_INTERNAL_FRAME READONLY location=(0, 250)
+++++ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 250)
+++++++ROLE_SYSTEM_GRAPHIC READONLY location=(15, 265) size=(150, 75)
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
index 820b014..8cb9c0b 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-nested-cross-process-expected-blink.txt
@@ -3,4 +3,4 @@
 ++++rootWebArea pageLocation=(0, 100)
 ++++++iframe pageLocation=(200, 100) transform
 ++++++++rootWebArea pageLocation=(200, 100)
-++++++++++image pageLocation=(240, 140) pageSize=(560, 460)
+++++++++++image pageLocation=(240, 140) pageSize=(400, 200)
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-cross-process.html b/content/test/data/accessibility/html/iframe-transform-nested-cross-process.html
index f70a5cf..3f2281c3 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-cross-process.html
+++ b/content/test/data/accessibility/html/iframe-transform-nested-cross-process.html
@@ -1,7 +1,20 @@
 <!--
 @BLINK-ALLOW:pageLocation*
-@BLINK-ALLOW:pageSize=(560, 460)
+@BLINK-ALLOW:pageSize=(400, 200)
 @BLINK-ALLOW:transform
+
+This is the same as iframe-transform-nested.html except that the
+iframes are cross-process rather than being from the same site.
+
+This page includes frame/nested-cross-process-frame.html in an iframe,
+and that page includes frame/box.html in an iframe.
+Both pages absolute-position the iframe and give it a scale
+factor of 2.0.
+
+The image in box.html is at (10, 10) size (100 x 50)
+Relative to nested-frame.html it's at (120, 20) size (200 x 100)
+Relative to this file it's at (240, 140) size (400 x 200)
+
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt b/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
index 820b014..8cb9c0b 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
+++ b/content/test/data/accessibility/html/iframe-transform-nested-expected-blink.txt
@@ -3,4 +3,4 @@
 ++++rootWebArea pageLocation=(0, 100)
 ++++++iframe pageLocation=(200, 100) transform
 ++++++++rootWebArea pageLocation=(200, 100)
-++++++++++image pageLocation=(240, 140) pageSize=(560, 460)
+++++++++++image pageLocation=(240, 140) pageSize=(400, 200)
diff --git a/content/test/data/accessibility/html/iframe-transform-nested.html b/content/test/data/accessibility/html/iframe-transform-nested.html
index bb88e2164..f8aabe4 100644
--- a/content/test/data/accessibility/html/iframe-transform-nested.html
+++ b/content/test/data/accessibility/html/iframe-transform-nested.html
@@ -1,11 +1,21 @@
 <!--
 @BLINK-ALLOW:pageLocation*
-@BLINK-ALLOW:pageSize=(560, 460)
+@BLINK-ALLOW:pageSize=(400, 200)
 @BLINK-ALLOW:transform
+
+This page includes frame/nested-frame.html in an iframe,
+and that page includes frame/box.html in an iframe.
+Both pages absolute-position the iframe and give it a scale
+factor of 2.0.
+
+The image in box.html is at (10, 10) size (100 x 50)
+Relative to nested-frame.html it's at (120, 20) size (200 x 100)
+Relative to this file it's at (240, 140) size (400 x 200)
+
 -->
 <!DOCTYPE html>
 <html>
 <body style="padding: 0; margin: 0;">
-  <iframe width=500 height=500 src="/cross-site/2.com/accessibility/html/frame/nested-frame.html" style="border: 0; position: absolute; top: 100px; left: 0px; transform: scale(2.0); transform-origin: left top;"></iframe>
+  <iframe width=500 height=500 src="frame/nested-frame.html" style="border: 0; position: absolute; top: 100px; left: 0px; transform: scale(2.0); transform-origin: left top;"></iframe>
 </body>
 </html>
diff --git a/content/test/data/accessibility/html/iframe-transform.html b/content/test/data/accessibility/html/iframe-transform.html
index 19783401..d29a9c59 100644
--- a/content/test/data/accessibility/html/iframe-transform.html
+++ b/content/test/data/accessibility/html/iframe-transform.html
@@ -1,16 +1,25 @@
 <!--
 @WIN-ALLOW:location*
-@WIN-ALLOW:size*
+@WIN-ALLOW:size=(100, 50)
+@WIN-ALLOW:size=(150, 75)
 
 @BLINK-ALLOW:pageLocation*
-@BLINK-ALLOW:pageSize=(200, 200)
-@BLINK-ALLOW:pageSize=(300, 300)
+@BLINK-ALLOW:pageSize=(100, 50)
+@BLINK-ALLOW:pageSize=(150, 75)
 @BLINK-ALLOW:transform
+
+There are two iframes that each include box.html, one with no transform,
+and one with a transform of 1.5 applied.
+
+The image in box.html is at (10, 10) size (100 x 50)
+Inside the first iframe it should be at (10, 10) size (100 x 50)
+Inside the second iframe it should be at (15, 265) size (150 x 75)
+
 -->
 <!DOCTYPE html>
 <html>
-<body style="padding: 0; margin: 0; width: 800px; height: 600px">
+<body style="padding: 0; margin: 0;">
   <iframe width=220 height=220 src="frame/box.html" style="border: 0; position: absolute; top: 0px; left: 0px;"></iframe>
   <iframe width=220 height=220 src="frame/box.html" style="border: 0; position: absolute; top: 250px; left: 0px; transform: scale(1.5); transform-origin: left top;"></iframe>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index ca79f8e..9c93ff9 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -139,6 +139,11 @@
     self.Skip('conformance/rendering/texture-switch-performance.html',
         bug=735483)
 
+    # Flaky on multiple platforms. Going to rewrite the test to make
+    # it more obviously correct.
+    self.Flaky('conformance/textures/misc/' +
+        'tex-video-using-tex-unit-non-zero.html', bug=830901)
+
     # Passthrough command decoder / OpenGL
     self.Fail('conformance/renderbuffers/framebuffer-test.html',
         ['passthrough', 'opengl'], bug=665521)
@@ -646,9 +651,6 @@
     self.Flaky('conformance/textures/image_bitmap_from_video/' +
         'tex-2d-rgb-rgb-unsigned_byte.html',
         ['android', ('qualcomm', 'Adreno (TM) 418')], bug=716496)
-    self.Flaky('conformance/textures/misc/' +
-        'tex-video-using-tex-unit-non-zero.html',
-        ['android', ('qualcomm', 'Adreno (TM) 418')], bug=793050)
     self.Fail('conformance/uniforms/uniform-samplers-test.html',
         ['android', ('qualcomm', 'Adreno (TM) 418'), 'no_passthrough'],
         bug=610951)
@@ -697,12 +699,12 @@
         'copy-tex-image-and-sub-image-2d.html',
         ['android', ('qualcomm', 'Adreno (TM) 420'), 'no_passthrough'],
         bug=499555)
-    self.Flaky('conformance/textures/misc/' +
-        'tex-video-using-tex-unit-non-zero.html',
-        ['android', ('qualcomm', 'Adreno (TM) 420')], bug=830901)
-    self.Flaky('conformance/textures/misc/' +
-        'tex-video-using-tex-unit-non-zero.html',
-        ['android', ('qualcomm', 'Adreno (TM) 430')], bug=830901)
+    # self.Flaky('conformance/textures/misc/' +
+    #     'tex-video-using-tex-unit-non-zero.html',
+    #     ['android', ('qualcomm', 'Adreno (TM) 420')], bug=830901)
+    # self.Flaky('conformance/textures/misc/' +
+    #     'tex-video-using-tex-unit-non-zero.html',
+    #     ['android', ('qualcomm', 'Adreno (TM) 430')], bug=830901)
     self.Fail('conformance/uniforms/uniform-samplers-test.html',
         ['android', ('qualcomm', 'Adreno (TM) 430'), 'no_passthrough'],
         bug=663071)
@@ -721,9 +723,9 @@
         ['android', 'nvidia'], bug=478572)
     self.Fail('conformance/glsl/bugs/multiplication-assignment.html',
         ['android', 'nvidia'], bug=606096)
-    self.Flaky('conformance/textures/misc/' +
-        'tex-video-using-tex-unit-non-zero.html',
-        ['android', 'nvidia'], bug=830901)
+    # self.Flaky('conformance/textures/misc/' +
+    #     'tex-video-using-tex-unit-non-zero.html',
+    #     ['android', 'nvidia'], bug=830901)
 
     # Nexus 9 and Shield TV (NVIDIA GPUs currently on the waterfall)
     self.Fail('conformance/ogles/GL/array/array_001_to_006.html',
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 2cd179cd..26a29869 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1323,6 +1323,7 @@
   SYSTEM_POWER_SOURCE_REQUESTSTATUSUPDATE = 1260,
   INPUTMETHODPRIVATE_GETSURROUNDINGTEXT = 1261,
   USERSPRIVATE_GETLOGINSTATUS = 1262,
+  FILEMANAGERPRIVATEINTERNAL_INSTALLLINUXPACKAGE = 1263,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
index 83c60652..dd75f02 100644
--- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
+++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc
@@ -92,6 +92,12 @@
   return nullptr;
 }
 
+DocumentSuggestionsService*
+AutocompleteProviderClientImpl::GetDocumentSuggestionsService(
+    bool create_if_necessary) const {
+  return nullptr;
+}
+
 const SearchTermsData& AutocompleteProviderClientImpl::GetSearchTermsData()
     const {
   return search_terms_data_;
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
index 41c837c..c518468c 100644
--- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
+++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.h
@@ -36,6 +36,8 @@
   const TemplateURLService* GetTemplateURLService() const override;
   ContextualSuggestionsService* GetContextualSuggestionsService(
       bool create_if_necessary) const override;
+  DocumentSuggestionsService* GetDocumentSuggestionsService(
+      bool create_if_necessary) const override;
   const SearchTermsData& GetSearchTermsData() const override;
   scoped_refptr<ShortcutsBackend> GetShortcutsBackend() override;
   scoped_refptr<ShortcutsBackend> GetShortcutsBackendIfExists() override;
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 f0e83f76..9642b370a 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -30,8 +30,10 @@
 #import "ios/chrome/browser/ui/image_util/image_util.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
+#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
 #include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -71,7 +73,11 @@
   ItemTypeName = kItemTypeEnumZero,
   ItemTypeFolder,
   ItemTypeURL,
+  ItemTypeInvalidURLFooter,
 };
+
+// The text color for the invalid URL label.
+const CGFloat kInvalidURLTextColor = 0xEA4335;
 }  // namespace
 
 @interface BookmarkEditViewController ()<BookmarkFolderViewControllerDelegate,
@@ -114,6 +120,9 @@
 @property(nonatomic, strong) BookmarkParentFolderItem* folderItem;
 @property(nonatomic, strong) BookmarkTextFieldItem* URLItem;
 
+// YES if the URL item is displaying a valid URL.
+@property(nonatomic, assign) BOOL displayingValidURL;
+
 // Reports the changes to the delegate, that has the responsibility to save the
 // bookmark.
 - (void)commitBookmarkChanges;
@@ -153,6 +162,7 @@
 @synthesize bookmark = _bookmark;
 @synthesize bookmarkModel = _bookmarkModel;
 @synthesize delegate = _delegate;
+@synthesize displayingValidURL = _displayingValidURL;
 @synthesize folder = _folder;
 @synthesize folderViewController = _folderViewController;
 @synthesize browserState = _browserState;
@@ -207,7 +217,6 @@
   self.tableView.estimatedRowHeight = 88.0;
   self.tableView.rowHeight = UITableViewAutomaticDimension;
   self.tableView.sectionHeaderHeight = 0;
-  self.tableView.sectionFooterHeight = 0;
   self.view.accessibilityIdentifier = kBookmarkEditViewContainerIdentifier;
 
   if (experimental_flags::IsBookmarksUIRebootEnabled()) {
@@ -406,6 +415,11 @@
   self.URLItem.delegate = self;
   [model addItem:self.URLItem toSectionWithIdentifier:SectionIdentifierInfo];
 
+  TableViewHeaderFooterItem* errorFooter =
+      [[TableViewHeaderFooterItem alloc] initWithType:ItemTypeInvalidURLFooter];
+  [model setFooter:errorFooter forSectionWithIdentifier:SectionIdentifierInfo];
+  self.displayingValidURL = YES;
+
   // Save button state.
   [self updateSaveButtonState];
 }
@@ -472,21 +486,20 @@
 
 - (void)textDidChangeForItem:(BookmarkTextFieldItem*)item {
   [self updateSaveButtonState];
-
-  if (experimental_flags::IsBookmarksUIRebootEnabled()) {
-    NSIndexPath* textFieldIndexPath =
-        [self.tableViewModel indexPathForItemType:item.type
-                                sectionIdentifier:SectionIdentifierInfo];
-    UITableViewCell* cell =
-        [self.tableView cellForRowAtIndexPath:textFieldIndexPath];
-    BookmarkTextFieldCell* URLCell =
-        base::mac::ObjCCastStrict<BookmarkTextFieldCell>(cell);
-    // Update the URLCell valid state if it has changed.
-    if ([self inputURLIsValid] != URLCell.validState) {
-      [self.tableView beginUpdates];
-      URLCell.validState = [self inputURLIsValid];
-      [self.tableView endUpdates];
-    }
+  if (experimental_flags::IsBookmarksUIRebootEnabled() &&
+      (self.displayingValidURL != [self inputURLIsValid])) {
+    self.displayingValidURL = [self inputURLIsValid];
+    UITableViewHeaderFooterView* footer = [self.tableView
+        footerViewForSection:[self.tableViewModel sectionForSectionIdentifier:
+                                                      SectionIdentifierInfo]];
+    NSString* footerText =
+        [self inputURLIsValid]
+            ? @""
+            : l10n_util::GetNSString(
+                  IDS_IOS_BOOKMARK_URL_FIELD_VALIDATION_FAILED);
+    [self.tableView beginUpdates];
+    footer.textLabel.text = footerText;
+    [self.tableView endUpdates];
   }
 }
 
@@ -542,6 +555,21 @@
     [self moveBookmark];
 }
 
+- (UIView*)tableView:(UITableView*)tableView
+    viewForFooterInSection:(NSInteger)section {
+  UIView* footerView =
+      [super tableView:tableView viewForFooterInSection:section];
+  if (section ==
+      [self.tableViewModel sectionForSectionIdentifier:SectionIdentifierInfo]) {
+    UITableViewHeaderFooterView* headerFooterView =
+        base::mac::ObjCCastStrict<UITableViewHeaderFooterView>(footerView);
+    headerFooterView.textLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
+    headerFooterView.textLabel.textColor = UIColorFromRGB(kInvalidURLTextColor);
+  }
+  return footerView;
+}
+
 #pragma mark - BookmarkFolderViewControllerDelegate
 
 - (void)folderPicker:(BookmarkFolderViewController*)folderPicker
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 6c9d8dce..20eb2a3 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
@@ -42,10 +42,6 @@
 // Text field to display the title or the URL of the bookmark node.
 @property(nonatomic, strong) UITextField* textField;
 
-// If |NO| changes the cell appearance to reflect that |self.textfield| is on an
-// invalid state.
-@property(nonatomic, assign) BOOL validState;
-
 @end
 
 @interface LegacyBookmarkTextFieldCell : UITableViewCell
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 811372fd..0e58c07 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
@@ -56,7 +56,6 @@
     cell.textField.accessibilityLabel = self.text;
     cell.textField.accessibilityIdentifier = [NSString
         stringWithFormat:@"%@_textField", self.accessibilityIdentifier];
-    cell.validState = YES;
     cell.selectionStyle = UITableViewCellSelectionStyleNone;
   } else {
     LegacyBookmarkTextFieldCell* cell =
@@ -86,15 +85,9 @@
 
 #pragma mark - BookmarkTextFieldCell
 
-@interface BookmarkTextFieldCell ()
-@property(nonatomic, strong) UILabel* invalidURLLabel;
-@end
-
 @implementation BookmarkTextFieldCell
 @synthesize textField = _textField;
 @synthesize titleLabel = _titleLabel;
-@synthesize invalidURLLabel = _invalidURLLabel;
-@synthesize validState = _validState;
 
 - (instancetype)initWithStyle:(UITableViewCellStyle)style
               reuseIdentifier:(NSString*)reuseIdentifier {
@@ -138,44 +131,21 @@
   [horizontalStack
       setContentCompressionResistancePriority:UILayoutPriorityRequired
                                       forAxis:UILayoutConstraintAxisVertical];
-
-  // Invalid URL label
-  self.invalidURLLabel = [[UILabel alloc] init];
-  self.invalidURLLabel.text =
-      l10n_util::GetNSString(IDS_IOS_BOOKMARK_URL_FIELD_VALIDATION_FAILED);
-  self.invalidURLLabel.textColor = [UIColor redColor];
-  self.invalidURLLabel.font =
-      [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
-  self.invalidURLLabel.adjustsFontForContentSizeCategory = YES;
-  [self.invalidURLLabel
-      setContentCompressionResistancePriority:UILayoutPriorityRequired
-                                      forAxis:UILayoutConstraintAxisVertical];
-  [self.invalidURLLabel
-      setContentHuggingPriority:UILayoutPriorityDefaultLow
-                        forAxis:UILayoutConstraintAxisHorizontal];
-
-  // Vertical StackView.
-  UIStackView* verticalStack = [[UIStackView alloc]
-      initWithArrangedSubviews:@[ horizontalStack, self.invalidURLLabel ]];
-  verticalStack.axis = UILayoutConstraintAxisVertical;
-  verticalStack.translatesAutoresizingMaskIntoConstraints = NO;
-  [verticalStack
-      setContentCompressionResistancePriority:UILayoutPriorityRequired
-                                      forAxis:UILayoutConstraintAxisVertical];
-  [self.contentView addSubview:verticalStack];
+  horizontalStack.translatesAutoresizingMaskIntoConstraints = NO;
+  [self.contentView addSubview:horizontalStack];
 
   // Set up constraints.
   [NSLayoutConstraint activateConstraints:@[
-    [verticalStack.topAnchor
+    [horizontalStack.topAnchor
         constraintEqualToAnchor:self.contentView.topAnchor
                        constant:kBookmarkCellVerticalInset],
-    [verticalStack.bottomAnchor
+    [horizontalStack.bottomAnchor
         constraintEqualToAnchor:self.contentView.bottomAnchor
                        constant:-kBookmarkCellVerticalInset],
-    [verticalStack.leadingAnchor
+    [horizontalStack.leadingAnchor
         constraintEqualToAnchor:self.contentView.leadingAnchor
                        constant:kBookmarkCellHorizontalLeadingInset],
-    [verticalStack.trailingAnchor
+    [horizontalStack.trailingAnchor
         constraintEqualToAnchor:self.contentView.trailingAnchor
                        constant:-kBookmarkCellHorizontalTrailingInset],
   ]];
@@ -183,24 +153,12 @@
   return self;
 }
 
-- (void)setValidState:(BOOL)validState {
-  _validState = validState;
-  if (validState) {
-    self.invalidURLLabel.hidden = YES;
-    self.textField.textColor = [UIColor lightGrayColor];
-  } else {
-    self.invalidURLLabel.hidden = NO;
-    self.textField.textColor = [UIColor redColor];
-  }
-}
-
 - (void)prepareForReuse {
   [super prepareForReuse];
   [self.textField resignFirstResponder];
   [self.textField removeTarget:nil
                         action:NULL
               forControlEvents:UIControlEventAllEvents];
-  self.validState = YES;
   self.textField.delegate = nil;
   self.textField.text = nil;
 }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.cc b/ios/chrome/browser/ui/omnibox/omnibox_util.cc
index 42ca1d9..c9d9a1b8 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.cc
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.cc
@@ -48,6 +48,10 @@
       // never sent to the search provider.
       DCHECK(!is_incognito);
       return IDR_IOS_OMNIBOX_CALCULATOR;
+    case AutocompleteMatchType::DOCUMENT_SUGGESTION:
+      // Document suggeestions aren't yet supported on mobile.
+      NOTREACHED();
+      return IDR_IOS_OMNIBOX_HTTP;
     case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
     case AutocompleteMatchType::NUM_TYPES:
       NOTREACHED();
@@ -69,6 +73,7 @@
     case AutocompleteMatchType::PHYSICAL_WEB_DEPRECATED:
     case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW_DEPRECATED:
     case AutocompleteMatchType::URL_WHAT_YOU_TYPED:
+    case AutocompleteMatchType::DOCUMENT_SUGGESTION:
       return "omnibox_completion_default_favicon";
     case AutocompleteMatchType::HISTORY_BODY:
     case AutocompleteMatchType::HISTORY_KEYWORD:
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
index 4d094c5..628caac3 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller.mm
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_table_view_controller_commands.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -79,6 +80,7 @@
     [self.tableView selectRowAtIndexPath:rowIndexPath
                                 animated:NO
                           scrollPosition:UITableViewScrollPositionNone];
+    TriggerHapticFeedbackForSelectionChange();
   }
 }
 
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index ed1f613..96b0ce4 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -1182,6 +1182,7 @@
 - (void)handleTabSwitcherLongPress:(UILongPressGestureRecognizer*)gesture {
   if (gesture.state == UIGestureRecognizerStateBegan) {
     [self.dispatcher showTabStripTabGridButtonPopup];
+    TriggerHapticFeedbackForAction();
   } else if (gesture.state == UIGestureRecognizerStateEnded) {
     [self.longPressDelegate
         longPressEndedAtPoint:[gesture locationOfTouch:0 inView:nil]];
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
index fe7bb6a..6d7acad9 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
@@ -368,11 +368,11 @@
 
 // Adds a LongPressGesture to the |view|, with target on -|handleLongPress:|.
 - (void)addLongPressGestureToView:(UIView*)view {
-  UILongPressGestureRecognizer* navigationHistoryLongPress =
+  UILongPressGestureRecognizer* longPressGestureRecognizer =
       [[UILongPressGestureRecognizer alloc]
           initWithTarget:self
                   action:@selector(handleLongPress:)];
-  [view addGestureRecognizer:navigationHistoryLongPress];
+  [view addGestureRecognizer:longPressGestureRecognizer];
 }
 
 // Handles the long press on the views.
@@ -390,6 +390,7 @@
       base::RecordAction(base::UserMetricsAction("MobileToolbarShowMenu"));
       [self.dispatcher showToolsMenuPopup];
     }
+    TriggerHapticFeedbackForAction();
   } else if (gesture.state == UIGestureRecognizerStateEnded) {
     [self.longPressDelegate
         longPressEndedAtPoint:[gesture locationOfTouch:0 inView:nil]];
diff --git a/ios/web_view/internal/signin/web_view_signin_manager_factory.mm b/ios/web_view/internal/signin/web_view_signin_manager_factory.mm
index b2472e8..ed1ad46 100644
--- a/ios/web_view/internal/signin/web_view_signin_manager_factory.mm
+++ b/ios/web_view/internal/signin/web_view_signin_manager_factory.mm
@@ -75,7 +75,7 @@
       WebViewAccountTrackerServiceFactory::GetForBrowserState(browser_state),
       WebViewGaiaCookieManagerServiceFactory::GetForBrowserState(browser_state),
       WebViewSigninErrorControllerFactory::GetForBrowserState(browser_state),
-      signin::AccountConsistencyMethod::kMirror);
+      signin::AccountConsistencyMethod::kDisabled);
   service->Initialize(ApplicationContext::GetInstance()->GetLocalState());
   return service;
 }
diff --git a/ios/web_view/test/BUILD.gn b/ios/web_view/test/BUILD.gn
index 3e646ac6..10551a5 100644
--- a/ios/web_view/test/BUILD.gn
+++ b/ios/web_view/test/BUILD.gn
@@ -11,9 +11,9 @@
   sources = [
     "scroll_view_kvo_inttest.mm",
     "web_view_autofill_inttest.mm",
-    "web_view_int_test.h",
-    "web_view_int_test.mm",
     "web_view_inttest.mm",
+    "web_view_inttest_base.h",
+    "web_view_inttest_base.mm",
     "web_view_kvo_inttest.mm",
     "web_view_restorable_state_inttest.mm",
     "web_view_script_command_inttest.mm",
diff --git a/ios/web_view/test/scroll_view_kvo_inttest.mm b/ios/web_view/test/scroll_view_kvo_inttest.mm
index f0f530b..6189f1ef 100644
--- a/ios/web_view/test/scroll_view_kvo_inttest.mm
+++ b/ios/web_view/test/scroll_view_kvo_inttest.mm
@@ -7,7 +7,7 @@
 
 #import "base/test/ios/wait_util.h"
 #import "ios/web_view/test/observer.h"
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 #import "ios/web_view/test/web_view_test_util.h"
 #include "testing/gtest_mac.h"
 
@@ -19,7 +19,7 @@
 
 // Tests that the KVO compliant properties of CWVScrollView correctly report
 // changes.
-typedef ios_web_view::WebViewIntTest ScrollViewKvoTest;
+typedef ios_web_view::WebViewInttestBase ScrollViewKvoTest;
 
 // Tests that CWVScrollView correctly reports |contentOffset| state.
 TEST_F(ScrollViewKvoTest, contentOffset) {
diff --git a/ios/web_view/test/web_view_autofill_inttest.mm b/ios/web_view/test/web_view_autofill_inttest.mm
index e9537a2..284442a 100644
--- a/ios/web_view/test/web_view_autofill_inttest.mm
+++ b/ios/web_view/test/web_view_autofill_inttest.mm
@@ -8,7 +8,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 #import "ios/web_view/test/web_view_test_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -47,7 +47,7 @@
 }  // namespace
 
 // Tests autofill features in CWVWebViews.
-class WebViewAutofillTest : public WebViewIntTest {
+class WebViewAutofillTest : public WebViewInttestBase {
  protected:
   WebViewAutofillTest() : autofill_controller_(web_view_.autofillController) {}
 
diff --git a/ios/web_view/test/web_view_inttest.mm b/ios/web_view/test/web_view_inttest.mm
index 850548c..b01b439 100644
--- a/ios/web_view/test/web_view_inttest.mm
+++ b/ios/web_view/test/web_view_inttest.mm
@@ -6,7 +6,7 @@
 #import <Foundation/Foundation.h>
 
 #import "base/test/ios/wait_util.h"
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 #import "ios/web_view/test/web_view_test_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -27,7 +27,7 @@
 // Tests public methods in CWVWebView.
 //
 // Note that some methods are covered by other tests in this directory.
-class WebViewTest : public ios_web_view::WebViewIntTest {
+class WebViewTest : public ios_web_view::WebViewInttestBase {
  public:
   void SetUp() override {
     test_server_->RegisterRequestHandler(base::BindRepeating(
diff --git a/ios/web_view/test/web_view_int_test.h b/ios/web_view/test/web_view_inttest_base.h
similarity index 86%
rename from ios/web_view/test/web_view_int_test.h
rename to ios/web_view/test/web_view_inttest_base.h
index 39c9e68..cb3c30b 100644
--- a/ios/web_view/test/web_view_int_test.h
+++ b/ios/web_view/test/web_view_inttest_base.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_VIEW_TEST_WEB_VIEW_INT_TEST_H_
-#define IOS_WEB_VIEW_TEST_WEB_VIEW_INT_TEST_H_
+#ifndef IOS_WEB_VIEW_TEST_WEB_VIEW_INTTEST_BASE_H_
+#define IOS_WEB_VIEW_TEST_WEB_VIEW_INTTEST_BASE_H_
 
 #import <Foundation/Foundation.h>
 #include <memory>
@@ -28,10 +28,10 @@
 // A test fixture for testing CWVWebView. A test server is also created to
 // support loading content. The server supports the urls returned by the GetUrl*
 // methods below.
-class WebViewIntTest : public PlatformTest {
+class WebViewInttestBase : public PlatformTest {
  protected:
-  WebViewIntTest();
-  ~WebViewIntTest() override;
+  WebViewInttestBase();
+  ~WebViewInttestBase() override;
 
   // Returns URL to an html page with title set to |title|.
   //
@@ -63,4 +63,4 @@
 
 NS_ASSUME_NONNULL_END
 
-#endif  // IOS_WEB_VIEW_TEST_WEB_VIEW_INT_TEST_H_
+#endif  // IOS_WEB_VIEW_TEST_WEB_VIEW_INTTEST_BASE_H_
diff --git a/ios/web_view/test/web_view_int_test.mm b/ios/web_view/test/web_view_inttest_base.mm
similarity index 88%
rename from ios/web_view/test/web_view_int_test.mm
rename to ios/web_view/test/web_view_inttest_base.mm
index 59a7e194c..c2a5178e 100644
--- a/ios/web_view/test/web_view_int_test.mm
+++ b/ios/web_view/test/web_view_inttest_base.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 
 #import <ChromeWebView/ChromeWebView.h>
 #import <Foundation/Foundation.h>
@@ -96,25 +96,27 @@
 
 namespace ios_web_view {
 
-WebViewIntTest::WebViewIntTest()
+WebViewInttestBase::WebViewInttestBase()
     : web_view_(test::CreateWebView()),
       test_server_(std::make_unique<net::EmbeddedTestServer>(
           net::test_server::EmbeddedTestServer::TYPE_HTTP)) {
-  test_server_->RegisterRequestHandler(base::Bind(&TestRequestHandler));
+  test_server_->RegisterRequestHandler(
+      base::BindRepeating(&TestRequestHandler));
 }
 
-WebViewIntTest::~WebViewIntTest() = default;
+WebViewInttestBase::~WebViewInttestBase() = default;
 
-GURL WebViewIntTest::GetUrlForPageWithTitle(const std::string& title) {
+GURL WebViewInttestBase::GetUrlForPageWithTitle(const std::string& title) {
   return GetUrlForPageWithTitleAndBody(title, std::string());
 }
 
-GURL WebViewIntTest::GetUrlForPageWithHtmlBody(const std::string& html) {
+GURL WebViewInttestBase::GetUrlForPageWithHtmlBody(const std::string& html) {
   return GetUrlForPageWithTitleAndBody(std::string(), html);
 }
 
-GURL WebViewIntTest::GetUrlForPageWithTitleAndBody(const std::string& title,
-                                                   const std::string& body) {
+GURL WebViewInttestBase::GetUrlForPageWithTitleAndBody(
+    const std::string& title,
+    const std::string& body) {
   GURL url = test_server_->GetURL(kPageHtmlPath);
 
   // Encode |title| and |body| in url query in order to build the server
diff --git a/ios/web_view/test/web_view_kvo_inttest.mm b/ios/web_view/test/web_view_kvo_inttest.mm
index 645f42b..050716f 100644
--- a/ios/web_view/test/web_view_kvo_inttest.mm
+++ b/ios/web_view/test/web_view_kvo_inttest.mm
@@ -8,7 +8,7 @@
 #include "base/strings/stringprintf.h"
 #import "base/strings/sys_string_conversions.h"
 #import "ios/web_view/test/observer.h"
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 #import "ios/web_view/test/web_view_test_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -23,7 +23,7 @@
 
 // Tests that the KVO compliant properties of CWVWebView correctly report
 // changes.
-typedef ios_web_view::WebViewIntTest WebViewKvoTest;
+typedef ios_web_view::WebViewInttestBase WebViewKvoTest;
 
 // Tests that CWVWebView correctly reports |canGoBack| and |canGoForward| state.
 TEST_F(WebViewKvoTest, CanGoBackForward) {
diff --git a/ios/web_view/test/web_view_restorable_state_inttest.mm b/ios/web_view/test/web_view_restorable_state_inttest.mm
index c4a8400..c38c645 100644
--- a/ios/web_view/test/web_view_restorable_state_inttest.mm
+++ b/ios/web_view/test/web_view_restorable_state_inttest.mm
@@ -4,7 +4,7 @@
 
 #import <ChromeWebView/ChromeWebView.h>
 
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 #import "ios/web_view/test/web_view_test_util.h"
 #include "testing/gtest_mac.h"
 
@@ -16,7 +16,7 @@
 
 // Tests encodeRestorableStateWithCoder: and decodeRestorableStateWithCoder:
 // methods.
-typedef ios_web_view::WebViewIntTest WebViewRestorableStateTest;
+typedef ios_web_view::WebViewInttestBase WebViewRestorableStateTest;
 TEST_F(WebViewRestorableStateTest, EncodeDecode) {
   // Load 2 URLs to create non-default state.
   ASSERT_FALSE([web_view_ lastCommittedURL]);
diff --git a/ios/web_view/test/web_view_script_command_inttest.mm b/ios/web_view/test/web_view_script_command_inttest.mm
index 97322319..067dc2f 100644
--- a/ios/web_view/test/web_view_script_command_inttest.mm
+++ b/ios/web_view/test/web_view_script_command_inttest.mm
@@ -6,7 +6,7 @@
 #import <Foundation/Foundation.h>
 
 #import "base/test/ios/wait_util.h"
-#import "ios/web_view/test/web_view_int_test.h"
+#import "ios/web_view/test/web_view_inttest_base.h"
 #import "ios/web_view/test/web_view_test_util.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -43,7 +43,7 @@
 namespace ios_web_view {
 
 // Tests the script command feature in CWVWebView.
-using WebViewScriptCommandTest = WebViewIntTest;
+using WebViewScriptCommandTest = WebViewInttestBase;
 
 // Tests that a handler added by -[CWVWebView
 // addScriptCommandHandler:commandPrefix] is invoked by JavaScript.
diff --git a/media/blink/webmediaplayer_delegate.h b/media/blink/webmediaplayer_delegate.h
index 1c6c5b5a..96b66d2 100644
--- a/media/blink/webmediaplayer_delegate.h
+++ b/media/blink/webmediaplayer_delegate.h
@@ -78,7 +78,10 @@
     virtual void OnPictureInPictureModeEnded() = 0;
 
     // Called when a custom control is clicked on the Picture-in-Picture window.
-    virtual void OnPictureInPictureControlClicked() = 0;
+    // |control_id| is the identifier for its custom control. This is defined by
+    // the site that calls the web API.
+    virtual void OnPictureInPictureControlClicked(
+        const std::string& control_id) = 0;
   };
 
   // Returns true if the host frame is hidden or closed.
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 02c4d3fa..bfda277 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -1126,6 +1126,12 @@
 }
 
 bool WebMediaPlayerImpl::HasSingleSecurityOrigin() const {
+  if (demuxer_found_hls_) {
+    // HLS manifests might pull segments from a different origin. We can't know
+    // for sure, so we conservatively say no here.
+    return false;
+  }
+
   if (data_source_)
     return data_source_->HasSingleOrigin();
   return true;
@@ -1530,6 +1536,8 @@
 
 #if defined(OS_ANDROID)
   if (status == PipelineStatus::DEMUXER_ERROR_DETECTED_HLS) {
+    demuxer_found_hls_ = true;
+
     renderer_factory_selector_->SetUseMediaPlayer(true);
 
     pipeline_controller_.Stop();
@@ -2086,10 +2094,12 @@
   client_->PictureInPictureStopped();
 }
 
-void WebMediaPlayerImpl::OnPictureInPictureControlClicked() {
+void WebMediaPlayerImpl::OnPictureInPictureControlClicked(
+    const std::string& control_id) {
   if (client_ && client_->DisplayType() ==
                      WebMediaPlayer::DisplayType::kPictureInPicture) {
-    client_->PictureInPictureControlClicked();
+    client_->PictureInPictureControlClicked(
+        blink::WebString::FromUTF8(control_id));
   }
 }
 
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 5ae91aa..c579785 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -243,7 +243,7 @@
   void OnVolumeMultiplierUpdate(double multiplier) override;
   void OnBecamePersistentVideo(bool value) override;
   void OnPictureInPictureModeEnded() override;
-  void OnPictureInPictureControlClicked() override;
+  void OnPictureInPictureControlClicked(const std::string& control_id) override;
 
   void RequestRemotePlaybackDisabled(bool disabled) override;
 #if defined(OS_ANDROID)  // WMPI_CAST
@@ -788,6 +788,11 @@
   // removing |cast_impl_|.
   bool using_media_player_renderer_ = false;
 
+  // Set whenever the demuxer encounters an HLS file.
+  // This flag is distinct from |using_media_player_renderer_|, because on older
+  // devices we might use MediaPlayerRenderer for non HLS playback.
+  bool demuxer_found_hls_ = false;
+
   // Called sometime after the media is suspended in a playing state in
   // OnFrameHidden(), causing the state to change to paused.
   base::OneShotTimer background_pause_timer_;
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 5ab37e7a..2f28a42 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -173,7 +173,7 @@
   MOCK_METHOD1(MediaRemotingStopped, void(blink::WebLocalizedString::Name));
   MOCK_METHOD0(PictureInPictureStarted, void());
   MOCK_METHOD0(PictureInPictureStopped, void());
-  MOCK_METHOD0(PictureInPictureControlClicked, void());
+  MOCK_METHOD1(PictureInPictureControlClicked, void(const blink::WebString&));
   MOCK_CONST_METHOD0(CouldPlayIfEnoughData, bool());
   MOCK_METHOD0(RequestPlay, void());
   MOCK_METHOD0(RequestPause, void());
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index 800fb69..708d26daa 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -690,6 +690,92 @@
   return true;
 }
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+AV1CodecConfigurationRecord::AV1CodecConfigurationRecord()
+    : profile(VIDEO_CODEC_PROFILE_UNKNOWN) {}
+
+AV1CodecConfigurationRecord::AV1CodecConfigurationRecord(
+    const AV1CodecConfigurationRecord& other) = default;
+
+AV1CodecConfigurationRecord::~AV1CodecConfigurationRecord() = default;
+
+FourCC AV1CodecConfigurationRecord::BoxType() const {
+  return FOURCC_AV1C;
+}
+
+bool AV1CodecConfigurationRecord::Parse(BoxReader* reader) {
+  RCHECK(reader->ReadFullBoxHeader());
+
+  // Skip over unused parts of the configuration record.
+  RCHECK(reader->SkipBytes(1));
+
+  // We need to scan through the OBUs to find the profile.
+  while (profile == VIDEO_CODEC_PROFILE_UNKNOWN) {
+    // Zero or more OBUs are allowed, when none are present assume main profile.
+    if (!reader->HasBytes(1)) {
+      DVLOG(2) << "No OBU_SEQUENCE_HEADER is present, assuming main profile.";
+      profile = AV1PROFILE_PROFILE_MAIN;
+      return true;
+    }
+
+    uint8_t obu_header;
+    RCHECK(reader->Read1(&obu_header));
+
+    // Skip over the extension header if needed.
+    if (obu_header & 0b100 /* obu_extension_flag */)
+      RCHECK(reader->SkipBytes(1));
+
+    // Low overhead bitstream OBUs, when contained within configOBUs, are
+    // required to have a size field.
+    DCHECK(obu_header & 0b10 /* obu_has_size_field */);
+
+    // Read the size out in LEB128 format. Per spec this must always fit in a
+    // uint32_t, but since the max shift below is 49 (7*7), use a uint64_t to
+    // avoid any undefined behavior.
+    uint64_t obu_size = 0u;
+    for (int i = 0; i < 8; ++i) {
+      uint8_t leb128_byte;
+      RCHECK(reader->Read1(&leb128_byte));
+      obu_size |= static_cast<uint64_t>(leb128_byte & 0x7f) << (i * 7);
+      if (!(leb128_byte & 0x80))
+        break;
+    }
+    RCHECK(reader->HasBytes(obu_size));
+
+    // Clear out everything except for the obu_type.
+    const uint8_t obu_type = (obu_header >> 3) & 0b1111;
+
+    // We only want to look at OBUs of type OBU_SEQUENCE_HEADER.
+    if (obu_type != 1 /* OBU_SEQUENCE_HEADER */) {
+      RCHECK(reader->SkipBytes(obu_size));
+      continue;
+    }
+
+    // Read enough of the sequence header to parse |seq_profile|.
+    uint8_t sequence_header;
+    RCHECK(reader->Read1(&sequence_header));
+
+    const uint8_t seq_profile = sequence_header >> 5;
+    switch (seq_profile) {
+      case 0:
+        profile = AV1PROFILE_PROFILE_MAIN;
+        break;
+      case 1:
+        profile = AV1PROFILE_PROFILE_HIGH;
+        break;
+      case 2:
+        profile = AV1PROFILE_PROFILE_PRO;
+        break;
+      default:
+        MEDIA_LOG(ERROR, reader->media_log())
+            << "Unsupported AV1 profile: 0x" << std::hex << seq_profile;
+        return false;
+    }
+  }
+  return true;
+}
+#endif  // BUILDFLAG(ENABLE_AV1_DECODER)
+
 PixelAspectRatioBox::PixelAspectRatioBox() : h_spacing(1), v_spacing(1) {}
 PixelAspectRatioBox::PixelAspectRatioBox(const PixelAspectRatioBox& other) =
     default;
@@ -842,11 +928,11 @@
 #if BUILDFLAG(ENABLE_AV1_DECODER)
     case FOURCC_AV01: {
       DVLOG(2) << __func__ << " reading AV1 configuration.";
-      // TODO(dalecurtis): This needs updating to read the actual profile and
-      // configuration before enabling for release. http://crbug.com/784993
+      AV1CodecConfigurationRecord av1_config;
+      RCHECK(reader->ReadChild(&av1_config));
       frame_bitstream_converter = nullptr;
       video_codec = kCodecAV1;
-      video_codec_profile = AV1PROFILE_PROFILE_MAIN;
+      video_codec_profile = av1_config.profile;
       break;
     }
 #endif
diff --git a/media/formats/mp4/box_definitions.h b/media/formats/mp4/box_definitions.h
index 847c6b7..d07ebbc 100644
--- a/media/formats/mp4/box_definitions.h
+++ b/media/formats/mp4/box_definitions.h
@@ -252,6 +252,14 @@
   VideoCodecProfile profile;
 };
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+struct MEDIA_EXPORT AV1CodecConfigurationRecord : Box {
+  DECLARE_BOX_METHODS(AV1CodecConfigurationRecord);
+
+  VideoCodecProfile profile;
+};
+#endif
+
 struct MEDIA_EXPORT PixelAspectRatioBox : Box {
   DECLARE_BOX_METHODS(PixelAspectRatioBox);
 
diff --git a/media/formats/mp4/fourccs.h b/media/formats/mp4/fourccs.h
index 6d028ac..1b73d00c 100644
--- a/media/formats/mp4/fourccs.h
+++ b/media/formats/mp4/fourccs.h
@@ -21,6 +21,7 @@
 #endif
 #if BUILDFLAG(ENABLE_AV1_DECODER)
   FOURCC_AV01 = 0x61763031,  // "av01"
+  FOURCC_AV1C = 0x61763143,  // "av1C"
 #endif
   FOURCC_AVC1 = 0x61766331,
   FOURCC_AVC3 = 0x61766333,
diff --git a/media/media_options.gni b/media/media_options.gni
index 17aff0a8..d8e20f6 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -177,14 +177,14 @@
 # Can be overridden by gn build arguments from the --args command line flag
 # for local testing.
 if (enable_mojo_media) {
-  if (is_chromecast && is_cast_using_cma_backend) {
+  if (is_chromecast && is_cast_using_cma_backend && !is_android) {
     _default_mojo_media_services = [
       "cdm",
       "renderer",
     ]
     _default_mojo_media_host = "browser"
   } else if (is_android) {
-    # Both chrome for Android and cast for ATV belongs to this case
+    # Both chrome for Android and cast for Android belongs to this case
     _default_mojo_media_services = [
       "cdm",
       "audio_decoder",
diff --git a/media/test/BUILD.gn b/media/test/BUILD.gn
index 0478dd1..5b541e59 100644
--- a/media/test/BUILD.gn
+++ b/media/test/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//media/media_options.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/libaom/options.gni")
 
 source_set("run_all_unittests") {
   testonly = true
@@ -167,6 +168,10 @@
   # See below for additional variants depending on build configuration.
 ]
 
+if (enable_av1_decoder) {
+  pipeline_integration_fuzzer_variants += [ "MP4_AV1" ]
+}
+
 if (proprietary_codecs) {
   pipeline_integration_fuzzer_variants += [
     "ADTS",
@@ -210,6 +215,7 @@
       # header for pipeline_integration_test_base.h.  This should be
       # moved into the .cc file to avoid the extra dependency here.
       "//testing/gmock",
+      "//third_party/libaom:av1_buildflags",
       "//ui/gfx:test_support",
     ]
 
diff --git a/media/test/data/bear-av1.mp4 b/media/test/data/bear-av1.mp4
index da8da62..adadb38 100644
--- a/media/test/data/bear-av1.mp4
+++ b/media/test/data/bear-av1.mp4
Binary files differ
diff --git a/media/test/mp4.dict b/media/test/mp4.dict
index d6c29e63..247d709 100644
--- a/media/test/mp4.dict
+++ b/media/test/mp4.dict
@@ -1,6 +1,8 @@
 FOURCC_NULL="\x00\x00\x00\x00"
 FOURCC_AC3 ="\x61\x63\x2d\x33"
 FOURCC_EAC3="\x65\x63\x2d\x33"
+FOURCC_AV01="\x61\x76\x30\x31"
+FOURCC_AV1C="\x61\x76\x31\x43"
 FOURCC_AVC1="\x61\x76\x63\x31"
 FOURCC_AVC3="\x61\x76\x63\x33"
 FOURCC_AVCC="\x61\x76\x63\x43"
diff --git a/media/test/pipeline_integration_fuzzertest.cc b/media/test/pipeline_integration_fuzzertest.cc
index e02a71b..673a292 100644
--- a/media/test/pipeline_integration_fuzzertest.cc
+++ b/media/test/pipeline_integration_fuzzertest.cc
@@ -20,6 +20,7 @@
 #include "media/base/pipeline_status.h"
 #include "media/test/mock_media_source.h"
 #include "media/test/pipeline_integration_test_base.h"
+#include "third_party/libaom/av1_buildflags.h"
 
 namespace {
 
@@ -31,6 +32,9 @@
   WEBM_VP8,
   WEBM_VP9,
   WEBM_OPUS_VP9,
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  MP4_AV1,
+#endif
   MP4_FLAC,
   MP3,
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -61,6 +65,10 @@
       return "video/webm; codecs=\"vp9\"";
     case WEBM_OPUS_VP9:
       return "video/webm; codecs=\"opus,vp9\"";
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+    case MP4_AV1:
+      return "video/mp4; codecs=\"av01.0.04M.08\"";
+#endif  // BUILDFLAG(ENABLE_AV1_DECODER)
     case MP4_FLAC:
       return "audio/mp4; codecs=\"flac\"";
     case MP3:
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 16a6779..74cd7eb 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -765,8 +765,7 @@
 
 #if BUILDFLAG(ENABLE_AV1_DECODER)
     // AV1 in MP4
-    // TODO(johannkoenig): re-enable when an av1 mp4 muxer is available.
-    // {"bear-av1.mp4", kMP4AV1, kAppendWholeFile, kVP9WebMFileDurationMs},
+    {"bear-av1.mp4", kMP4AV1, kAppendWholeFile, kVP9WebMFileDurationMs},
 
     // AV1 in WebM
     {"bear-av1.webm", kWebMAV1, kAppendWholeFile, kVP9WebMFileDurationMs},
@@ -1072,9 +1071,7 @@
   Stop();
 }
 
-// Flaky crashes on multiple platforms. crbug.com/864018
-TEST_F(PipelineIntegrationTest,
-       DISABLED_PipelineStoppedWhileVideoRestartPending) {
+TEST_F(PipelineIntegrationTest, PipelineStoppedWhileVideoRestartPending) {
   ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm"));
   Play();
 
@@ -1760,11 +1757,10 @@
 #endif
 
 #if BUILDFLAG(ENABLE_AV1_DECODER)
-// TODO(johannkoenig): re-enable when an av1 mp4 muxer is available.
-TEST_P(MSEPipelineIntegrationTest, DISABLED_BasicPlayback_AV1_MP4) {
+TEST_P(MSEPipelineIntegrationTest, BasicPlayback_AV1_MP4) {
   base::test::ScopedFeatureList scoped_feature_list_;
   scoped_feature_list_.InitAndEnableFeature(kAv1Decoder);
-  MockMediaSource source("bear-av1.mp4", kMP4AV1, 80496);
+  MockMediaSource source("bear-av1.mp4", kMP4AV1, 24723);
   EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));
   source.EndOfStream();
 
@@ -1817,8 +1813,7 @@
 }
 
 #if BUILDFLAG(ENABLE_AV1_DECODER)
-// TODO(johannkoenig): re-enable when an av1 mp4 muxer is available.
-TEST_F(PipelineIntegrationTest, DISABLED_BasicPlayback_VideoOnly_AV1_Mp4) {
+TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_AV1_Mp4) {
   base::test::ScopedFeatureList scoped_feature_list_;
   scoped_feature_list_.InitAndEnableFeature(kAv1Decoder);
   ASSERT_EQ(PIPELINE_OK, Start("bear-av1.mp4"));
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index ef0a914d..7a15f2f 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -400,7 +400,7 @@
 void PipelineIntegrationTestBase::QuitAfterCurrentTimeTask(
     base::TimeDelta quit_time,
     base::OnceClosure quit_closure) {
-  if (pipeline_->GetMediaTime() >= quit_time ||
+  if (!pipeline_ || pipeline_->GetMediaTime() >= quit_time ||
       pipeline_status_ != PIPELINE_OK) {
     std::move(quit_closure).Run();
     return;
diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h
index 6842c7c..581c91d8 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -113,6 +113,7 @@
   void QueryVersion(const base::Callback<void(uint32_t)>& callback);
   void RequireVersion(uint32_t version);
   void FlushForTesting();
+  void FlushAsyncForTesting(base::OnceClosure callback);
 
  private:
   // Maps from the id of a response to the MessageReceiver that handles the
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
index 3ec522d..0d7d6ff 100644
--- a/mojo/public/cpp/bindings/interface_ptr.h
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -127,6 +127,12 @@
   // stimulus.
   void FlushForTesting() { internal_state_.FlushForTesting(); }
 
+  // Same as |FlushForTesting()| but will call |callback| when the flush is
+  // complete.
+  void FlushAsyncForTesting(base::OnceClosure callback) {
+    internal_state_.FlushAsyncForTesting(std::move(callback));
+  }
+
   // Closes the bound message pipe, if any.
   void reset() {
     State doomed;
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index 9fd7bf41..5e6c3808 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -12,6 +12,7 @@
 #include "base/callback_helpers.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
 #include "mojo/public/cpp/bindings/lib/validation_util.h"
 #include "mojo/public/cpp/bindings/message.h"
@@ -39,12 +40,12 @@
 }
 
 using RunCallback =
-    base::Callback<void(interface_control::RunResponseMessageParamsPtr)>;
+    base::OnceCallback<void(interface_control::RunResponseMessageParamsPtr)>;
 
 class RunResponseForwardToCallback : public MessageReceiver {
  public:
-  explicit RunResponseForwardToCallback(const RunCallback& callback)
-      : callback_(callback) {}
+  explicit RunResponseForwardToCallback(RunCallback callback)
+      : callback_(std::move(callback)) {}
   bool Accept(Message* message) override;
 
  private:
@@ -65,13 +66,13 @@
   Deserialize<interface_control::RunResponseMessageParamsDataView>(
       params, &params_ptr, &context);
 
-  callback_.Run(std::move(params_ptr));
+  std::move(callback_).Run(std::move(params_ptr));
   return true;
 }
 
 void SendRunMessage(MessageReceiverWithResponder* receiver,
                     interface_control::RunInputPtr input_ptr,
-                    const RunCallback& callback) {
+                    RunCallback callback) {
   auto params_ptr = interface_control::RunMessageParams::New();
   params_ptr->input = std::move(input_ptr);
   Message message(interface_control::kRunMessageId,
@@ -81,7 +82,7 @@
   Serialize<interface_control::RunMessageParamsDataView>(
       params_ptr, message.payload_buffer(), &params, &context);
   std::unique_ptr<MessageReceiver> responder =
-      std::make_unique<RunResponseForwardToCallback>(callback);
+      std::make_unique<RunResponseForwardToCallback>(std::move(callback));
   ignore_result(receiver->AcceptWithResponder(&message, std::move(responder)));
 }
 
@@ -115,9 +116,9 @@
   callback.Run(version);
 }
 
-void RunClosure(const base::Closure& callback,
+void RunClosure(base::OnceClosure callback,
                 interface_control::RunResponseMessageParamsPtr run_response) {
-  callback.Run();
+  std::move(callback).Run();
 }
 
 }  // namespace
@@ -133,7 +134,7 @@
   auto input_ptr = interface_control::RunInput::New();
   input_ptr->set_query_version(interface_control::QueryVersion::New());
   SendRunMessage(receiver_, std::move(input_ptr),
-                 base::Bind(&RunVersionCallback, callback));
+                 base::BindOnce(&RunVersionCallback, callback));
 }
 
 void ControlMessageProxy::RequireVersion(uint32_t version) {
@@ -145,29 +146,38 @@
 }
 
 void ControlMessageProxy::FlushForTesting() {
-  if (encountered_error_)
-    return;
-
-  auto input_ptr = interface_control::RunInput::New();
-  input_ptr->set_flush_for_testing(interface_control::FlushForTesting::New());
   base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-  run_loop_quit_closure_ = run_loop.QuitClosure();
-  SendRunMessage(
-      receiver_, std::move(input_ptr),
-      base::Bind(&RunClosure,
-                 base::Bind(&ControlMessageProxy::RunFlushForTestingClosure,
-                            base::Unretained(this))));
+  FlushAsyncForTesting(run_loop.QuitClosure());
   run_loop.Run();
 }
 
+void ControlMessageProxy::FlushAsyncForTesting(base::OnceClosure callback) {
+  if (encountered_error_) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                     std::move(callback));
+    return;
+  }
+
+  auto input_ptr = interface_control::RunInput::New();
+  input_ptr->set_flush_for_testing(interface_control::FlushForTesting::New());
+  DCHECK(!pending_flush_callback_);
+  pending_flush_callback_ = std::move(callback);
+  SendRunMessage(
+      receiver_, std::move(input_ptr),
+      base::BindOnce(
+          &RunClosure,
+          base::BindOnce(&ControlMessageProxy::RunFlushForTestingClosure,
+                         base::Unretained(this))));
+}
+
 void ControlMessageProxy::RunFlushForTestingClosure() {
-  DCHECK(!run_loop_quit_closure_.is_null());
-  base::ResetAndReturn(&run_loop_quit_closure_).Run();
+  DCHECK(!pending_flush_callback_.is_null());
+  std::move(pending_flush_callback_).Run();
 }
 
 void ControlMessageProxy::OnConnectionError() {
   encountered_error_ = true;
-  if (!run_loop_quit_closure_.is_null())
+  if (!pending_flush_callback_.is_null())
     RunFlushForTestingClosure();
 }
 
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.h b/mojo/public/cpp/bindings/lib/control_message_proxy.h
index 2f9314e..f15ba24 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.h
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.h
@@ -29,6 +29,7 @@
   void RequireVersion(uint32_t version);
 
   void FlushForTesting();
+  void FlushAsyncForTesting(base::OnceClosure callback);
   void OnConnectionError();
 
  private:
@@ -38,7 +39,7 @@
   MessageReceiverWithResponder* receiver_;
   bool encountered_error_ = false;
 
-  base::Closure run_loop_quit_closure_;
+  base::OnceClosure pending_flush_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ControlMessageProxy);
 };
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index 6f119e4..4e6108d 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -347,6 +347,10 @@
   control_message_proxy_.FlushForTesting();
 }
 
+void InterfaceEndpointClient::FlushAsyncForTesting(base::OnceClosure callback) {
+  control_message_proxy_.FlushAsyncForTesting(std::move(callback));
+}
+
 void InterfaceEndpointClient::InitControllerIfNecessary() {
   if (controller_ || handle_.pending_association())
     return;
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 2e73564..dcea866 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -131,6 +131,11 @@
     endpoint_client()->FlushForTesting();
   }
 
+  void FlushAsyncForTesting(base::OnceClosure callback) {
+    ConfigureProxyIfNecessary();
+    endpoint_client()->FlushAsyncForTesting(std::move(callback));
+  }
+
   void CloseWithReason(uint32_t custom_reason, const std::string& description) {
     ConfigureProxyIfNecessary();
     endpoint_client()->CloseWithReason(custom_reason, description);
diff --git a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
index 550a5aff..c928302 100644
--- a/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc
@@ -754,6 +754,27 @@
   EXPECT_EQ(10.0, calculator_ui.GetOutput());
 }
 
+TEST_P(InterfacePtrTest, FlushAsyncForTesting) {
+  math::CalculatorPtr calc;
+  MathCalculatorImpl calc_impl(MakeRequest(&calc));
+  calc.set_connection_error_handler(base::BindOnce(&Fail));
+
+  MathCalculatorUI calculator_ui(std::move(calc));
+
+  calculator_ui.Add(2.0, base::DoNothing());
+  base::RunLoop run_loop;
+  calculator_ui.GetInterfacePtr().FlushAsyncForTesting(run_loop.QuitClosure());
+  run_loop.Run();
+  EXPECT_EQ(2.0, calculator_ui.GetOutput());
+
+  calculator_ui.Multiply(5.0, base::DoNothing());
+  base::RunLoop run_loop2;
+  calculator_ui.GetInterfacePtr().FlushAsyncForTesting(run_loop2.QuitClosure());
+  run_loop2.Run();
+
+  EXPECT_EQ(10.0, calculator_ui.GetOutput());
+}
+
 void SetBool(bool* value) {
   *value = true;
 }
@@ -768,6 +789,21 @@
   calc.FlushForTesting();
 }
 
+TEST_P(InterfacePtrTest, FlushAsyncForTestingWithClosedPeer) {
+  math::CalculatorPtr calc;
+  MakeRequest(&calc);
+  bool called = false;
+  calc.set_connection_error_handler(base::BindOnce(&SetBool, &called));
+  base::RunLoop run_loop;
+  calc.FlushAsyncForTesting(run_loop.QuitClosure());
+  run_loop.Run();
+  EXPECT_TRUE(called);
+
+  base::RunLoop run_loop2;
+  calc.FlushAsyncForTesting(run_loop2.QuitClosure());
+  run_loop2.Run();
+}
+
 TEST_P(InterfacePtrTest, ConnectionErrorWithReason) {
   math::CalculatorPtr calc;
   MathCalculatorImpl calc_impl(MakeRequest(&calc));
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index 16f0e28..fd80563 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -43,6 +43,8 @@
 
 // This load will not make any changes to cookies, including storing new
 // cookies or updating existing ones.
+// Deprecated. Use URLRequest::set_allow_credentials instead. See
+// https://crbug.com/799935.
 LOAD_FLAG(DO_NOT_SAVE_COOKIES, 1 << 6)
 
 // Do not resolve proxies. This override is used when downloading PAC files
@@ -50,10 +52,14 @@
 LOAD_FLAG(BYPASS_PROXY, 1 << 7)
 
 // This load will not send any cookies.
+// Deprecated. Use URLRequest::set_allow_credentials instead. See
+// https://crbug.com/799935.
 LOAD_FLAG(DO_NOT_SEND_COOKIES, 1 << 8)
 
 // This load will not send authentication data (user name/password)
 // to the server (as opposed to the proxy).
+// Deprecated. Use URLRequest::set_allow_credentials instead. See
+// https://crbug.com/799935.
 LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 9)
 
 // This should only be used for testing (set by HttpNetworkTransaction).
diff --git a/net/network_error_logging/network_error_logging_end_to_end_test.cc b/net/network_error_logging/network_error_logging_end_to_end_test.cc
index 0b8a8a6..e7a7e32 100644
--- a/net/network_error_logging/network_error_logging_end_to_end_test.cc
+++ b/net/network_error_logging/network_error_logging_end_to_end_test.cc
@@ -206,7 +206,6 @@
 
   ExpectDictStringValue("http.response.empty", *body_dict, "type");
   ExpectDictIntegerValue(0, *body_dict, "status_code");
-  ExpectDictStringValue(GetFailURL().spec(), *body_dict, "uri");
 }
 
 #if defined(OS_WIN)
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index 7867394..b694d19 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -546,7 +546,6 @@
       const RequestDetails& details) const {
     auto body = std::make_unique<base::DictionaryValue>();
 
-    body->SetString(kUriKey, details.uri.spec());
     body->SetString(kReferrerKey, details.referrer.spec());
     body->SetDouble(kSamplingFractionKey, sampling_fraction);
     body->SetString(kServerIpKey, details.server_ip.ToString());
@@ -586,7 +585,6 @@
 // that generate new NEL reports to bypass the age limit on Reporting reports.
 const int NetworkErrorLoggingService::kMaxNestedReportDepth = 1;
 
-const char NetworkErrorLoggingService::kUriKey[] = "uri";
 const char NetworkErrorLoggingService::kReferrerKey[] = "referrer";
 const char NetworkErrorLoggingService::kSamplingFractionKey[] =
     "sampling_fraction";
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h
index 405f089c..cfb4968 100644
--- a/net/network_error_logging/network_error_logging_service.h
+++ b/net/network_error_logging/network_error_logging_service.h
@@ -78,7 +78,6 @@
 
   // Keys for data included in report bodies. Exposed for tests.
 
-  static const char kUriKey[];
   static const char kReferrerKey[];
   static const char kSamplingFractionKey[];
   static const char kServerIpKey[];
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 4463f3a2..86574e0 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -260,8 +260,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   // TODO(juliatuttle): Extract these constants.
@@ -298,8 +296,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   // TODO(juliatuttle): Extract these constants.
@@ -336,8 +332,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   // TODO(juliatuttle): Extract these constants.
@@ -375,8 +369,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   ExpectDictDoubleValue(1.0, *body,
@@ -413,8 +405,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   ExpectDictDoubleValue(1.0, *body,
@@ -451,8 +441,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   ExpectDictDoubleValue(1.0, *body,
@@ -489,8 +477,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   ExpectDictDoubleValue(1.0, *body,
@@ -526,8 +512,6 @@
 
   const base::DictionaryValue* body;
   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
-  base::ExpectDictStringValue(kUrl_.spec(), *body,
-                              NetworkErrorLoggingService::kUriKey);
   base::ExpectDictStringValue(kReferrer_.spec(), *body,
                               NetworkErrorLoggingService::kReferrerKey);
   ExpectDictDoubleValue(1.0, *body,
diff --git a/net/url_request/report_sender.cc b/net/url_request/report_sender.cc
index 4b0f05e..daccbe06 100644
--- a/net/url_request/report_sender.cc
+++ b/net/url_request/report_sender.cc
@@ -40,9 +40,7 @@
 
 namespace net {
 
-const int ReportSender::kLoadFlags =
-    LOAD_BYPASS_CACHE | LOAD_DISABLE_CACHE | LOAD_DO_NOT_SEND_AUTH_DATA |
-    LOAD_DO_NOT_SEND_COOKIES | LOAD_DO_NOT_SAVE_COOKIES;
+const int ReportSender::kLoadFlags = LOAD_BYPASS_CACHE | LOAD_DISABLE_CACHE;
 
 ReportSender::ReportSender(URLRequestContext* request_context,
                            net::NetworkTrafficAnnotationTag traffic_annotation)
@@ -64,6 +62,7 @@
       std::make_unique<CallbackInfo>(success_callback, error_callback));
 
   url_request->SetLoadFlags(kLoadFlags);
+  url_request->set_allow_credentials(false);
 
   HttpRequestHeaders extra_headers;
   extra_headers.SetHeader(HttpRequestHeaders::kContentType, content_type);
diff --git a/net/url_request/test_url_fetcher_factory.h b/net/url_request/test_url_fetcher_factory.h
index e85d322..305e2f6a 100644
--- a/net/url_request/test_url_fetcher_factory.h
+++ b/net/url_request/test_url_fetcher_factory.h
@@ -111,6 +111,7 @@
                            bool is_last_chunk) override;
   void SetLoadFlags(int load_flags) override;
   int GetLoadFlags() const override;
+  void SetAllowCredentials(bool allow_credentials) override {}
   void SetReferrer(const std::string& referrer) override;
   void SetReferrerPolicy(URLRequest::ReferrerPolicy referrer_policy) override;
   void SetExtraRequestHeaders(
diff --git a/net/url_request/url_fetcher.h b/net/url_request/url_fetcher.h
index f4bddb1..8a037f6 100644
--- a/net/url_request/url_fetcher.h
+++ b/net/url_request/url_fetcher.h
@@ -220,6 +220,10 @@
   // called before the request is started.
   virtual void SetLoadFlags(int load_flags) = 0;
 
+  // Set whether credentials should be included on the request. Must be called
+  // before the request is started.
+  virtual void SetAllowCredentials(bool allow_credentials) = 0;
+
   // Returns the current load flags.
   virtual int GetLoadFlags() const = 0;
 
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index 721d96c..c8ac159f 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -78,6 +78,7 @@
       delegate_(d),
       delegate_task_runner_(base::SequencedTaskRunnerHandle::Get()),
       load_flags_(LOAD_NORMAL),
+      allow_credentials_(base::nullopt),
       response_code_(URLFetcher::RESPONSE_CODE_INVALID),
       url_request_data_key_(NULL),
       was_fetched_via_proxy_(false),
@@ -214,6 +215,10 @@
   load_flags_ = load_flags;
 }
 
+void URLFetcherCore::SetAllowCredentials(bool allow_credentials) {
+  allow_credentials_ = base::make_optional<bool>(allow_credentials);
+}
+
 int URLFetcherCore::GetLoadFlags() const {
   return load_flags_;
 }
@@ -563,6 +568,9 @@
     request_->set_upload(std::move(chunked_stream_));
 
   request_->SetLoadFlags(flags);
+  if (allow_credentials_) {
+    request_->set_allow_credentials(allow_credentials_.value());
+  }
   request_->SetReferrer(referrer_);
   request_->set_referrer_policy(referrer_policy_);
   request_->set_site_for_cookies(initiator_.has_value() &&
diff --git a/net/url_request/url_fetcher_core.h b/net/url_request/url_fetcher_core.h
index 3e261e04..89d9fa20 100644
--- a/net/url_request/url_fetcher_core.h
+++ b/net/url_request/url_fetcher_core.h
@@ -86,6 +86,7 @@
   // one or more of the LOAD_* flags defined in net/base/load_flags.h.
   void SetLoadFlags(int load_flags);
   int GetLoadFlags() const;
+  void SetAllowCredentials(bool allow_credentials);
   void SetReferrer(const std::string& referrer);
   void SetReferrerPolicy(URLRequest::ReferrerPolicy referrer_policy);
   void SetExtraRequestHeaders(const std::string& extra_request_headers);
@@ -246,6 +247,8 @@
   scoped_refptr<base::TaskRunner> upload_file_task_runner_;
   std::unique_ptr<URLRequest> request_;  // The actual request this wraps
   int load_flags_;                   // Flags for the load operation
+  // Whether credentials are sent along with the request.
+  base::Optional<bool> allow_credentials_;
   int response_code_;                // HTTP status code for the request
   scoped_refptr<IOBuffer> buffer_;
                                      // Read buffer
diff --git a/net/url_request/url_fetcher_impl.cc b/net/url_request/url_fetcher_impl.cc
index aefd9969..5ffd221 100644
--- a/net/url_request/url_fetcher_impl.cc
+++ b/net/url_request/url_fetcher_impl.cc
@@ -76,6 +76,10 @@
   core_->SetLoadFlags(load_flags);
 }
 
+void URLFetcherImpl::SetAllowCredentials(bool allow_credentials) {
+  core_->SetAllowCredentials(allow_credentials);
+}
+
 int URLFetcherImpl::GetLoadFlags() const {
   return core_->GetLoadFlags();
 }
diff --git a/net/url_request/url_fetcher_impl.h b/net/url_request/url_fetcher_impl.h
index d0f76ad..a420486 100644
--- a/net/url_request/url_fetcher_impl.h
+++ b/net/url_request/url_fetcher_impl.h
@@ -56,6 +56,7 @@
   void AppendChunkToUpload(const std::string& data,
                            bool is_last_chunk) override;
   void SetLoadFlags(int load_flags) override;
+  void SetAllowCredentials(bool allow_credentials) override;
   int GetLoadFlags() const override;
   void SetReferrer(const std::string& referrer) override;
   void SetReferrerPolicy(URLRequest::ReferrerPolicy referrer_policy) override;
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index f1ec2c50..bfd26271 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -509,6 +509,16 @@
   delegate_ = delegate;
 }
 
+void URLRequest::set_allow_credentials(bool allow_credentials) {
+  if (allow_credentials) {
+    load_flags_ &= ~(LOAD_DO_NOT_SAVE_COOKIES | LOAD_DO_NOT_SEND_COOKIES |
+                     LOAD_DO_NOT_SEND_AUTH_DATA);
+  } else {
+    load_flags_ |= (LOAD_DO_NOT_SAVE_COOKIES | LOAD_DO_NOT_SEND_COOKIES |
+                    LOAD_DO_NOT_SEND_AUTH_DATA);
+  }
+}
+
 void URLRequest::Start() {
   DCHECK(delegate_);
 
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 8551e92..b3c59f6a 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -362,6 +362,16 @@
   // must not yet have a Delegate set.
   void set_delegate(Delegate* delegate);
 
+  // Sets whether credentials are allowed.
+  // If credentials are allowed, the request will send and save HTTP
+  // cookies, as well as authentication to the origin server. If not,
+  // they will not be sent, however proxy-level authentication will
+  // still occur.
+  // Setting this to false is equivalent to setting the
+  // LOAD_DO_NOT_SAVE_COOKIES, LOAD_DO_NOT_SEND_COOKIES, and
+  // LOAD_DO_NOT_SEND_AUTH_DATA flags. See https://crbug.com/799935.
+  void set_allow_credentials(bool allow_credentials);
+
   // Sets the upload data.
   void set_upload(std::unique_ptr<UploadDataStream> upload);
 
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index fad59f1..98949f1 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -69,17 +69,21 @@
 }  // namespace
 
 CORSURLLoader::CORSURLLoader(
+    mojom::URLLoaderRequest loader_request,
     int32_t routing_id,
     int32_t request_id,
     uint32_t options,
+    DeleteCallback delete_callback,
     const ResourceRequest& resource_request,
     mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
     mojom::URLLoaderFactory* network_loader_factory,
     const base::RepeatingCallback<void(int)>& request_finalizer)
-    : routing_id_(routing_id),
+    : binding_(this, std::move(loader_request)),
+      routing_id_(routing_id),
       request_id_(request_id),
       options_(options),
+      delete_callback_(std::move(delete_callback)),
       network_loader_factory_(network_loader_factory),
       network_client_binding_(this),
       request_(resource_request),
@@ -88,14 +92,18 @@
       request_finalizer_(request_finalizer),
       traffic_annotation_(traffic_annotation),
       weak_factory_(this) {
+  binding_.set_connection_error_handler(base::BindOnce(
+      &CORSURLLoader::OnConnectionError, base::Unretained(this)));
   DCHECK(network_loader_factory_);
-  DCHECK(resource_request.request_initiator);
+}
 
+CORSURLLoader::~CORSURLLoader() = default;
+
+void CORSURLLoader::Start() {
   if (fetch_cors_flag_ &&
       request_.fetch_request_mode == mojom::FetchRequestMode::kSameOrigin) {
-    forwarding_client_->OnComplete(URLLoaderCompletionStatus(
+    HandleComplete(URLLoaderCompletionStatus(
         CORSErrorStatus(mojom::CORSError::kDisallowedByMode)));
-    forwarding_client_.reset();
     return;
   }
 
@@ -109,12 +117,9 @@
       request_.url = request_.url.ReplaceComponents(replacements);
     }
   }
-
   StartRequest();
 }
 
-CORSURLLoader::~CORSURLLoader() {}
-
 void CORSURLLoader::FollowRedirect(
     const base::Optional<std::vector<std::string>>&
         to_be_removed_request_headers,
@@ -123,13 +128,15 @@
   DCHECK(!modified_request_headers.has_value()) << "Redirect with modified "
                                                    "headers was not supported "
                                                    "yet. crbug.com/845683";
-  DCHECK(network_loader_);
-  DCHECK(is_waiting_follow_redirect_call_);
+  if (!network_loader_ || !is_waiting_follow_redirect_call_) {
+    HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
+    return;
+  }
   is_waiting_follow_redirect_call_ = false;
 
-  // When the redirect mode is not "follow", the client is not expected to
+  // When the redirect mode is "error", the client is not expected to
   // call this function. Let's abort the request.
-  if (request_.fetch_redirect_mode != mojom::FetchRedirectMode::kFollow) {
+  if (request_.fetch_redirect_mode == mojom::FetchRedirectMode::kError) {
     HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
     return;
   }
@@ -144,16 +151,19 @@
   // We cannot use FollowRedirect for a request with preflight (i.e., when both
   // |fetch_cors_flag_| and |NeedsPreflight(request_)| are true).
   //
-  // Additionally, when |original_fetch_cors_flag| is false and
+  // Additionally, when |original_fetch_cors_flag| is false,
   // |fetch_cors_flag_| is true and |NeedsPreflight(request)| is false, the net/
   // implementation won't attach an "origin" header on redirect, as the original
   // request didn't have one. In such a case we need to re-issue a request
   // manually in order to attach the correct origin header.
+  // For "no-cors" requests we rely on redirect logic in net/ (specifically
+  // in net/url_request/redirect_util.cc).
   if ((original_fetch_cors_flag && !NeedsPreflight(request_)) ||
       !fetch_cors_flag_) {
     network_loader_->FollowRedirect(base::nullopt, base::nullopt);
     return;
   }
+  DCHECK_NE(request_.fetch_request_mode, mojom::FetchRequestMode::kNoCORS);
 
   if (request_finalizer_)
     request_finalizer_.Run(request_id_);
@@ -343,18 +353,20 @@
   // |httpRequest|’s header list.
   if (fetch_cors_flag_ ||
       (request_.method != "GET" && request_.method != "HEAD")) {
-    request_.headers.SetHeader(
-        net::HttpRequestHeaders::kOrigin,
-        (tainted_ ? url::Origin() : *request_.request_initiator).Serialize());
+    url::Origin empty_origin;
+    const url::Origin& origin = tainted_ || !request_.request_initiator
+                                    ? empty_origin
+                                    : *request_.request_initiator;
+    request_.headers.SetHeader(net::HttpRequestHeaders::kOrigin,
+                               origin.Serialize());
   }
 
   if (request_.fetch_request_mode == mojom::FetchRequestMode::kSameOrigin) {
     if (!request_.request_initiator ||
         !request_.request_initiator->IsSameOriginWith(
             url::Origin::Create(request_.url))) {
-      forwarding_client_->OnComplete(URLLoaderCompletionStatus(
+      HandleComplete(URLLoaderCompletionStatus(
           CORSErrorStatus(mojom::CORSError::kDisallowedByMode)));
-      forwarding_client_.reset();
       return;
     }
   }
@@ -383,10 +395,8 @@
     int error_code,
     base::Optional<CORSErrorStatus> status) {
   if (error_code != net::OK) {
-    forwarding_client_->OnComplete(status
-                                       ? URLLoaderCompletionStatus(*status)
-                                       : URLLoaderCompletionStatus(error_code));
-    forwarding_client_.reset();
+    HandleComplete(status ? URLLoaderCompletionStatus(*status)
+                          : URLLoaderCompletionStatus(error_code));
     return;
   }
 
@@ -396,21 +406,12 @@
   // Binding |this| as an unretained pointer is safe because
   // |network_client_binding_| shares this object's lifetime.
   network_client_binding_.set_connection_error_handler(base::BindOnce(
-      &CORSURLLoader::OnUpstreamConnectionError, base::Unretained(this)));
+      &CORSURLLoader::OnConnectionError, base::Unretained(this)));
   network_loader_factory_->CreateLoaderAndStart(
       mojo::MakeRequest(&network_loader_), routing_id_, request_id_, options_,
       request_, std::move(network_client), traffic_annotation_);
 }
 
-void CORSURLLoader::OnUpstreamConnectionError() {
-  // |network_client_binding_| has experienced a connection error and will no
-  // longer call any of the mojom::URLLoaderClient methods above. The client
-  // pipe to the downstream client is closed to inform it of this failure. The
-  // client should respond by closing its mojom::URLLoader pipe which will cause
-  // this object to be destroyed.
-  forwarding_client_.reset();
-}
-
 void CORSURLLoader::HandleComplete(const URLLoaderCompletionStatus& status) {
   forwarding_client_->OnComplete(status);
 
@@ -419,6 +420,13 @@
 
   forwarding_client_.reset();
   network_loader_.reset();
+
+  std::move(delete_callback_).Run(this);
+  // |this| is deleted here.
+}
+
+void CORSURLLoader::OnConnectionError() {
+  HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
 }
 
 }  // namespace cors
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h
index dfd5d92e..835cec5 100644
--- a/services/network/cors/cors_url_loader.h
+++ b/services/network/cors/cors_url_loader.h
@@ -28,13 +28,17 @@
     : public mojom::URLLoader,
       public mojom::URLLoaderClient {
  public:
+  using DeleteCallback = base::OnceCallback<void(mojom::URLLoader* loader)>;
+
   // Assumes network_loader_factory outlives this loader.
   // TODO(yhirano): Remove |request_finalizer| when the network service is
   // fully enabled.
   CORSURLLoader(
+      mojom::URLLoaderRequest loader_request,
       int32_t routing_id,
       int32_t request_id,
       uint32_t options,
+      DeleteCallback delete_callback,
       const ResourceRequest& resource_request,
       mojom::URLLoaderClientPtr client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
@@ -43,6 +47,10 @@
 
   ~CORSURLLoader() override;
 
+  // Starts processing the request. This is expected to be called right after
+  // the constructor.
+  void Start();
+
   // mojom::URLLoader overrides:
   void FollowRedirect(const base::Optional<std::vector<std::string>>&
                           to_be_removed_request_headers,
@@ -79,11 +87,17 @@
   // Handles OnComplete() callback.
   void HandleComplete(const URLLoaderCompletionStatus& status);
 
+  void OnConnectionError();
+
+  mojo::Binding<mojom::URLLoader> binding_;
+
   // We need to save these for redirect.
   const int32_t routing_id_;
   const int32_t request_id_;
   const uint32_t options_;
 
+  DeleteCallback delete_callback_;
+
   // This raw URLLoaderFactory pointer is shared with the CORSURLLoaderFactory
   // that created and owns this object.
   mojom::URLLoaderFactory* network_loader_factory_;
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index c7c399f6..e0b71b9 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -4,25 +4,60 @@
 
 #include "services/network/cors/cors_url_loader_factory.h"
 
+#include "net/base/load_flags.h"
 #include "services/network/cors/cors_url_loader.h"
+#include "services/network/network_context.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/fetch_api.mojom.h"
+#include "services/network/resource_scheduler_client.h"
+#include "services/network/url_loader_factory.h"
 
 namespace network {
 
 namespace cors {
 
 CORSURLLoaderFactory::CORSURLLoaderFactory(
-    std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory)
-    : network_loader_factory_(std::move(network_loader_factory)) {}
+    NetworkContext* context,
+    mojom::URLLoaderFactoryParamsPtr params,
+    scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
+    mojom::URLLoaderFactoryRequest request)
+    : context_(context),
+      disable_web_security_(params && params->disable_web_security),
+      network_loader_factory_(std::make_unique<network::URLLoaderFactory>(
+          context,
+          std::move(params),
+          std::move(resource_scheduler_client),
+          this)) {
+  DCHECK(context_);
+  bindings_.AddBinding(this, std::move(request));
+  bindings_.set_connection_error_handler(base::BindRepeating(
+      &CORSURLLoaderFactory::DeleteIfNeeded, base::Unretained(this)));
+}
 
 CORSURLLoaderFactory::CORSURLLoaderFactory(
+    bool disable_web_security,
     std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory,
     const base::RepeatingCallback<void(int)>& preflight_finalizer)
-    : network_loader_factory_(std::move(network_loader_factory)),
+    : disable_web_security_(disable_web_security),
+      network_loader_factory_(std::move(network_loader_factory)),
       preflight_finalizer_(preflight_finalizer) {}
 
 CORSURLLoaderFactory::~CORSURLLoaderFactory() = default;
 
+void CORSURLLoaderFactory::OnLoaderCreated(
+    std::unique_ptr<mojom::URLLoader> loader) {
+  loaders_.insert(std::move(loader));
+}
+
+void CORSURLLoaderFactory::DestroyURLLoader(mojom::URLLoader* loader) {
+  auto it = loaders_.find(loader);
+  DCHECK(it != loaders_.end());
+  loaders_.erase(it);
+
+  DeleteIfNeeded();
+}
+
 void CORSURLLoaderFactory::CreateLoaderAndStart(
     mojom::URLLoaderRequest request,
     int32_t routing_id,
@@ -31,13 +66,17 @@
     const ResourceRequest& resource_request,
     mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  if (base::FeatureList::IsEnabled(features::kOutOfBlinkCORS)) {
-    loader_bindings_.AddBinding(
-        std::make_unique<CORSURLLoader>(
-            routing_id, request_id, options, resource_request,
-            std::move(client), traffic_annotation,
-            network_loader_factory_.get(), preflight_finalizer_),
-        std::move(request));
+  if (base::FeatureList::IsEnabled(features::kOutOfBlinkCORS) &&
+      !disable_web_security_) {
+    auto loader = std::make_unique<CORSURLLoader>(
+        std::move(request), routing_id, request_id, options,
+        base::BindOnce(&CORSURLLoaderFactory::DestroyURLLoader,
+                       base::Unretained(this)),
+        resource_request, std::move(client), traffic_annotation,
+        network_loader_factory_.get(), preflight_finalizer_);
+    auto* raw_loader = loader.get();
+    OnLoaderCreated(std::move(loader));
+    raw_loader->Start();
   } else {
     network_loader_factory_->CreateLoaderAndStart(
         std::move(request), routing_id, request_id, options, resource_request,
@@ -50,6 +89,13 @@
   bindings_.AddBinding(this, std::move(request));
 }
 
+void CORSURLLoaderFactory::DeleteIfNeeded() {
+  if (!context_)
+    return;
+  if (bindings_.empty() && loaders_.empty())
+    context_->DestroyURLLoaderFactory(this);
+}
+
 }  // namespace cors
 
 }  // namespace network
diff --git a/services/network/cors/cors_url_loader_factory.h b/services/network/cors/cors_url_loader_factory.h
index 7fa3846..cd25335 100644
--- a/services/network/cors/cors_url_loader_factory.h
+++ b/services/network/cors/cors_url_loader_factory.h
@@ -8,13 +8,18 @@
 #include <memory>
 
 #include "base/callback_forward.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 namespace network {
 
+class NetworkContext;
+class ResourceSchedulerClient;
+class URLLoader;
 struct ResourceRequest;
 
 namespace cors {
@@ -26,15 +31,23 @@
 class COMPONENT_EXPORT(NETWORK_SERVICE) CORSURLLoaderFactory final
     : public mojom::URLLoaderFactory {
  public:
-  explicit CORSURLLoaderFactory(
-      std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory);
-  // TODO(yhirano): Remove |preflight_finalizer| when the network service is
-  // fully enabled.
+  // Used by network::NetworkContext.
   CORSURLLoaderFactory(
+      NetworkContext* context,
+      mojom::URLLoaderFactoryParamsPtr params,
+      scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
+      mojom::URLLoaderFactoryRequest request);
+  // Used by content::ResourceMessageFilter.
+  // TODO(yhirano): Remove this once when the network service is fully enabled.
+  CORSURLLoaderFactory(
+      bool disable_web_security,
       std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory,
       const base::RepeatingCallback<void(int)>& preflight_finalizer);
   ~CORSURLLoaderFactory() override;
 
+  void OnLoaderCreated(std::unique_ptr<mojom::URLLoader> loader);
+  void DestroyURLLoader(mojom::URLLoader* loader);
+
  private:
   // Implements mojom::URLLoaderFactory.
   void CreateLoaderAndStart(mojom::URLLoaderRequest request,
@@ -47,15 +60,23 @@
                                 traffic_annotation) override;
   void Clone(mojom::URLLoaderFactoryRequest request) override;
 
+  void DeleteIfNeeded();
+
   mojo::BindingSet<mojom::URLLoaderFactory> bindings_;
 
+  // Used when constructed by NetworkContext.
+  // The NetworkContext owns |this|.
+  NetworkContext* const context_ = nullptr;
+  scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
+  std::set<std::unique_ptr<mojom::URLLoader>, base::UniquePtrComparator>
+      loaders_;
+
+  const bool disable_web_security_;
   std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory_;
 
+  // Used when constructed by ResourceMessageFilter.
   base::RepeatingCallback<void(int)> preflight_finalizer_;
 
-  // The factory owns the CORSURLLoader it creates.
-  mojo::StrongBindingSet<mojom::URLLoader> loader_bindings_;
-
   DISALLOW_COPY_AND_ASSIGN(CORSURLLoaderFactory);
 };
 
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index a8dfc41..2c146041 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
+#include "net/base/load_flags.h"
 #include "net/http/http_request_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request.h"
@@ -119,8 +120,8 @@
     std::unique_ptr<TestURLLoaderFactory> factory =
         std::make_unique<TestURLLoaderFactory>();
     test_url_loader_factory_ = factory->GetWeakPtr();
-    cors_url_loader_factory_ =
-        std::make_unique<CORSURLLoaderFactory>(std::move(factory));
+    cors_url_loader_factory_ = std::make_unique<CORSURLLoaderFactory>(
+        false, std::move(factory), base::RepeatingCallback<void(int)>());
   }
 
  protected:
@@ -135,6 +136,9 @@
     ResourceRequest request;
     request.fetch_request_mode = fetch_request_mode;
     request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
+    request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+    request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
+    request.load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
     request.method = net::HttpRequestHeaders::kGetMethod;
     request.url = url;
     request.request_initiator = url::Origin::Create(origin);
@@ -664,6 +668,9 @@
   ResourceRequest original_request;
   original_request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
   original_request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
+  original_request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+  original_request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
+  original_request.load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
   original_request.method = "PATCH";
   original_request.url = url;
   original_request.request_initiator = url::Origin::Create(origin);
@@ -734,6 +741,9 @@
   ResourceRequest request;
   request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
   request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
+  request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+  request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
+  request.load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
   request.method = "POST";
   request.url = url;
   request.request_initiator = url::Origin::Create(origin);
@@ -816,6 +826,9 @@
   ResourceRequest original_request;
   original_request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
   original_request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
+  original_request.load_flags |= net::LOAD_DO_NOT_SAVE_COOKIES;
+  original_request.load_flags |= net::LOAD_DO_NOT_SEND_COOKIES;
+  original_request.load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
   original_request.fetch_redirect_mode = mojom::FetchRedirectMode::kError;
   original_request.method = "GET";
   original_request.url = url;
@@ -838,36 +851,6 @@
   EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
 }
 
-TEST_F(CORSURLLoaderTest, FollowManualRedirect) {
-  const GURL origin("https://example.com");
-  const GURL url("https://example.com/foo.png");
-  const GURL new_url("https://example.com/bar.png");
-
-  ResourceRequest original_request;
-  original_request.fetch_request_mode = mojom::FetchRequestMode::kCORS;
-  original_request.fetch_credentials_mode = mojom::FetchCredentialsMode::kOmit;
-  original_request.fetch_redirect_mode = mojom::FetchRedirectMode::kManual;
-  original_request.method = "GET";
-  original_request.url = url;
-  original_request.request_initiator = url::Origin::Create(origin);
-  CreateLoaderAndStart(original_request);
-
-  NotifyLoaderClientOnReceiveRedirect(CreateRedirectInfo(301, "GET", new_url));
-  RunUntilRedirectReceived();
-  EXPECT_TRUE(client().has_received_redirect());
-  EXPECT_FALSE(client().has_received_response());
-  EXPECT_FALSE(client().has_received_completion());
-
-  ClearHasReceivedRedirect();
-  FollowRedirect();
-  RunUntilComplete();
-
-  EXPECT_FALSE(client().has_received_redirect());
-  EXPECT_FALSE(client().has_received_response());
-  ASSERT_TRUE(client().has_received_completion());
-  EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
-}
-
 }  // namespace
 
 }  // namespace cors
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 6752c0b..2ba3a07 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -64,6 +64,7 @@
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
+#include "services/network/cors/cors_url_loader_factory.h"
 #include "services/network/expect_ct_reporter.h"
 #include "services/network/http_server_properties_pref_delegate.h"
 #include "services/network/ignore_errors_cert_verifier.h"
@@ -82,8 +83,6 @@
 #include "services/network/throttling/network_conditions.h"
 #include "services/network/throttling/throttling_controller.h"
 #include "services/network/throttling/throttling_network_transaction_factory.h"
-#include "services/network/url_loader.h"
-#include "services/network/url_loader_factory.h"
 #include "services/network/url_request_context_builder_mojo.h"
 
 #if !defined(OS_IOS)
@@ -474,7 +473,7 @@
     mojom::URLLoaderFactoryRequest request,
     mojom::URLLoaderFactoryParamsPtr params,
     scoped_refptr<ResourceSchedulerClient> resource_scheduler_client) {
-  url_loader_factories_.emplace(std::make_unique<URLLoaderFactory>(
+  url_loader_factories_.emplace(std::make_unique<cors::CORSURLLoaderFactory>(
       this, std::move(params), std::move(resource_scheduler_client),
       std::move(request)));
 }
@@ -513,7 +512,7 @@
 }
 
 void NetworkContext::DestroyURLLoaderFactory(
-    URLLoaderFactory* url_loader_factory) {
+    mojom::URLLoaderFactory* url_loader_factory) {
   auto it = url_loader_factories_.find(url_loader_factory);
   DCHECK(it != url_loader_factories_.end());
   url_loader_factories_.erase(it);
diff --git a/services/network/network_context.h b/services/network/network_context.h
index c5fc2064..83459ab 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -55,7 +55,6 @@
 class NetworkService;
 class ResourceScheduler;
 class ResourceSchedulerClient;
-class URLLoaderFactory;
 class URLRequestContextBuilderMojo;
 class WebSocketFactory;
 
@@ -208,9 +207,9 @@
   // Disables use of QUIC by the NetworkContext.
   void DisableQuic();
 
-  // Destroys the specified URLLoaderFactory. Called by the URLLoaderFactory
-  // itself when it has no open pipes.
-  void DestroyURLLoaderFactory(URLLoaderFactory* url_loader_factory);
+  // Destroys the specified factory. Called by the factory itself when it has
+  // no open pipes.
+  void DestroyURLLoaderFactory(mojom::URLLoaderFactory* url_loader_factory);
 
  private:
   class ContextNetworkDelegate;
@@ -275,7 +274,7 @@
 
   // This must be below |url_request_context_| so that the URLRequestContext
   // outlives all the URLLoaderFactories and URLLoaders that depend on it.
-  std::set<std::unique_ptr<URLLoaderFactory>, base::UniquePtrComparator>
+  std::set<std::unique_ptr<mojom::URLLoaderFactory>, base::UniquePtrComparator>
       url_loader_factories_;
 
   mojo::StrongBindingSet<mojom::NetLogExporter> net_log_exporter_bindings_;
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 0797c6f6..35d1e55 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -315,6 +315,10 @@
   // extension manifest V3 / assumming that content scripts have a
   // URLLoaderFactory separate from the rest of the renderer).
   string corb_excluded_initiator_scheme;
+
+  // True if web related security (e.g., CORS) should be disabled. This is
+  // mainly used by people testing their sites, via a command line switch.
+  bool disable_web_security = false;
 };
 
 // Represents a distinct context for making network requests, with its own
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index 45fd09f..c7da25a2 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -48,7 +48,7 @@
       public net::URLRequest::Delegate,
       public mojom::AuthChallengeResponder {
  public:
-  using DeleteCallback = base::OnceCallback<void(URLLoader* url_loader)>;
+  using DeleteCallback = base::OnceCallback<void(mojom::URLLoader* loader)>;
 
   // |delete_callback| tells the URLLoader's owner to destroy the URLLoader.
   // The URLLoader must be destroyed before the |url_request_context|.
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
index 8ad0bdc..e61ca93 100644
--- a/services/network/url_loader_factory.cc
+++ b/services/network/url_loader_factory.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "services/network/cors/cors_url_loader_factory.h"
 #include "services/network/network_context.h"
 #include "services/network/network_service.h"
 #include "services/network/network_usage_accumulator.h"
@@ -25,17 +26,14 @@
     NetworkContext* context,
     mojom::URLLoaderFactoryParamsPtr params,
     scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
-    mojom::URLLoaderFactoryRequest request)
+    cors::CORSURLLoaderFactory* cors_url_loader_factory)
     : context_(context),
       params_(std::move(params)),
-      resource_scheduler_client_(std::move(resource_scheduler_client)) {
+      resource_scheduler_client_(std::move(resource_scheduler_client)),
+      cors_url_loader_factory_(cors_url_loader_factory) {
   DCHECK(context);
   DCHECK_NE(mojom::kInvalidProcessId, params_->process_id);
 
-  binding_set_.AddBinding(this, std::move(request));
-  binding_set_.set_connection_error_handler(base::BindRepeating(
-      &URLLoaderFactory::DeleteIfNeeded, base::Unretained(this)));
-
   if (context_->network_service()) {
     context_->network_service()->keepalive_statistics_recorder()->Register(
         params_->process_id);
@@ -122,33 +120,21 @@
     }
   }
 
-  url_loaders_.insert(std::make_unique<URLLoader>(
+  auto loader = std::make_unique<URLLoader>(
       context_->url_request_context(), network_service_client,
-      base::BindOnce(&URLLoaderFactory::DestroyURLLoader,
-                     base::Unretained(this)),
+      base::BindOnce(&cors::CORSURLLoaderFactory::DestroyURLLoader,
+                     base::Unretained(cors_url_loader_factory_)),
       std::move(request), options, url_request, report_raw_headers,
       std::move(client),
       static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
       params_.get(), request_id, resource_scheduler_client_,
       std::move(keepalive_statistics_recorder),
-      std::move(network_usage_accumulator)));
+      std::move(network_usage_accumulator));
+  cors_url_loader_factory_->OnLoaderCreated(std::move(loader));
 }
 
 void URLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest request) {
-  binding_set_.AddBinding(this, std::move(request));
-}
-
-void URLLoaderFactory::DestroyURLLoader(URLLoader* url_loader) {
-  auto it = url_loaders_.find(url_loader);
-  DCHECK(it != url_loaders_.end());
-  url_loaders_.erase(it);
-  DeleteIfNeeded();
-}
-
-void URLLoaderFactory::DeleteIfNeeded() {
-  if (!binding_set_.empty() || !url_loaders_.empty())
-    return;
-  context_->DestroyURLLoaderFactory(this);
+  NOTREACHED();
 }
 
 }  // namespace network
diff --git a/services/network/url_loader_factory.h b/services/network/url_loader_factory.h
index 7817925e..7031e60 100644
--- a/services/network/url_loader_factory.h
+++ b/services/network/url_loader_factory.h
@@ -8,10 +8,8 @@
 #include <memory>
 #include <set>
 
-#include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
@@ -22,6 +20,10 @@
 class ResourceSchedulerClient;
 class URLLoader;
 
+namespace cors {
+class CORSURLLoaderFactory;
+}  // namespace cors
+
 // This class is an implementation of mojom::URLLoaderFactory that
 // creates a mojom::URLLoader.
 // A URLLoaderFactory has a pointer to ResourceSchedulerClient. A
@@ -31,11 +33,10 @@
 // works on each frame.
 // A URLLoaderFactory can be created with null ResourceSchedulerClient, in which
 // case requests constructed by the factory will not be throttled.
-//
-// URLLoaderFactories own all the URLLoaders they were used to create. Once
-// there are no live Mojo pipes to a URLLoaderFactory, and all URLLoaders it was
-// used to created have been destroyed, it will tell the NetworkContext that
-// owns it to destroy it.
+// The CORS related part is implemented in CORSURLLoader[Factory] until
+// kOutOfBlinkCORS and kNetworkService is fully enabled. Note that
+// NetworkContext::CreateURLLoaderFactory returns a CORSURLLoaderFactory,
+// instead of a URLLoaderFactory.
 class URLLoaderFactory : public mojom::URLLoaderFactory {
  public:
   // NOTE: |context| must outlive this instance.
@@ -43,7 +44,7 @@
       NetworkContext* context,
       mojom::URLLoaderFactoryParamsPtr params,
       scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
-      mojom::URLLoaderFactoryRequest request);
+      cors::CORSURLLoaderFactory* cors_url_loader_factory);
 
   ~URLLoaderFactory() override;
 
@@ -58,24 +59,18 @@
                                 traffic_annotation) override;
   void Clone(mojom::URLLoaderFactoryRequest request) override;
 
-  void DestroyURLLoader(URLLoader* url_loader);
-
   static constexpr int kMaxKeepaliveConnections = 256;
   static constexpr int kMaxKeepaliveConnectionsPerProcess = 20;
   static constexpr int kMaxKeepaliveConnectionsPerProcessForFetchAPI = 10;
 
  private:
-  // If |binding_set_| and |url_loaders_| are both empty, tells the
-  // NetworkContext to destroy |this|.
-  void DeleteIfNeeded();
-
-  // The NetworkContext that owns |this|.
+  // The NetworkContext that indirectly owns |this|.
   NetworkContext* const context_;
   mojom::URLLoaderFactoryParamsPtr params_;
   scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
 
-  mojo::BindingSet<mojom::URLLoaderFactory> binding_set_;
-  std::set<std::unique_ptr<URLLoader>, base::UniquePtrComparator> url_loaders_;
+  // |cors_url_loader_factory_| owns this.
+  cors::CORSURLLoaderFactory* cors_url_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(URLLoaderFactory);
 };
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index ebf4495..fb2f7ae1 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -71,7 +71,7 @@
     std::unique_ptr<URLLoader>* url_loader) {
   return base::BindOnce(
       [](base::RunLoop* run_loop, std::unique_ptr<URLLoader>* url_loader,
-         URLLoader* url_loader_ptr) {
+         mojom::URLLoader* url_loader_ptr) {
         DCHECK_EQ(url_loader->get(), url_loader_ptr);
         url_loader->reset();
         run_loop->Quit();
@@ -81,10 +81,10 @@
 
 // Returns a URLLoader::DeleteCallback that does nothing, but calls NOTREACHED.
 // Tests that use a URLLoader that actually tries to delete itself shouldn't use
-// this methods, as URLLoaders don't expect to be alive after theyinvoke their
+// this method, as URLLoaders don't expect to be alive after they invoke their
 // delete callback.
 URLLoader::DeleteCallback NeverInvokedDeleteLoaderCallback() {
-  return base::BindOnce([](URLLoader* /* url_loader*/) { NOTREACHED(); });
+  return base::BindOnce([](mojom::URLLoader* /* loader*/) { NOTREACHED(); });
 }
 
 constexpr char kBodyReadFromNetBeforePausedHistogram[] =
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index dcac99fe..0b12b84 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -41,6 +41,7 @@
 
 # Features that do not have active plans to support or turn on.
 crbug.com/591099 fast/css3-text/css3-text-justify/text-justify-distribute.html [ Skip ]
+crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-out-of-flow-each-line-hanging.html [ Skip ]
 
 # New passes
 crbug.com/774229 editing/pasteboard/copy-paste-white-space.html [ Pass ]
@@ -505,7 +506,6 @@
 crbug.com/714962 fast/borders/border-styles-split.html [ Failure ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
 crbug.com/591099 fast/box-decoration-break/box-decoration-break-rendering.html [ Failure ]
-crbug.com/591099 fast/box-shadow/basic-shadows.html [ Failure ]
 crbug.com/591099 fast/box-shadow/box-shadow.html [ Failure ]
 crbug.com/591099 fast/box-shadow/inset-subpixel.html [ Failure ]
 crbug.com/591099 fast/box-shadow/inset.html [ Failure ]
@@ -543,7 +543,6 @@
 crbug.com/591099 fast/css3-text/css3-text-indent/negative-text-indent-leading-out-of-flow-text-align-left-and-right.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/negative-text-indent-leading-out-of-flow.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-leading-out-of-flow.html [ Failure ]
-crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-out-of-flow-each-line-hanging.html [ Failure ]
 crbug.com/591099 fast/dom/HTMLAreaElement/area-download.html [ Failure ]
 crbug.com/755750 fast/dom/Range/get-bounding-client-rect-empty-and-non-empty.html [ Failure ]
 crbug.com/755750 fast/dom/Range/getBoundingClientRect-linebreak-character.html [ Failure ]
@@ -557,11 +556,8 @@
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Failure Pass ]
-crbug.com/591099 fast/forms/form-hides-table.html [ Failure ]
-crbug.com/591099 fast/forms/select/select-initial-position.html [ Failure ]
 crbug.com/591099 fast/forms/select/select-style.html [ Failure ]
 crbug.com/591099 fast/forms/text-control-intrinsic-widths.html [ Timeout ]
-crbug.com/591099 fast/frames/iframe-with-frameborder.html [ Failure ]
 crbug.com/591099 fast/inline-block/vertical-align-top-and-bottom-2.html [ Failure ]
 crbug.com/591099 fast/inline/absolute-positioned-block-in-centred-block.html [ Failure ]
 crbug.com/714962 fast/inline/continuation-outlines-with-layers-2.html [ Failure ]
@@ -580,7 +576,6 @@
 crbug.com/860415 fast/multicol/out-of-flow/abspos-auto-position-on-line-rtl.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
 crbug.com/591099 fast/overflow/recompute-overflow-of-layout-root-container.html [ Failure ]
-crbug.com/591099 fast/parser/001.html [ Failure ]
 crbug.com/591099 fast/parser/entities-in-html.html [ Failure ]
 crbug.com/591099 fast/parser/entities-in-xhtml.xhtml [ Failure ]
 crbug.com/591099 fast/replaced/table-replaced-element.html [ Failure ]
@@ -826,8 +821,6 @@
 crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass Timeout ]
 crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Timeout ]
-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 ]
 crbug.com/591099 svg/custom/object-sizing-no-width-height.xhtml [ Failure ]
 crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ]
 crbug.com/591099 svg/in-html/sizing/svg-inline.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index ff3e3b3..533bf941 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -26,8 +26,6 @@
 crbug.com/506754 http/tests/serviceworker/resolve-after-window-close.html [ Leak ]
 crbug.com/506754 http/tests/serviceworker/window-close-during-registration.html [ Leak ]
 
-crbug.com/664874 http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html [ Leak ]
-
 crbug.com/672740 http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker-allowed.html [ Leak Pass ]
 crbug.com/672740 http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker.html [ Leak Pass ]
 
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index 5ef9a3f9..0e91a8a 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -401,3 +401,5 @@
 crbug.com/861670 [ Linux Mac ] virtual/gpu/fast/canvas/canvas-blending-image-over-gradient.html [ Slow ] 
 
 crbug.com/864887 [ Mac ] fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Slow ]
+
+crbug.com/865262 [ Mac ] media/controls/text-track-menu-pointer-selection.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 0c6fedc5..0e4c464 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1674,7 +1674,7 @@
 # TODO(toyoshim, tyoshino, kinuko): Make following tests pass.
 # See crbug.com/736308 for more details. Since outofblink-cors is still under
 # development, just marking failed tests here is fine enough for tests under
-# virtual/outofblink-cors.
+# virtual/outofblink-cors and virtual/outofblink-cors-ns.
 # These are entries specific to outofblink-cors. Entries having the same
 # expectations with the base tests (without virtual/outofblink-cors, for
 # example) are not listed here.
@@ -1688,6 +1688,7 @@
 
 # This test crashes on some builders, passes on others, and fails on yet other builders.
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/service-worker-csp-connect.https.html [ Crash Failure Pass ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/service-worker-csp-connect.https.html [ Crash Failure Pass ]
 
 # Timeout tests in dictionary order.
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html [ Timeout ]
@@ -1695,9 +1696,7 @@
 
 # Failing tests in dictionary order.
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-timing.https.html [ Failure ]
-
 crbug.com/736308 virtual/outofblink-cors/http/tests/fetch/chromium/error-messages.html [ Failure ]
-
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-no-credential-prompt.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-unsupported-url.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
@@ -1706,12 +1705,22 @@
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url.html [ Failure ]
-crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html [ Failure ]
-crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-timing.https.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/fetch/chromium/error-messages.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-no-credential-prompt.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-unsupported-url.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-removal.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url.html [ Failure ]
+
 # ====== Out of Blink CORS related tests END ======
 
 crbug.com/771118 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
 crbug.com/771118 virtual/outofblink-cors/external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
+crbug.com/771118 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
 
 crbug.com/492664 [ Linux ] external/wpt/css/css-writing-modes/box-offsets-rel-pos-vlr-005.xht [ Failure ]
 crbug.com/492664 [ Linux ] external/wpt/css/css-writing-modes/box-offsets-rel-pos-vrl-004.xht [ Failure ]
@@ -1790,6 +1799,7 @@
 crbug.com/518883 crbug.com/390452 http/tests/security/isolatedWorld/media-query-wrapper-leaks.html [ Failure Pass Timeout ]
 crbug.com/518987 http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ]
 crbug.com/518987 virtual/outofblink-cors/http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ]
+crbug.com/518987 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Pass Timeout ]
 
 # These performance-sensitive user-timing tests are flaky in debug on all platforms, and flaky on all configurations of windows.
 # See: crbug.com/567965, crbug.com/518992, and crbug.com/518993
@@ -2639,6 +2649,7 @@
 crbug.com/832071 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 crbug.com/832071 virtual/outofblink-cors/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
+crbug.com/832071 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 
 # failures in external/wpt/css/css-animations/ and web-animations/ from Mozilla tests
 crbug.com/849859 external/wpt/css/css-animations/CSSAnimation-pausing.tentative.html [ Failure ]
@@ -2646,6 +2657,10 @@
 crbug.com/849859 external/wpt/web-animations/timing-model/animations/pausing-an-animation.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html [ Failure ]
+crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/inside-service-worker.https.html [ Timeout ]
+crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Timeout ]
+crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html [ Timeout ]
 crbug.com/626703 external/wpt/editing/manual/insertlinebreak-manual.html [ Skip ]
 crbug.com/626703 external/wpt/html/editing/dnd/canvas/cross-domain/001-manual.xhtml [ Skip ]
 crbug.com/626703 external/wpt/html/editing/dnd/images/cross-domain/001-manual.xhtml [ Skip ]
@@ -2685,8 +2700,10 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-column-row-gap-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-column-row-gap-002.html [ Failure ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/cross-origin-resource-policy/fetch.any.html [ Timeout ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/fetch/cross-origin-resource-policy/fetch.any.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/cross-origin-resource-policy/fetch.any.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Timeout ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Timeout ]
 crbug.com/626703 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Timeout ]
 crbug.com/626703 external/wpt/push-api/idlharness.https.any.serviceworker.html [ Skip ]
 crbug.com/626703 [ Win7 ] external/wpt/preload/link-header-preload.html [ Timeout ]
@@ -2715,13 +2732,16 @@
 crbug.com/626703 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-transforms/transform-box/view-box-mutation.html [ Failure ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ Skip ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ Skip ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 [ Mac10.12 ] virtual/video-surface-layer/external/wpt/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/domxpath/xml_xpath_runner.html [ Timeout ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-polygon-024.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-ellipse-048.html [ Failure ]
@@ -2825,12 +2845,15 @@
 crbug.com/626703 [ Mac10.12 ] external/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html [ Skip ]
 crbug.com/626703 [ Mac10.12 ] external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Skip ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
 crbug.com/626703 [ Linux Mac10.13 ] external/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-fonts/font-feature-settings-descriptor-01.html [ Failure ]
 crbug.com/626703 [ Linux Win10 ] external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Timeout ]
 crbug.com/626703 [ Linux Win10 ] virtual/outofblink-cors/external/wpt/fetch/api/redirect/redirect-count.any.html [ Timeout ]
 crbug.com/626703 [ Linux Win10 ] virtual/outofblink-cors/external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Timeout ]
+crbug.com/626703 [ Linux Win10 ] virtual/outofblink-cors-ns/external/wpt/fetch/api/redirect/redirect-count.any.html [ Timeout ]
+crbug.com/626703 [ Linux Win10 ] virtual/outofblink-cors-ns/external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Timeout ]
 crbug.com/626703 [ Linux Win10 ] external/wpt/fetch/api/redirect/redirect-count.any.html [ Timeout ]
 
 # Grouped frame-policy gunk (flaky copypasta).
@@ -2846,6 +2869,7 @@
 crbug.com/626703 external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ Skip ]
 crbug.com/626703 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ Skip ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ Skip ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-003.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-contain/counter-scoping-002.html [ Failure ]
@@ -3199,6 +3223,7 @@
 crbug.com/626703 external/wpt/screen-orientation/onchange-event-subframe.html [ Timeout ]
 crbug.com/648295 external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/648295 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
 crbug.com/626703 external/wpt/speech-api/SpeechSynthesis-speak-twice.html [ Timeout ]
 crbug.com/626703 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ]
@@ -3587,14 +3612,17 @@
 crbug.com/691944 external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 crbug.com/691944 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 crbug.com/691944 virtual/outofblink-cors/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
+crbug.com/691944 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 
 # These tests (erroneously) see a platform-specific User-Agent header
 crbug.com/595993 external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 virtual/outofblink-cors/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
+crbug.com/595993 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
 crbug.com/595993 external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/595993 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 crbug.com/595993 virtual/outofblink-cors/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
+crbug.com/595993 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ]
 
 crbug.com/619427 [ Mac Linux ] fast/overflow/overflow-height-float-not-removed-crash3.html [ Pass Failure ]
 
@@ -3730,8 +3758,10 @@
 # Importing 'fetch' tests from WPT.
 crbug.com/705490 external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
 crbug.com/705490 virtual/outofblink-cors/external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
+crbug.com/705490 virtual/outofblink-cors-ns/external/wpt/fetch/api/basic/error-after-response.html [ Timeout Pass ]
 crbug.com/820334 external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
 crbug.com/820334 virtual/outofblink-cors/external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
+crbug.com/820334 virtual/outofblink-cors-ns/external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
 
 crbug.com/765116 external/wpt/xhr/responsexml-document-properties.htm [ Failure ]
 
@@ -3768,6 +3798,7 @@
 crbug.com/831509 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/skip-waiting-installed.https.html [ Failure Pass ]
 crbug.com/831509 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/skip-waiting-installed.https.html [ Failure Pass ]
 crbug.com/831509 virtual/outofblink-cors/external/wpt/service-workers/service-worker/skip-waiting-installed.https.html [ Failure Pass ]
+crbug.com/831509 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/skip-waiting-installed.https.html [ Failure Pass ]
 
 # Sheriff failures 2017-02-21
 crbug.com/73609 http/tests/media/video-play-stall.html [ Pass Timeout ]
@@ -3915,6 +3946,7 @@
 crbug.com/757165 [ Win ] external/wpt/service-workers/service-worker/navigation-redirect.https.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/service-worker-servicification/external/wpt/service-workers/service-worker/navigation-redirect.https.html [ Skip ]
 crbug.com/757165 [ Win ] virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-redirect.https.html [ Skip ]
+crbug.com/757165 [ Win ] virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-redirect.https.html [ Skip ]
 crbug.com/757165 [ Win ] fast/forms/file/recover-file-input-in-unposted-form.html [ Skip ]
 crbug.com/757165 [ Win ] fast/spatial-navigation/snav-aligned-not-aligned.html [ Pass Failure Timeout Crash ]
 crbug.com/757165 [ Win ] fast/spatial-navigation/snav-clipped-overflowed-content.html [ Pass Failure Timeout Crash ]
@@ -4175,6 +4207,7 @@
 
 crbug.com/807838 external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Crash Pass ]
 crbug.com/807838 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Crash Pass ]
+crbug.com/807838 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Crash Pass ]
 crbug.com/862886 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Failure ]
 
 # Sheriff faulures 2017-12-12
@@ -4412,6 +4445,7 @@
 
 crbug.com/840881 external/wpt/service-workers/service-worker/resource-timing.https.html [ Failure ]
 crbug.com/840881 virtual/outofblink-cors/external/wpt/service-workers/service-worker/resource-timing.https.html [ Failure ]
+crbug.com/840881 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/resource-timing.https.html [ Failure ]
 crbug.com/840881 virtual/service-worker-servicification/external/wpt/service-workers/service-worker/resource-timing.https.html [ Failure ]
 
 # Sheriff 2018-04-12
@@ -4608,9 +4642,6 @@
 # Sheriff 2018-7-12
 crbug.com/863067 [ Win10 ] virtual/user-activation-v2/fast/dom/Window/window-focus-self.html [ Failure Pass ]
 
-# crrev/c/1102157 exposed this DCHECK violation is an unwanted behavior.
-crbug.com/863651 fast/forms/search/search-cancel-button-mouseup.html [ Crash Pass ]
-
 # Sheriff 2018-7-13
 crbug.com/863599 [ Linux Debug ] external/wpt/requestidlecallback/callback-iframe.html [ Pass Timeout ]
 
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index a303745..b3a30f1 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -507,6 +507,36 @@
     "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
   },
   {
+    "prefix": "outofblink-cors-ns",
+    "base": "external/wpt/fetch",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
+    "prefix": "outofblink-cors-ns",
+    "base": "external/wpt/http",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
+    "prefix": "outofblink-cors-ns",
+    "base": "external/wpt/referrer-policy",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
+    "prefix": "outofblink-cors-ns",
+    "base": "external/wpt/service-workers",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
+    "prefix": "outofblink-cors-ns",
+    "base": "http/tests/fetch",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
+    "prefix": "outofblink-cors-ns",
+    "base": "http/tests/xmlhttprequest",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
     "prefix": "presentation",
     "base": "receiver",
     "args": ["--force-presentation-receiver-for-testing"]
diff --git a/third_party/WebKit/LayoutTests/css1/box_properties/float_on_text_elements.html b/third_party/WebKit/LayoutTests/css1/box_properties/float_on_text_elements.html
index a2d75eb..5b358a13 100644
--- a/third_party/WebKit/LayoutTests/css1/box_properties/float_on_text_elements.html
+++ b/third_party/WebKit/LayoutTests/css1/box_properties/float_on_text_elements.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+<!DOCTYPE HTML>
 <HTML>
 <HEAD>
 <TITLE>CSS1 Test Suite: 5.5.25 float</TITLE>
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/15381.html b/third_party/WebKit/LayoutTests/editing/execCommand/justify_center_do_not_modify_root_editable.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/editing/execCommand/15381.html
rename to third_party/WebKit/LayoutTests/editing/execCommand/justify_center_do_not_modify_root_editable.html
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index aef8c97..82042fe 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -37217,6 +37217,18 @@
      {}
     ]
    ],
+   "css/css-flexbox/align-items-baseline-overflow-non-visible.html": [
+    [
+     "/css/css-flexbox/align-items-baseline-overflow-non-visible.html",
+     [
+      [
+       "/css/css-flexbox/reference/align-items-baseline-overflow-non-visible-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/align-self-001.html": [
     [
      "/css/css-flexbox/align-self-001.html",
@@ -87593,6 +87605,18 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html": [
+    [
+     "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html",
+     [
+      [
+       "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-single-line-clamp-1.html": [
     [
      "/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-single-line-clamp-1.html",
@@ -113776,6 +113800,11 @@
      {}
     ]
    ],
+   "css/css-flexbox/reference/align-items-baseline-overflow-non-visible-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-flexbox/reference/css-box-justify-content-ref.html": [
     [
      {}
@@ -123496,6 +123525,21 @@
      {}
     ]
    ],
+   "css/css-logical/animation-001-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-logical/animation-002-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-logical/animation-003.tenative-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-logical/cascading-001-ref.html": [
     [
      {}
@@ -138911,6 +138955,11 @@
      {}
     ]
    ],
+   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-single-line-clamp-1-ref.html": [
     [
      {}
@@ -164801,11 +164850,6 @@
      {}
     ]
    ],
-   "secure-contexts/basic-dedicated-worker.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "secure-contexts/basic-popup-and-iframe-tests.https.js": [
     [
      {}
@@ -166101,11 +166145,6 @@
      {}
     ]
    ],
-   "service-workers/service-worker/claim-worker-fetch.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "service-workers/service-worker/clients-get-client-types.https-expected.txt": [
     [
      {}
@@ -169086,7 +169125,7 @@
      {}
     ]
    ],
-   "trusted-types/support/helper.js": [
+   "trusted-types/support/helper.sub.js": [
     [
      {}
     ]
@@ -170466,6 +170505,11 @@
      {}
     ]
    ],
+   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels-expected.wav": [
     [
      {}
@@ -170496,6 +170540,16 @@
      {}
     ]
    ],
+   "webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webaudio/the-audio-api/the-audioparam-interface/automation-rate-testing.js": [
     [
      {}
@@ -170576,6 +170630,11 @@
      {}
     ]
    ],
+   "webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webaudio/the-audio-api/the-convolvernode-interface/.gitkeep": [
     [
      {}
@@ -174211,26 +174270,11 @@
      {}
     ]
    ],
-   "workers/modules/dedicated-worker-import-blob-url.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/modules/dedicated-worker-import-data-url.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "workers/modules/dedicated-worker-import-meta-expected.txt": [
     [
      {}
     ]
    ],
-   "workers/modules/dedicated-worker-import.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "workers/modules/dedicated-worker-options-credentials.html.headers": [
     [
      {}
@@ -174386,36 +174430,6 @@
      {}
     ]
    ],
-   "workers/nested_worker.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/nested_worker_close_from_parent_worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/nested_worker_close_self.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/nested_worker_importScripts.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/nested_worker_sync_xhr.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "workers/nested_worker_terminate_from_document-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "workers/non-automated/application-cache-dedicated.html": [
     [
      {}
@@ -192055,6 +192069,24 @@
      {}
     ]
    ],
+   "css/css-logical/animation-001.html": [
+    [
+     "/css/css-logical/animation-001.html",
+     {}
+    ]
+   ],
+   "css/css-logical/animation-002.html": [
+    [
+     "/css/css-logical/animation-002.html",
+     {}
+    ]
+   ],
+   "css/css-logical/animation-003.tenative.html": [
+    [
+     "/css/css-logical/animation-003.tenative.html",
+     {}
+    ]
+   ],
    "css/css-logical/logical-box-border-color.html": [
     [
      "/css/css-logical/logical-box-border-color.html",
@@ -258193,6 +258225,20 @@
      {}
     ]
    ],
+   "webusb/insecure-context.any.js": [
+    [
+     "/webusb/insecure-context.any.html",
+     {}
+    ],
+    [
+     "/webusb/insecure-context.any.sharedworker.html",
+     {}
+    ],
+    [
+     "/webusb/insecure-context.any.worker.html",
+     {}
+    ]
+   ],
    "webusb/usb-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html": [
     [
      "/webusb/usb-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html",
@@ -278613,7 +278659,7 @@
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html": [
-   "e338e94ea726419db64ed5b98c95b862c394409e",
+   "f6623c80b2b4be3fd9dd0f5dc0a6417652f1b797",
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html.headers": [
@@ -278665,7 +278711,7 @@
    "testharness"
   ],
   "content-security-policy/securitypolicyviolation/support/inside-worker.sub.js": [
-   "f425a7ae6c167bfe9857f08f460897e16bf6ca95",
+   "d94662579190653a3b3e9d076b79d7b0f01f2dc7",
    "support"
   ],
   "content-security-policy/securitypolicyviolation/support/inside-worker.sub.js.headers": [
@@ -300804,6 +300850,10 @@
    "b309758484c1b6ec774f47166f97cfbd9258e687",
    "reftest"
   ],
+  "css/css-flexbox/align-items-baseline-overflow-non-visible.html": [
+   "073637c5319713eff6c9faa00ee8e9f7d36a6322",
+   "reftest"
+  ],
   "css/css-flexbox/align-self-001.html": [
    "74fad615303053096f9af7ec697f4584dee9900e",
    "reftest"
@@ -303408,6 +303458,10 @@
    "5fe3c5719f13ddfbba0177bef43d8216129ca763",
    "support"
   ],
+  "css/css-flexbox/reference/align-items-baseline-overflow-non-visible-ref.html": [
+   "7d8c5555baceb9df9b0d3067bbf027e83fb5ea37",
+   "support"
+  ],
   "css/css-flexbox/reference/css-box-justify-content-ref.html": [
    "98639f2d30602f31d472feb5533288c581cdc8c0",
    "support"
@@ -314460,6 +314514,30 @@
    "f5ec83d4ee5ce80ae40a5fe12269d4c7c6c9d91a",
    "support"
   ],
+  "css/css-logical/animation-001-expected.txt": [
+   "3cec1856ed688a6870ae0141bd3a87bade9a9bfe",
+   "support"
+  ],
+  "css/css-logical/animation-001.html": [
+   "361b8af532357e065f01504b9553d5f70cee38ae",
+   "testharness"
+  ],
+  "css/css-logical/animation-002-expected.txt": [
+   "3eac3e48512ce7b6df7e514c45c2dd9d6d3eb3f7",
+   "support"
+  ],
+  "css/css-logical/animation-002.html": [
+   "205a6330ecf0bf69dc3fca0b4f4afa9850e3a782",
+   "testharness"
+  ],
+  "css/css-logical/animation-003.tenative-expected.txt": [
+   "ff44f2aadd8f274135c40ffc70a94b71df022718",
+   "support"
+  ],
+  "css/css-logical/animation-003.tenative.html": [
+   "bdb7e952eb7fecf402f64129a00b511d89470195",
+   "testharness"
+  ],
   "css/css-logical/cascading-001-ref.html": [
    "b95cd62ce3592f653aaa54de0dbc27e16618064b",
    "support"
@@ -317605,11 +317683,11 @@
    "reftest"
   ],
   "css/css-pseudo/first-letter-opacity-float-001-ref.html": [
-   "df71597f8e4bbac13d32504c1ac38f585739b3c7",
+   "0062e047958a7a89a90187061c3d9e407207c386",
    "support"
   ],
   "css/css-pseudo/first-letter-opacity-float-001.html": [
-   "9ba635e13bc8bc7ce0099183ab9c053539569a67",
+   "bb4ac268aee454d512450ef580b422ac0948aeff",
    "reftest"
   ],
   "css/css-pseudo/first-letter-property-whitelist.html": [
@@ -347028,6 +347106,14 @@
    "c50a2e8a9af659d0c537a0a09bec89f7446d6f39",
    "reftest"
   ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001-ref.html": [
+   "97eab29e766b3897c462a551b3a242bd482516fb",
+   "support"
+  ],
+  "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html": [
+   "84063c7a5ac9b9aef46fcf5e2f3f268ed2dfb099",
+   "reftest"
+  ],
   "css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-single-line-clamp-1-ref.html": [
    "262d5b4e48431a1bd92f396f825e20868054fe08",
    "support"
@@ -365525,7 +365611,7 @@
    "testharness"
   ],
   "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker-expected.txt": [
-   "dca7776baefe8e2c5758475769c3e28f265171bb",
+   "ec7b06e82bb0eb5806b5f73e56914624f99dcdfc",
    "support"
   ],
   "html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success-dedicatedworker.html": [
@@ -365813,7 +365899,7 @@
    "testharness"
   ],
   "html/infrastructure/urls/resolving-urls/query-encoding/utf-8-expected.txt": [
-   "0e78750b5f164f1018249af103ea4db31cda8324",
+   "121fc9fc0d00a38e24b334a092580d9b7e1914cc",
    "support"
   ],
   "html/infrastructure/urls/resolving-urls/query-encoding/utf-8.html": [
@@ -365821,7 +365907,7 @@
    "testharness"
   ],
   "html/infrastructure/urls/resolving-urls/query-encoding/windows-1251-expected.txt": [
-   "a0f2778e95a5c53bd935fcca7a4fa7b482c4dda5",
+   "e6bebe7cca9013fa05ecf346365c216e205e8a58",
    "support"
   ],
   "html/infrastructure/urls/resolving-urls/query-encoding/windows-1251.html": [
@@ -365829,7 +365915,7 @@
    "testharness"
   ],
   "html/infrastructure/urls/resolving-urls/query-encoding/windows-1252-expected.txt": [
-   "a863e9d19fbc6f681c4988dea23122ae8ba93359",
+   "aaff88b7bf1e0594873ddd9ed2eb587f9788625f",
    "support"
   ],
   "html/infrastructure/urls/resolving-urls/query-encoding/windows-1252.html": [
@@ -398453,17 +398539,13 @@
    "support"
   ],
   "secure-contexts/basic-dedicated-worker-expected.txt": [
-   "58c95513a3aa5f96cf7494958c979e9dd36ddf98",
+   "2e890f47252bbb92a2fd3cd2dda696a33854bc85",
    "support"
   ],
   "secure-contexts/basic-dedicated-worker.html": [
    "3e2dc8d37996552fc830ee6931f67091e83aa174",
    "testharness"
   ],
-  "secure-contexts/basic-dedicated-worker.https-expected.txt": [
-   "10263e5a8c3639c74e04bb19f174b62f8357526d",
-   "support"
-  ],
   "secure-contexts/basic-dedicated-worker.https.html": [
    "13ce3f1a8ef03b87cca968fd3710d968f35a2439",
    "testharness"
@@ -399944,10 +400026,6 @@
    "dac61fcadc94d01fa1f46ac65d81c0405d90ecd3",
    "testharness"
   ],
-  "service-workers/service-worker/claim-worker-fetch.https-expected.txt": [
-   "9d5c35657412084e52ae0d8aa9c48937b1d531da",
-   "support"
-  ],
   "service-workers/service-worker/claim-worker-fetch.https.html": [
    "3221144d2d91cb4f2afeac1e7b074ce2450b21ce",
    "testharness"
@@ -405113,27 +405191,27 @@
    "testharness"
   ],
   "trusted-types/DOMParser-requiresTrustedTypes.tentative.html": [
-   "0846d9c9f9c97063915cee559bcf4a3e711e9887",
+   "f9b9110f3620949c26b9ae047730b2def936a812",
    "testharness"
   ],
   "trusted-types/DOMParser.tentative.html": [
-   "a32d31137bcfc113ce1ca9f75c9770d3501364d5",
+   "95e12b63536c98404993ddf9b6b90e248f56db31",
    "testharness"
   ],
   "trusted-types/HTMLBaseElement-href.tentative.html": [
-   "5b387ae813ec359650618081128001955c7024e2",
+   "bdc6593b4490bd0a1b22ef423c7fc95468acd7e5",
    "testharness"
   ],
   "trusted-types/HTMLImageElement-src.tentative.html": [
-   "1ac2d898da5cb684f642250760dce70b0e130489",
+   "69ff5aae0ee5d8d5776450ec09e39cdcb912c374",
    "testharness"
   ],
   "trusted-types/HTMLMediaElement-src.tentative.html": [
-   "dc2d8beec67583a7821d445c0273be1c5754c33d",
+   "c24c19db7ed389820a5f6680597e6e7c76683f7b",
    "testharness"
   ],
   "trusted-types/HTMLSourceElement-src.tentative.html": [
-   "bc816aea73f1d1eaf7fbd7516360430483608fee",
+   "872f3b4930d931d56069adfd97afdb4eef5fb978",
    "testharness"
   ],
   "trusted-types/META.yml": [
@@ -405145,119 +405223,119 @@
    "support"
   ],
   "trusted-types/TrustedHTML.tentative.html": [
-   "1bcbd6d4d990c00449a95fd9c410c199b83b6661",
+   "808ec9c374b847012bc1299aecfb9d87b2e8c19c",
    "testharness"
   ],
   "trusted-types/TrustedScriptURL.tentative.html": [
-   "2a02a26d6c55e38d51abebe59b470d6f5008440c",
+   "2f8d956c0179adc05fd92250fab500fcf21f6bba",
    "testharness"
   ],
   "trusted-types/TrustedURL.tentative.html": [
-   "e6cff885204af25c0233d9c18dd3de5cb82ed51b",
+   "2543ae30982c5d979502278f9edcd88d03090eba",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-HTMLBaseElement-href.tentative.html": [
-   "1a3857314ef43c75bcf398f2429d34adce135edb",
+   "8f09389fb792f0fb24afd34035fa9cf055c05be6",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-HTMLImageElement-src.tentative.html": [
-   "29af914e035e196635be0568d8536f037c179c28",
+   "3f50eeada881f742a15be93140f6d274251290d4",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-HTMLMediaElement-src.tentative.html": [
-   "9bb4f5866cff0c34d4d11a274008f322fa943920",
+   "4302f83ec84a7b505985cb2756ce75bf4150d600",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-HTMLSourceElement-src.tentative.html": [
-   "1a403b7f4d9a0614e3fb7f41b95a0cf1e5fbb3ff",
+   "c3209381cb9dfafb16b2421b7536b225c3efd0a4",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-createContextualFragment.tentative.html": [
-   "aa2e78ed37b9b04378e0cbfc93a510bf428f6f78",
+   "9f2da1fdf1bf19b5bd86fb6526412655c3ccbfe6",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-embed-src.tentative.html": [
-   "1e598f550c120e3f1ae24dd36111da7d8863c7fd",
+   "67f647d655ac8c6716270ae1929f8fdb8919d8ed",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-innerHTML.tentative.html": [
-   "cde544697dbfa750e2f5ca8a1d7499d6c85c407e",
+   "ddbdee0f12a482599ec5913f78a527127a2aeb16",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-insertAdjacentHTML.tentative.html": [
-   "739b7940a27a298ca05005e9549774f9e0c0122f",
+   "3c43309acf17f8f2efe37113c662ef97d07aa0de",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-location-assign.tentative.html": [
-   "c50f889d7e517c42e8a490fcdc9e5e169b910876",
+   "189e70168a06390395863dc3c9d7609c11acf0a0",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-location-href.tentative.html": [
-   "b4da566f7eab26c9156e7976714618c74fd405b0",
+   "8c4f974ef05dac942dcdd811ea92fa6702ba8a40",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-location-replace.tentative.html": [
-   "2089fb7ca09b558d654d5e779a52f5acb61d4be8",
+   "e06b0b7233070f19f0d1b234d1ca8c023b98df1a",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-outerHTML.tentative.html": [
-   "a5301e971af8a918df577a3c00cf5d4be2b1d413",
+   "e45a6ea12e10693fb9c77e28e76e62a0c733d3da",
    "testharness"
   ],
   "trusted-types/block-string-assignment-to-script-src.tentative.html": [
-   "4a92a5485db5e199036f10322a89b713b9b02423",
+   "da38712c6e43d1e6fe5892a5339a45c4bf438c7e",
    "testharness"
   ],
   "trusted-types/createContextualFragment.tentative.html": [
-   "c806e71e06aa143840c7376960a44be6e6de77a8",
+   "e98f5e7fa6feeb5000a6310377ea82041c87e27d",
    "testharness"
   ],
   "trusted-types/document-write.tentative.html": [
-   "4eaf06e1d68d027a858ef6818aeac9b912164cbd",
+   "d4097e6235d0a8ddd28c9cfde4b985fb61e6ace9",
    "testharness"
   ],
   "trusted-types/embed-src.tentative.html": [
-   "402c569b64f260a4e0c4121a0eee76c59ed53737",
+   "0230cba4a277809feaedecd0ac17bb6bd6b99797",
    "testharness"
   ],
   "trusted-types/innerHTML.tentative.html": [
-   "d5797e778311a76860aab5ae1c1212ed6bf281b0",
+   "6c2492b545f0989ba74772ff8e0f3922f6ba70da",
    "testharness"
   ],
   "trusted-types/insertAdjacentHTML.tentative.html": [
-   "67298baa3acbfd88c9d867e60fc46ff8f9e2a2ca",
+   "fd95e2fa76d567311b8875bb7481d6345e5423c2",
    "testharness"
   ],
   "trusted-types/location-assign.tentative.html": [
-   "a13e8e471524a854a729ff6724bf7b818f278719",
+   "685f454d8f28c650b0714d1e35baaa3cfbd0b6c8",
    "testharness"
   ],
   "trusted-types/location-href.tentative.html": [
-   "b6b009db2b50ef1a456762256c598b907cbdce81",
+   "973d7da1fbcbfc5d1b75c5769ae9b53379340bba",
    "testharness"
   ],
   "trusted-types/location-replace.tentative.html": [
-   "a1aa171c4af1bab6e501504a0eb1ee9889e8ca26",
+   "07f2e2b7b6b4a1cbd9824bc9a3e575eeb99a3fe5",
    "testharness"
   ],
   "trusted-types/outerHTML.tentative.html": [
-   "959d23151fe6fa7f049fac11336da8ab9d962d0a",
+   "ad67e6c1be0b93e47b26c54544f3989d28588ece",
    "testharness"
   ],
   "trusted-types/script-src.tentative.html": [
-   "4a125530e91a3834077c658a9c0b550fcce8e626",
+   "bcebab27339a828c230ad518d1d71da3cd4cda98",
    "testharness"
   ],
   "trusted-types/srcDoc-requiresTrustedTypes.tentative.html": [
-   "d6691f250d64db32f34b1204ba769fa771712b02",
+   "7a7be9f8ed0bf2990f434a18169533a3a9df13ca",
    "testharness"
   ],
   "trusted-types/srcDoc.tentative.html": [
-   "1fc457290e2b9bd63acfb7eecd94c2f559ca558e",
+   "c13a940e03f51dacfbed5036be81356ef4fe72e5",
    "testharness"
   ],
-  "trusted-types/support/helper.js": [
-   "6ea027fb1cee52a457e64f9b2b2c8294aa8a9dfc",
+  "trusted-types/support/helper.sub.js": [
+   "6162bad41b15d0ae0be727b5d960bb538d430fe2",
    "support"
   ],
   "uievents/META.yml": [
@@ -407305,7 +407383,7 @@
    "support"
   ],
   "webaudio/resources/audionodeoptions.js": [
-   "d7712311bddd23e171e7e1f024aec0a565b08a13",
+   "7ebfb95e0173d463e44d735250773c258d247be1",
    "support"
   ],
   "webaudio/resources/audioparam-testing.js": [
@@ -407317,7 +407395,7 @@
    "support"
   ],
   "webaudio/resources/audit.js": [
-   "eb55fd24237ac7ea4a69c109202e27d6ccd82f80",
+   "4c1c99952e8fb11586e728ad143c1ecc0e01b834",
    "support"
   ],
   "webaudio/resources/biquad-filters.js": [
@@ -407369,7 +407447,7 @@
    "support"
   ],
   "webaudio/resources/start-stop-exceptions.js": [
-   "70e0f890a721786f8afa4cd032e75ef85b5fc6bb",
+   "4d6ca82caf92855b193ea1974405d452226033d9",
    "support"
   ],
   "webaudio/resources/stereopanner-testing.js": [
@@ -407421,7 +407499,7 @@
    "support"
   ],
   "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html": [
-   "b9edb1bd4139c0a045936942d35ac8c763460f5b",
+   "25cced6f02069a5729f8473290e64efb96a913dd",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-getChannelData.html": [
@@ -407433,19 +407511,23 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html": [
-   "34d9e7ccb333ce23c838126a4e84918321292d33",
+   "a46421e357516c255c7cd77a7605f9163b2e64ae",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/.gitkeep": [
    "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "support"
   ],
+  "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic-expected.txt": [
+   "9b936c4844ee0a4f4a98323d3b04264bd73ba4bf",
+   "support"
+  ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic.html": [
    "79d7953fd8bf9fe307d071ee32f8a41851ae7462",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html": [
-   "07642a64398f3b18017608cde7f90cacb277cc9a",
+   "74d3c0c3b6f209da708547fdead9c50989871174",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-ended.html": [
@@ -407513,7 +407595,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html": [
-   "21ea30d8fa92e908da66e79fd127e8fa0203a4c5",
+   "59c3c16b779b39697f911827e2d0c181b35e6649",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiodestinationnode-interface/.gitkeep": [
@@ -407553,7 +407635,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audionode-interface/audionode.html": [
-   "0da532bb8f2505949062709d618da73441968c4d",
+   "e104fc3e8416ca4f9c94932d8de6d57a47d29b61",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audionode-interface/channel-mode-interp-basic.html": [
@@ -407568,8 +407650,12 @@
    "3a34d654e3f9f150a7efb3e18733ec8c9fc5635e",
    "testharness"
   ],
+  "webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values-expected.txt": [
+   "5452ab80e49545c2f5e8e1cfaa46efb93cb3bca3",
+   "support"
+  ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html": [
-   "db9fce12e15e0a640f13180e245488c6fab911f4",
+   "ee3ccd952752c22404f732248dee4c3cab327c76",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-exponentialRampToValueAtTime.html": [
@@ -407584,6 +407670,10 @@
    "d40bf6c901e81a22d24ffd3d5142be8f2ae61252",
    "testharness"
   ],
+  "webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining-expected.txt": [
+   "61911d2811e000150ba07696bbbfdd9288d20733",
+   "support"
+  ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining.html": [
    "5b008e87cad5952ce8bc4ce5e0501decb51ceaeb",
    "testharness"
@@ -407597,7 +407687,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html": [
-   "297e745cd05bedd8d8069136b08cb583f20b474e",
+   "a1bcf8b0209fb925a882f0ed0ffc33665cee618d",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html": [
@@ -407725,7 +407815,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html": [
-   "99284ab790c09dd7a23a6fa5022e8b08b9e3947d",
+   "70dab3e98745c72b6b9a31872c4d7f49a9f67849",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-disconnected-input.https.html": [
@@ -407801,7 +407891,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html": [
-   "3675c5430229774a8079eae866a355ca0793103b",
+   "c74c95e3b950d1c7b73eae3eb4e4bcb7e053ba66",
    "testharness"
   ],
   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html": [
@@ -407884,6 +407974,10 @@
    "743fd6af6f67958f67f4a63cef432515518edf41",
    "testharness"
   ],
+  "webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic-expected.txt": [
+   "9625fc2b8b042cd2c3deb1de9f33689d12ce4ae2",
+   "support"
+  ],
   "webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic.html": [
    "d60c7c7c6d9236f773199a213bef6b1103e02e2e",
    "testharness"
@@ -407965,7 +408059,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html": [
-   "2effacd5886d0af8c615f294fcd50dc4df8940f3",
+   "890f1d859c037ea3efa939375d2891bcb3dd45e1",
    "testharness"
   ],
   "webaudio/the-audio-api/the-delaynode-interface/delaynode-scheduling.html": [
@@ -407985,7 +408079,7 @@
    "support"
   ],
   "webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html": [
-   "6338104e8199673ff7de6f41d310b79a2ee51f04",
+   "247c663144b5c46ac9d3e65f894e7a91a5d9f246",
    "testharness"
   ],
   "webaudio/the-audio-api/the-dynamicscompressornode-interface/dynamicscompressor-basic.html": [
@@ -408021,11 +408115,11 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html": [
-   "3627d5b4a447a62de6c6a6f10556fa9f9dec1700",
+   "ce706e265d7bb218a3ea546914a801859bdd2a3b",
    "testharness"
   ],
   "webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html": [
-   "176168861bc667b2b05312dbae48f76f7f90d791",
+   "5f0cffb3c5931d96cf060f639762c9dcee59ac77",
    "testharness"
   ],
   "webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-getFrequencyResponse.html": [
@@ -408061,7 +408155,7 @@
    "support"
   ],
   "webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html": [
-   "4264798e9e64d30c72f9f0577a9648efa2d0a50a",
+   "136ab775c271251038743b99dc3a52ea78cf8213",
    "testharness"
   ],
   "webaudio/the-audio-api/the-offlineaudiocontext-interface/current-time-block-size.html": [
@@ -408081,7 +408175,7 @@
    "support"
   ],
   "webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html": [
-   "2b59d21a54b2216c1171a6ba2c7809291955a8af",
+   "365616f2f9f9666504048d991ff324bfd28c0076",
    "testharness"
   ],
   "webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html": [
@@ -408141,7 +408235,7 @@
    "support"
   ],
   "webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html": [
-   "1908ffc477d8c16b81ab371f5b9dbca46cc16a83",
+   "3452e6e613e694a9f4237757b54ac4c7f9e78973",
    "testharness"
   ],
   "webaudio/the-audio-api/the-stereopanner-interface/no-dezippering.html": [
@@ -409645,7 +409739,7 @@
    "testharness"
   ],
   "websockets/Create-on-worker-shutdown.any.worker-expected.txt": [
-   "c815282bb438e6b7cafa6d6d48ae8fb03f5005ce",
+   "e1cf63cbd54a758e353418bb96e0e3c77b0601c1",
    "support"
   ],
   "websockets/Create-protocol-with-space.any.js": [
@@ -410904,6 +410998,10 @@
    "d0370ee58f8199ca632ab40282e4bc4a543c53ce",
    "support"
   ],
+  "webusb/insecure-context.any.js": [
+   "a5ba2d24e4f588f5b85ded64e80134355b787b01",
+   "testharness"
+  ],
   "webusb/resources/fake-devices.js": [
    "2cfce7b35b9441529946c4bcea9427e261808c36",
    "support"
@@ -414401,7 +414499,7 @@
    "testharness"
   ],
   "workers/constructors/Worker/expected-self-properties.worker-expected.txt": [
-   "7fac8e2a2cb29e6e7ede0a62376ba3e10cf54ccc",
+   "cf6d7c6f252640fb8551fe52073738fe46c37ce5",
    "support"
   ],
   "workers/constructors/Worker/expected-self-properties.worker.js": [
@@ -414736,10 +414834,6 @@
    "811bccb876055daee01bc50152c425dc931c0f72",
    "testharness"
   ],
-  "workers/modules/dedicated-worker-import-blob-url.any.worker-expected.txt": [
-   "7297d62a2bf3dcda91bfdc1b80c939fcf96f4f44",
-   "support"
-  ],
   "workers/modules/dedicated-worker-import-csp.html": [
    "e889866185addcccf72828df7e75cec387cffab5",
    "testharness"
@@ -414748,10 +414842,6 @@
    "599db2cf40a1173d66b06c1b53229a654bc4473f",
    "testharness"
   ],
-  "workers/modules/dedicated-worker-import-data-url.any.worker-expected.txt": [
-   "7297d62a2bf3dcda91bfdc1b80c939fcf96f4f44",
-   "support"
-  ],
   "workers/modules/dedicated-worker-import-failure.html": [
    "29932911fcc6804e8d5f77f3d8f2a8adc4cd2fed",
    "testharness"
@@ -414772,10 +414862,6 @@
    "b890d5e557f526ed2d6c43f8e4f413faa93e58ff",
    "testharness"
   ],
-  "workers/modules/dedicated-worker-import.any.worker-expected.txt": [
-   "7297d62a2bf3dcda91bfdc1b80c939fcf96f4f44",
-   "support"
-  ],
   "workers/modules/dedicated-worker-options-credentials.html": [
    "f182ac364e933ce744b18c0ca6e03ae975a883a3",
    "testharness"
@@ -414912,50 +414998,26 @@
    "782f980596535125995d91c678d94fe98169b7da",
    "testharness"
   ],
-  "workers/nested_worker.worker-expected.txt": [
-   "b130299499ad6b5d796f433dda14634d21de7f93",
-   "support"
-  ],
   "workers/nested_worker.worker.js": [
    "4f3e18270ff312e53a8ccb6dacfd7af80e5355e4",
    "testharness"
   ],
-  "workers/nested_worker_close_from_parent_worker-expected.txt": [
-   "e2fe03ce719b850154da9fb33fd81241260fadea",
-   "support"
-  ],
   "workers/nested_worker_close_from_parent_worker.html": [
    "2224e949cc23fd7741d0372d2876c5128c5005df",
    "testharness"
   ],
-  "workers/nested_worker_close_self.worker-expected.txt": [
-   "d80d980c6f55e9b286c8ee1ddfbfedbb513df64e",
-   "support"
-  ],
   "workers/nested_worker_close_self.worker.js": [
    "70714124e09615d7f4756ecca18789e7e981a524",
    "testharness"
   ],
-  "workers/nested_worker_importScripts.worker-expected.txt": [
-   "3a42c56315a45e86f10a9681b7956ac0a9c7faf1",
-   "support"
-  ],
   "workers/nested_worker_importScripts.worker.js": [
    "6409ab5cfc9ffd1db51a1ed1cccac90e8bd1c68e",
    "testharness"
   ],
-  "workers/nested_worker_sync_xhr.worker-expected.txt": [
-   "7dca8999ffad761c24e041716fd03c33ed3182cf",
-   "support"
-  ],
   "workers/nested_worker_sync_xhr.worker.js": [
    "637b556d0e1a0fdbb270df3f2215c100681ccc63",
    "testharness"
   ],
-  "workers/nested_worker_terminate_from_document-expected.txt": [
-   "ec44e040fca88cc848aeeebece6e96ada39f789d",
-   "support"
-  ],
   "workers/nested_worker_terminate_from_document.html": [
    "597512ecf36dc5536dcaf33671cc8b8dd4680f7a",
    "testharness"
@@ -415077,7 +415139,7 @@
    "testharness"
   ],
   "workers/semantics/interface-objects/001.worker-expected.txt": [
-   "29fdb6eed06c5c6afecea03b2c9604e99d5bbeda",
+   "8996679686dc335d6f663b6bde3b891df6ab517c",
    "support"
   ],
   "workers/semantics/interface-objects/001.worker.js": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html
index 2761127..c63206d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html
@@ -4,10 +4,10 @@
 <script src="./support/testharness-helper.sub.js"></script>
 <body></body>
 <script>
-    function waitForViolation(el, t, policy, blocked_origin) {
+    function waitForViolation(el, t, policy, blockedURI) {
       return new Promise(resolve => {
         el.addEventListener('securitypolicyviolation', e => {
-          if (e.originalPolicy == policy && (new URL(e.blockedURI)).origin == blocked_origin)
+          if (e.originalPolicy == policy && e.blockedURI == blockedURI)
             resolve(e);
           else
             t.unreached_func("Unexpected violation event for " + e.blockedURI)();
@@ -21,7 +21,7 @@
       i.src = redirect.url;
 
       // Report-only policy should trigger a violation on the redirected request.
-      waitForViolation(window, t, "img-src https:", (new URL(redirect.target)).origin).then(t.step_func(e => {
+      waitForViolation(window, t, "img-src https:", new URL(redirect.url, window.location).href).then(t.step_func(e => {
         t.done();
       }));
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js
index 6e0d98c95..58bd02f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/securitypolicyviolation/support/inside-worker.sub.js
@@ -40,5 +40,18 @@
     .catch(t.step_func(e => assert_true(e instanceof TypeError)));
 }, "SecurityPolicyViolation event fired on global.");
 
+async_test(t => {
+  var url = "{{location[scheme]}}://{{host}}:{{location[port]}}/common/redirect.py?location={{location[scheme]}}://{{domains[www]}}:{{location[port]}}/content-security-policy/support/ping.js";
+  waitUntilCSPEventForURL(t, url)
+    .then(t.step_func_done(e => {
+      assert_equals(e.blockedURI, url);
+      assert_false(cspEventFiredInDocument);
+    }));
+
+  fetch(url)
+    .then(t.unreached_func("Fetch should not succeed."))
+    .catch(t.step_func(e => assert_true(e instanceof TypeError)));
+}, "SecurityPolicyViolation event fired on global with the correct blockedURI.");
+
 // Worker tests need an explicit `done()`.
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-001-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-001-expected.txt
new file mode 100644
index 0000000..81869ec6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-001-expected.txt
@@ -0,0 +1,27 @@
+This is a testharness.js-based test.
+FAIL Logical properties can be animated using object notation assert_equals: expected "50px" but got "100px"
+FAIL Logical properties can be animated using array notation assert_equals: expected "50px" but got "100px"
+PASS Logical properties are NOT stored as physical properties
+FAIL Logical properties in animations respect the writing-mode assert_equals: expected "50px" but got "100px"
+FAIL Logical properties in animations respect the direction assert_equals: expected "50px" but got "100px"
+PASS Physical properties win over logical properties in object notation
+PASS Physical properties win over logical properties in array notation
+PASS Physical properties with variables win over logical properties
+FAIL Logical shorthands follow the usual prioritization based on number of component longhands assert_equals: expected "300px" but got "0px"
+FAIL Physical longhands win over logical shorthands assert_equals: expected "200px" but got "100px"
+PASS Logical longhands win over physical shorthands
+FAIL Physical shorthands win over logical shorthands assert_equals: expected "200px" but got "100px"
+FAIL Physical shorthands using variables win over logical shorthands assert_equals: expected "200px" but got "100px"
+FAIL Physical properties and logical properties can be mixed assert_equals: expected "250px" but got "300px"
+FAIL Physical shorthands and logical shorthands can be mixed assert_equals: expected "250px" but got "150px"
+PASS Physical properties win over logical properties even when some keyframes only have logical properties
+FAIL Animations update when the writing-mode is changed assert_equals: expected "50px" but got "100px"
+PASS Filling animations update when the writing-mode is changed
+FAIL Animations with implicit from values update when the writing-mode is changed assert_equals: expected "250px" but got "300px"
+FAIL Animations with overlapping physical and logical properties update when the writing-mode is changed assert_equals: expected "50px" but got "100px"
+FAIL Animations update when the writing-mode is changed through a CSS variable assert_equals: expected "50px" but got "100px"
+FAIL Animations update when the direction is changed assert_equals: expected "50px" but got "100px"
+PASS writing-mode is not animatable
+PASS direction is not animatable
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-001.html
new file mode 100644
index 0000000..8135f432
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-001.html
@@ -0,0 +1,323 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Animating CSS logical properties using Web Animations</title>
+<link rel="help" href="https://drafts.csswg.org/css-logical/#box">
+<meta name="assert" content="The specified values of these properties are separate from the specified values of the parallel physical properties, but the flow-relative and physical properties share computed values.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../css-animations/support/testcommon.js"></script>
+<style>
+:root {
+  --200px: 200px;
+  --300px: 300px;
+  --writingMode: horizontal-tb;
+}
+</style>
+
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000);
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '50px');
+}, 'Logical properties can be animated using object notation');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    [{ blockSize: '0px' }, { blockSize: '100px' }],
+    1000
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '50px');
+}, 'Logical properties can be animated using array notation');
+
+test(t => {
+  const anim = addDiv(t).animate({ blockSize: ['0px', '100px'] }, 1000);
+  assert_equals(anim.effect.getKeyframes().length, 2);
+
+  assert_own_property(anim.effect.getKeyframes()[0], 'blockSize');
+  assert_false(anim.effect.getKeyframes()[0].hasOwnProperty('height'));
+
+  assert_own_property(anim.effect.getKeyframes()[1], 'blockSize');
+  assert_false(anim.effect.getKeyframes()[1].hasOwnProperty('height'));
+}, 'Logical properties are NOT stored as physical properties');
+
+test(t => {
+  const div = addDiv(t, { style: 'writing-mode: vertical-rl' });
+  const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000);
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Logical properties in animations respect the writing-mode');
+
+test(t => {
+  const div = addDiv(t, { style: 'direction: rtl' });
+  const anim = div.animate({ marginInlineStart: ['0px', '100px'] }, 1000);
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).marginLeft, '0px');
+  assert_equals(getComputedStyle(div).marginRight, '50px');
+}, 'Logical properties in animations respect the direction');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      blockSize: ['0px', '100px'],
+      height: ['200px', '300px'],
+    },
+    1000
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Physical properties win over logical properties in object notation');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    [
+      { height: '200px', blockSize: '0px' },
+      { height: '300px', blockSize: '100px' },
+    ],
+    1000
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Physical properties win over logical properties in array notation');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      blockSize: ['0px', '100px'],
+      height: ['var(--200px)', 'var(--300px)'],
+    },
+    1000
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Physical properties with variables win over logical properties');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      marginInlineStart: '100px',
+      marginInline: '200px',
+      margin: 'logical 300px',
+    },
+    { duration: 1, easing: 'step-start' }
+  );
+  assert_equals(getComputedStyle(div).marginLeft, '100px');
+  assert_equals(getComputedStyle(div).marginRight, '200px');
+  assert_equals(getComputedStyle(div).marginTop, '300px');
+  assert_equals(getComputedStyle(div).marginBottom, '300px');
+}, 'Logical shorthands follow the usual prioritization based on number of'
+   + ' component longhands');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      marginInline: '100px',
+      marginLeft: '200px',
+    },
+    { duration: 1, easing: 'step-start' }
+  );
+  assert_equals(getComputedStyle(div).marginLeft, '200px');
+  assert_equals(getComputedStyle(div).marginRight, '100px');
+}, 'Physical longhands win over logical shorthands');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      marginInlineStart: '100px',
+      margin: '200px',
+    },
+    { duration: 1, easing: 'step-start' }
+  );
+  assert_equals(getComputedStyle(div).marginLeft, '100px');
+  assert_equals(getComputedStyle(div).marginRight, '200px');
+}, 'Logical longhands win over physical shorthands');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      marginInline: '100px',
+      margin: '200px',
+    },
+    { duration: 1, easing: 'step-start' }
+  );
+  assert_equals(getComputedStyle(div).marginLeft, '200px');
+  assert_equals(getComputedStyle(div).marginRight, '200px');
+}, 'Physical shorthands win over logical shorthands');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    {
+      marginInline: '100px',
+      margin: 'var(--200px)',
+    },
+    { duration: 1, easing: 'step-start' }
+  );
+  assert_equals(getComputedStyle(div).marginLeft, '200px');
+  assert_equals(getComputedStyle(div).marginRight, '200px');
+}, 'Physical shorthands using variables win over logical shorthands');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate([{ blockSize: '200px' }, { height: '300px' }], 1000);
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Physical properties and logical properties can be mixed');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    [{ marginInline: '200px' }, { marginRight: '300px' }],
+    1000
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).marginRight, '250px');
+}, 'Physical shorthands and logical shorthands can be mixed');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    [{ blockSize: '100px', height: '200px' }, { height: '300px' }],
+    1000
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Physical properties win over logical properties even when some keyframes'
+   + ' only have logical properties');
+
+test(t => {
+  const div = addDiv(t, { style: 'width: 0px; height: 0px' });
+  const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000);
+  anim.currentTime = 500;
+
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '50px');
+
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Animations update when the writing-mode is changed');
+
+test(t => {
+  const div = addDiv(t, { style: 'width: 0px; height: 0px' });
+  const anim = div.animate(
+    { blockSize: ['0px', '100px'] },
+    {
+      duration: 1000,
+      fill: 'forwards',
+    }
+  );
+  anim.finish();
+
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '100px');
+
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '100px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Filling animations update when the writing-mode is changed');
+
+test(t => {
+  const div = addDiv(t, { style: 'width: 100px; height: 200px' });
+  const anim = div.animate({ blockSize: '300px' }, 1000);
+  anim.currentTime = 500;
+
+  // Initially we are animating height from 200px -> 300px
+  assert_equals(getComputedStyle(div).width, '100px');
+  assert_equals(getComputedStyle(div).height, '250px');
+
+  // After the change we are animating width from 100px -> 300px
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '200px');
+  assert_equals(getComputedStyle(div).height, '200px');
+}, 'Animations with implicit from values update when the writing-mode'
+   + ' is changed');
+
+test(t => {
+  const div = addDiv(t, { style: 'width: 0px; height: 0px' });
+  const anim = div.animate(
+    [
+      { height: '200px', blockSize: '0px' },
+      { height: '300px', blockSize: '100px' },
+    ],
+    1000
+  );
+  anim.currentTime = 500;
+
+  // Initially writing-mode is horizontal-tb so the 'block-size' values are
+  // clobbered by the 'height' values.
+
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '250px');
+
+  // After updating the writing-mode to vertical-rl the 'block-size' values
+  // should no longer be overridden and should apply to the height.
+
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Animations with overlapping physical and logical properties update'
+   + ' when the writing-mode is changed');
+
+test(t => {
+  const div = addDiv(t, { style: 'width: 0px; height: 0px' });
+  div.style.writingMode = 'var(--writingMode)';
+  const anim = div.animate({ blockSize: ['0px', '100px'] }, 1000);
+  anim.currentTime = 500;
+
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '50px');
+
+  div.style.setProperty('--writingMode', 'vertical-rl');
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Animations update when the writing-mode is changed through a CSS variable');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate({ marginInlineStart: ['0px', '100px'] }, 1000);
+  anim.currentTime = 500;
+
+  assert_equals(getComputedStyle(div).marginLeft, '50px');
+  assert_equals(getComputedStyle(div).marginRight, '0px');
+
+  div.style.direction = 'rtl';
+  assert_equals(getComputedStyle(div).marginLeft, '0px');
+  assert_equals(getComputedStyle(div).marginRight, '50px');
+}, 'Animations update when the direction is changed');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    { writingMode: 'vertical-rl' },
+    { duration: 1, easing: 'step-start' }
+  );
+  assert_equals(getComputedStyle(div).writingMode, 'horizontal-tb');
+  assert_equals(anim.effect.getKeyframes().length, 0);
+}, 'writing-mode is not animatable');
+
+test(t => {
+  const div = addDiv(t);
+  const anim = div.animate(
+    { writingMode: 'rtl' },
+    { duration: 1, easing: 'step-start' }
+  );
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(div).direction, 'ltr');
+  assert_equals(anim.effect.getKeyframes().length, 0);
+}, 'direction is not animatable');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-002-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-002-expected.txt
new file mode 100644
index 0000000..7d4ebc3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-002-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+FAIL Logical properties can be animated assert_equals: expected "50px" but got "100px"
+FAIL Logical properties in animations respect the writing-mode assert_equals: expected "50px" but got "100px"
+FAIL Logical properties in animations respect the direction assert_equals: expected "50px" but got "100px"
+PASS Declaration order is respected within @keyframes declaration blocks
+PASS Logical properties are able to override physical properties in @keyframes declaration blocks
+PASS Declaration order is respected amongst logical properties within @keyframes declaration blocks
+FAIL Physical properties and logical properties can be mixed assert_equals: expected "250px" but got "300px"
+FAIL Declaration order is respected on each keyframe individually assert_equals: expected "250px" but got "200px"
+FAIL Animations update when the writing-mode is changed assert_equals: expected "50px" but got "100px"
+PASS Filling animations update when the writing-mode is changed
+FAIL The number of interpolating properties can be increased when the writing-mode is changed assert_equals: expected "100px" but got "150px"
+FAIL The number of interpolating properties can be decreased when the writing-mode is changed assert_equals: expected "150px" but got "200px"
+FAIL Animations update when the writing-mode is changed through a CSS variable assert_equals: expected "50px" but got "100px"
+FAIL Animations update when the direction is changed assert_equals: expected "50px" but got "100px"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-002.html
new file mode 100644
index 0000000..d4f199d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-002.html
@@ -0,0 +1,213 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Animating CSS logical properties using CSS Animations</title>
+<link rel="help" href="https://drafts.csswg.org/css-logical/#box">
+<meta name="assert" content="The specified values of these properties are separate from the specified values of the parallel physical properties, but the flow-relative and physical properties share computed values.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../css-animations/support/testcommon.js"></script>
+
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 0px } to { block-size: 100px }',
+  });
+  const div = addDiv(t, { style: 'animation: anim 10s -5s paused linear' });
+  assert_equals(getComputedStyle(div).height, '50px');
+}, 'Logical properties can be animated');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 0px } to { block-size: 100px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear; writing-mode: vertical-rl',
+  });
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Logical properties in animations respect the writing-mode');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim':
+      'from { margin-inline-start: 0px } to { margin-inline-start: 100px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear; direction: rtl',
+  });
+  assert_equals(getComputedStyle(div).marginLeft, '0px');
+  assert_equals(getComputedStyle(div).marginRight, '50px');
+}, 'Logical properties in animations respect the direction');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim':
+      'from { block-size: 0px; height: 200px }'
+      + ' to { block-size: 100px; height: 300px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear',
+  });
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Declaration order is respected within @keyframes declaration blocks');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim':
+      'to { margin-top: 200px;'
+        + ' margin-block-start: 100px }'
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s paused step-start',
+  });
+  assert_equals(getComputedStyle(div).marginTop, '100px');
+}, 'Logical properties are able to override physical properties in'
+   + ' @keyframes declaration blocks');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim':
+      'to {'
+      + ' margin-inline: 200px;'
+      + ' margin-inline-start: 0px;'
+      + ' margin-inline-start: 100px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s paused step-start',
+  });
+  assert_equals(getComputedStyle(div).marginLeft, '100px');
+}, 'Declaration order is respected amongst logical properties within'
+   + ' @keyframes declaration blocks');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 200px } to { height: 300px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear',
+  });
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Physical properties and logical properties can be mixed');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim':
+      'from { height: 100px; block-size: 200px }'
+      + ' to { block-size: 100px; height: 300px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear',
+  });
+  assert_equals(getComputedStyle(div).height, '250px');
+}, 'Declaration order is respected on each keyframe individually');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 0px } to { block-size: 100px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear; width: 0px; height: 0px',
+  });
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '50px');
+
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Animations update when the writing-mode is changed');
+
+promise_test(async t => {
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 0px } to { block-size: 100px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -9.9s linear forwards;'
+      + ' width: 0px; height: 0px',
+  });
+  const watcher = new EventWatcher(t, div, [ 'animationend' ]);
+  await watcher.wait_for('animationend');
+
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '100px');
+
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '100px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Filling animations update when the writing-mode is changed');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'to { block-size: 100px; height: 200px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear; width: 0px; height: 0px',
+  });
+  // Initially we are interpolating the height from 0 to 200px
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '100px');
+
+  // But once we change the writing-mode, we will be interpolating *both*
+  // the height (from 0px to 200px) *and* the width (from 0px to 100px).
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '100px');
+}, 'The number of interpolating properties can be increased when the'
+   + ' writing-mode is changed');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'to { width: 300px; block-size: 200px }',
+  });
+  const div = addDiv(t, {
+    style: 'animation: anim 10s -5s paused linear; width: 100px; height: 100px',
+  });
+  // Initially we are interpolating the width (100px -> 300px) and the height
+  // (100px -> 200px).
+  assert_equals(getComputedStyle(div).width, '200px');
+  assert_equals(getComputedStyle(div).height, '150px');
+
+  // Once we change the writing-mode, we will be interpolating *only* the
+  // width (100px -> 200px).
+  div.style.writingMode = 'vertical-rl';
+  assert_equals(getComputedStyle(div).width, '150px');
+  assert_equals(getComputedStyle(div).height, '100px');
+}, 'The number of interpolating properties can be decreased when the'
+   + ' writing-mode is changed');
+
+test(t => {
+  addStyle(t, { ':root': '--writingMode: horizontal-tb' });
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 0px } to { block-size: 100px }',
+  });
+  const div = addDiv(t, {
+    style:
+      'animation: anim 10s -5s paused linear;'
+      + ' width: 0px; height: 0px;'
+      + ' writing-mode: var(--writingMode)'
+  });
+  assert_equals(getComputedStyle(div).width, '0px');
+  assert_equals(getComputedStyle(div).height, '50px');
+
+  div.style.setProperty('--writingMode', 'vertical-rl');
+  assert_equals(getComputedStyle(div).width, '50px');
+  assert_equals(getComputedStyle(div).height, '0px');
+}, 'Animations update when the writing-mode is changed through a CSS variable');
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim':
+      'from { margin-inline-start: 0px } to { margin-inline-start: 100px }',
+  });
+  const div = addDiv(t, { style: 'animation: anim 10s -5s paused linear' });
+  assert_equals(getComputedStyle(div).marginLeft, '50px');
+  assert_equals(getComputedStyle(div).marginRight, '0px');
+
+  div.style.direction = 'rtl';
+  assert_equals(getComputedStyle(div).marginLeft, '0px');
+  assert_equals(getComputedStyle(div).marginRight, '50px');
+}, 'Animations update when the direction is changed');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-003.tenative-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-003.tenative-expected.txt
new file mode 100644
index 0000000..24c710be
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-003.tenative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Logical properties are represented as physical properties in keyframes assert_own_property: expected property "height" missing
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-003.tenative.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-003.tenative.html
new file mode 100644
index 0000000..bcb4e15
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/animation-003.tenative.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Animating CSS logical properties using CSS Animations - Web Animations reflection</title>
+<link rel="help" href="https://drafts.csswg.org/css-logical/#box">
+<meta name="assert" content="The specified values of these properties are separate from the specified values of the parallel physical properties, but the flow-relative and physical properties share computed values.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../css-animations/support/testcommon.js"></script>
+
+<div id="log"></div>
+<script>
+'use strict';
+
+/*
+ * The mapping from CSS Animations to Web Animations has yet to be specified
+ * but, when it is, we expect it to require that logical properties in CSS
+ * keyframes be represented as physical properties in the result returned from
+ * getKeyframes() since this is consistent with the behavior of expanding out
+ * all shorthands in to their consituent longhands in order to resolve
+ * overlapping properties.
+ */
+
+test(t => {
+  addStyle(t, {
+    '@keyframes anim': 'from { block-size: 0px } to { block-size: 100px }',
+  });
+  const div = addDiv(t, { style: 'animation: anim 10s' });
+  const anim = div.getAnimations()[0];
+
+  assert_own_property(anim.effect.getKeyframes()[0], 'height');
+  assert_false(anim.effect.getKeyframes()[0].hasOwnProperty('blockSize'));
+
+  assert_own_property(anim.effect.getKeyframes()[1], 'height');
+  assert_false(anim.effect.getKeyframes()[1].hasOwnProperty('blockSize'));
+}, 'Logical properties are represented as physical properties in keyframes');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001-ref.html
new file mode 100644
index 0000000..b921f35
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001-ref.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/publicdomain/zero/1.0
+-->
+<html>
+<head>
+  <title>Reference: Testing safe overflow-position for align-content, justify-content, and align-items in flex containers</title>
+  <link rel="author" title="Mihir Iyer" href="mailto:miyer@mozilla.com">
+  <meta charset="utf-8">
+  <style>
+    .flex {
+      display: flex;
+      width: 85px;
+      height: 65px;
+      border: 1px solid black;
+      align-content: flex-end;
+      justify-content: center;
+      align-items: center;
+      float: left;
+      clear: both;
+      margin-top: 100px;
+    }
+    .rowNoWrap {
+      flex-flow: row nowrap;
+    }
+    .columnNoWrap {
+      flex-flow: column wrap;
+    }
+    .item {
+      border: 1px solid blue;
+      background: lightblue;
+      width: 28px;
+      height: 28px;
+      flex-shrink: 0;
+    }
+    .bigItem {
+      border: 1px solid blue;
+      background: lightblue;
+      width: 28px;
+      height: 90px;
+      flex-shrink: 0;
+    }
+    .alignContentStart {
+      align-content: start;
+    }
+    .justifyContentStart {
+      justify-content: start;
+    }
+    .alignSelfStart {
+      align-self: start;
+    }
+  </style>
+</head>
+<body>
+  <div class="flex rowNoWrap justifyContentStart">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="bigItem alignSelfStart"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+  <div class="flex columnNoWrap alignContentStart">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html
new file mode 100644
index 0000000..8114832a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/publicdomain/zero/1.0
+-->
+<html>
+<head>
+  <title>CSS Test: Testing safe overflow-position for align-content, justify-content, and align-items in flex containers</title>
+  <link rel="author" title="Mihir Iyer" href="mailto:miyer@mozilla.com">
+  <link rel="help" href="https://drafts.csswg.org/css-align-3/#overflow-values">
+  <link rel="match" href="flexbox-safe-overflow-position-001-ref.html">
+  <meta charset="utf-8">
+  <style>
+    .flex {
+      display: flex;
+      width: 85px;
+      height: 65px;
+      border: 1px solid black;
+      align-content: safe flex-end;
+      justify-content: safe center;
+      align-items: safe center;
+      float: left;
+      clear: both;
+      margin-top: 100px;
+    }
+    .rowNoWrap {
+      flex-flow: row nowrap;
+    }
+    .columnNoWrap {
+      flex-flow: column wrap;
+    }
+    .item {
+      border: 1px solid blue;
+      background: lightblue;
+      width: 28px;
+      height: 28px;
+      flex-shrink: 0;
+    }
+    .bigItem {
+      border: 1px solid blue;
+      background: lightblue;
+      width: 28px;
+      height: 90px;
+      flex-shrink: 0;
+    }
+  </style>
+</head>
+<body>
+  <div class="flex rowNoWrap">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="bigItem"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+  <div class="flex columnNoWrap">
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+    <div class="item"></div>
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-window-open.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-window-open.tentative.html
new file mode 100644
index 0000000..2c3a8ce0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-window-open.tentative.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="support/helper.sub.js"></script>
+
+  <meta http-equiv="Content-Security-Policy" content="require-trusted-types">
+</head>
+<body>
+<script>
+  //helper functions for the tests
+  function testWindowOpen(t, url, win) {
+    let child_window = win.open(url, "", "");
+    child_window.onload = t.step_func_done(_ => {
+      assert_equals(child_window.location.href, "" + url);
+      child_window.close();
+    });
+  }
+
+  function testWindowThrows(t, url, win) {
+    let child_window = win.open(TrustedURL.create(URLS.safe), "", "");
+    child_window.onload = t.step_func_done(_ => {
+      assert_throws(new TypeError(), _ => {
+        child_window = win.open(url, "", "");
+        child_window.close();
+      });
+    });
+  }
+
+  //TrustedURL assignments do not throw
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.create(URLS.safe), window);
+  }, "window.open: safe URL, safe construction.");
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.unsafelyCreate(URLS.safe), window);
+  }, "window.open: safe URL, unsafe construction.");
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.create(URLS.safe), document);
+  }, "document.open: safe URL, safe construction.");
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.unsafelyCreate(URLS.safe), document);
+  }, "document.open: safe URL, unsafe construction.");
+
+  //String assignments throw
+  async_test(t => {
+    testWindowThrows(t, 'A string', window);
+  }, "`window.open(string)` throws.");
+
+  async_test(t => {
+    testWindowThrows(t, 'A string', document);
+  }, "`document.open(string)` throws.");
+
+  //Null assignment throws
+  async_test(t => {
+    testWindowThrows(t, null, window);
+  }, "`window.open(null)` throws.");
+
+  //Null assignment throws
+  async_test(t => {
+    testWindowThrows(t, null, document);
+  }, "`document.open(null)` throws.");
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/window-open.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/window-open.tentative.html
new file mode 100644
index 0000000..66ffbd7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/window-open.tentative.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+<body>
+<script>
+  //helper functions for the tests
+  function testWindowOpen(t, url, win) {
+    let child_window = win.open(url, "", "");
+    child_window.onload = t.step_func_done(_ => {
+      assert_equals(child_window.location.href, "" + url);
+      child_window.close();
+    });
+  }
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.create(URLS.safe), window);
+  }, "window.open: safe URL, safe construction.");
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.unsafelyCreate(URLS.safe), window);
+  }, "window.open: safe URL, unsafe construction.");
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.create(URLS.safe), document);
+  }, "document.open: safe URL, safe construction.");
+
+  async_test(t => {
+    testWindowOpen(t, TrustedURL.unsafelyCreate(URLS.safe), document);
+  }, "document.open: safe URL, unsafe construction.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audionodeoptions.js b/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audionodeoptions.js
index 293e8e0..0d90a9c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audionodeoptions.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audionodeoptions.js
@@ -40,7 +40,7 @@
                   {channelCount: testChannelCount}));
         },
         'new ' + nodeName + '(c, {channelCount: ' + testChannelCount + '}}')
-        .throw(expectedNodeOptions.channelCount.errorType || 'TypeError');
+        .throw(expectedNodeOptions.channelCount.errorType || TypeError);
   } else {
     // The channel count is not fixed.  Try to set the count to invalid
     // values and make sure an error is thrown.
@@ -119,7 +119,7 @@
                   {channelCountMode: 'foobar'}));
         },
         'new ' + nodeName + '(c, {channelCountMode: "foobar"}')
-        .throw('TypeError');
+        .throw(TypeError);
     should(node.channelCountMode, 'node.channelCountMode after invalid setter')
         .beEqualTo(testValues[testValues.length - 1]);
   }
@@ -181,7 +181,7 @@
                   {channelInterpretation: 'foobar'}));
         },
         'new ' + nodeName + '(c, {channelInterpretation: "foobar"})')
-        .throw('TypeError');
+        .throw(TypeError);
     should(
         node.channelInterpretation,
         'node.channelInterpretation after invalid setter')
@@ -201,13 +201,13 @@
 function testInvalidConstructor(should, name, context) {
   should(() => {
     new window[name]();
-  }, 'new ' + name + '()').throw('TypeError');
+  }, 'new ' + name + '()').throw(TypeError);
   should(() => {
     new window[name](1);
-  }, 'new ' + name + '(1)').throw('TypeError');
+  }, 'new ' + name + '(1)').throw(TypeError);
   should(() => {
     new window[name](context, 42);
-  }, 'new ' + name + '(context, 42)').throw('TypeError');
+  }, 'new ' + name + '(context, 42)').throw(TypeError);
 }
 
 function testDefaultConstructor(should, name, context, options) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audit.js b/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audit.js
index c56e4d1..7ffa439 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audit.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/audit.js
@@ -81,6 +81,13 @@
           targetString = '' + String(target).split(/[\s\]]/)[1];
         }
         break;
+      case 'function':
+        if (Error.isPrototypeOf(target)) {
+          targetString = "EcmaScript error " + target.name;
+        } else {
+          targetString = String(target);
+        }
+        break;
       default:
         targetString = String(target);
         break;
@@ -267,7 +274,10 @@
 
     /**
      * Check if |actual| operation wrapped in a function throws an exception
-     * with a expected error type correctly. |expected| is optional.
+     * with a expected error type correctly. |expected| is optional. If it is a
+     * String, then it is considered to be the name of a DOMException. It can
+     * also be an instance of either an Error or a DOMException, to be more
+     * strict about the actual error type.
      *
      * @example
      *   should(() => { let a = b; }, 'A bad code').throw();
@@ -303,8 +313,15 @@
           // The expected error type was not given.
           didThrowCorrectly = true;
           passDetail = '${actual} threw ' + error.name + errorMessage + '.';
-        } else if (error.name === this._expected) {
-          // The expected error type match the actual one.
+        } else if (typeof(this._expected) == "string" &&
+                   error instanceof DOMException &&
+                   error.name === this._expected) {
+          // A DOMException was thrown and expected, and the names match
+          didThrowCorrectly = true;
+          passDetail = '${actual} threw ${expected}' + errorMessage + '.';
+        } else if (this._expected == error.constructor &&
+                   this._expected.name == error.name) {
+          // The expected error type and names match the actual one.
           didThrowCorrectly = true;
           passDetail = '${actual} threw ${expected}' + errorMessage + '.';
         } else {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/start-stop-exceptions.js b/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/start-stop-exceptions.js
index 99a93f50..a405f06 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/start-stop-exceptions.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/resources/start-stop-exceptions.js
@@ -8,7 +8,7 @@
       should(() => {
         node.start(time);
       }, `start(${time})`)
-    .throw('TypeError');
+    .throw(TypeError);
     });
 
   should(() => {
@@ -39,7 +39,7 @@
       should(() => {
         node.stop(time);
       }, `stop(${time})`)
-    .throw('TypeError');
+    .throw(TypeError);
     });
 }
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html
index 7d0af70d..b71078d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/audiobuffer-copy-channel.html
@@ -121,10 +121,10 @@
             .notThrow();
         should(() => {
           buffer.copyFromChannel(null, 0);
-        }, '1: buffer.copyFromChannel(null, 0)').throw('TypeError');
+        }, '1: buffer.copyFromChannel(null, 0)').throw(TypeError);
         should(() => {
           buffer.copyFromChannel(context, 0);
-        }, '2: buffer.copyFromChannel(context, 0)').throw('TypeError');
+        }, '2: buffer.copyFromChannel(context, 0)').throw(TypeError);
         should(() => {
           buffer.copyFromChannel(x, -1);
         }, '3: buffer.copyFromChannel(x, -1)').throw('IndexSizeError');
@@ -156,14 +156,14 @@
                 buffer.copyFromChannel(shared_buffer, 0);
               },
               '8: buffer.copyFromChannel(SharedArrayBuffer view, 0)')
-              .throw('TypeError');
+              .throw(TypeError);
 
           should(
               () => {
                 buffer.copyFromChannel(shared_buffer, 0, 0);
               },
               '9: buffer.copyFromChannel(SharedArrayBuffer view, 0, 0)')
-              .throw('TypeError');
+              .throw(TypeError);
         }
 
         task.done();
@@ -177,10 +177,10 @@
             .exist();
         should(() => {
           buffer.copyToChannel(null, 0);
-        }, '0: buffer.copyToChannel(null, 0)').throw('TypeError');
+        }, '0: buffer.copyToChannel(null, 0)').throw(TypeError);
         should(() => {
           buffer.copyToChannel(context, 0);
-        }, '1: buffer.copyToChannel(context, 0)').throw('TypeError');
+        }, '1: buffer.copyToChannel(context, 0)').throw(TypeError);
         should(() => {
           buffer.copyToChannel(x, -1);
         }, '2: buffer.copyToChannel(x, -1)').throw('IndexSizeError');
@@ -211,14 +211,14 @@
                 buffer.copyToChannel(shared_buffer, 0);
               },
               '7: buffer.copyToChannel(SharedArrayBuffer view, 0)')
-              .throw('TypeError');
+              .throw(TypeError);
 
           should(
               () => {
                 buffer.copyToChannel(shared_buffer, 0, 0);
               },
               '8: buffer.copyToChannel(SharedArrayBuffer view, 0, 0)')
-              .throw('TypeError');
+              .throw(TypeError);
         }
 
         task.done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html
index f6032f29..c5aae1ad 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/ctor-audiobuffer.html
@@ -24,13 +24,13 @@
       audit.define('invalid constructor', (task, should) => {
         should(() => {
           new AudioBuffer();
-        }, 'new AudioBuffer()').throw('TypeError');
+        }, 'new AudioBuffer()').throw(TypeError);
         should(() => {
           new AudioBuffer(1);
-        }, 'new AudioBuffer(1)').throw('TypeError');
+        }, 'new AudioBuffer(1)').throw(TypeError);
         should(() => {
           new AudioBuffer(Date, 42);
-        }, 'new AudioBuffer(Date, 42)').throw('TypeError');
+        }, 'new AudioBuffer(Date, 42)').throw(TypeError);
 
         task.done();
       });
@@ -42,19 +42,19 @@
         // optional.
         should(() => {
           new AudioBuffer({});
-        }, 'buffer = new AudioBuffer({})').throw('TypeError');
+        }, 'buffer = new AudioBuffer({})').throw(TypeError);
 
         should(() => {
           new AudioBuffer({length: 1});
-        }, 'buffer = new AudioBuffer({length: 1})').throw('TypeError');
+        }, 'buffer = new AudioBuffer({length: 1})').throw(TypeError);
 
         should(() => {
           new AudioBuffer({sampleRate: 48000});
-        }, 'buffer = new AudioBuffer({sampleRate: 48000})').throw('TypeError');
+        }, 'buffer = new AudioBuffer({sampleRate: 48000})').throw(TypeError);
 
         should(() => {
           buffer = new AudioBuffer({numberOfChannels: 1});
-        }, 'buffer = new AudioBuffer({numberOfChannels: 1}').throw('TypeError');
+        }, 'buffer = new AudioBuffer({numberOfChannels: 1}').throw(TypeError);
 
         // Length and sampleRate are required, but others are optional.
         should(
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic-expected.txt
new file mode 100644
index 0000000..d5ccc4a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-basic-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [start/stop exceptions] 
+PASS   start(NaN) threw EcmaScript error TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.".
+PASS   start(Infinity) threw EcmaScript error TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.".
+PASS   start(-Infinity) threw EcmaScript error TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.".
+PASS   Calling stop() before start() threw InvalidStateError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first.".
+FAIL X start(-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X start(0,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X start(0,0,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   Calling start() twice threw InvalidStateError: "Failed to execute 'start' on 'AudioBufferSourceNode': cannot call start more than once.".
+FAIL X stop(-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   stop(NaN) threw EcmaScript error TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   stop(Infinity) threw EcmaScript error TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   stop(-Infinity) threw EcmaScript error TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+FAIL < [start/stop exceptions] 4 out of 12 assertions were failed. assert_true: expected true got false
+FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html
index 0af05d3..5527f44 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-channels.html
@@ -28,7 +28,7 @@
             // Make sure we can't set to something which isn't an AudioBuffer.
             should(function() {
               source.buffer = 57;
-            }, 'source.buffer = 57').throw('TypeError');
+            }, 'source.buffer = 57').throw(TypeError);
 
             // It's ok to set the buffer to null.
             should(function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html
index 295cd5a..3a11074 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audiocontext-interface/audiocontextoptions.html
@@ -140,7 +140,7 @@
                   context = new AudioContext({'latencyHint': 'foo'})
                 },
                 'context = new AudioContext({\'latencyHint\': \'foo\'})')
-                .throw('TypeError');
+                .throw(TypeError);
 
             // Verify that no extra options can be passed into the
             // AudioContextOptions.
@@ -149,7 +149,7 @@
                   context = new AudioContext('latencyHint')
                 },
                 'context = new AudioContext(\'latencyHint\')')
-                .throw('TypeError');
+                .throw(TypeError);
 
             Promise.all(closingPromises).then(function() {
               task.done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audionode-interface/audionode.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audionode-interface/audionode.html
index b75cd0b..14cfbff7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audionode-interface/audionode.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audionode-interface/audionode.html
@@ -46,11 +46,11 @@
             // Try calling connect() method with illegal values.
             should(
                 () => audioNode.connect(0, 0, 0), 'audioNode.connect(0, 0, 0)')
-                .throw('TypeError');
+                .throw(TypeError);
             should(
                 () => audioNode.connect(null, 0, 0),
                 'audioNode.connect(null, 0, 0)')
-                .throw('TypeError');
+                .throw(TypeError);
             should(
                 () => audioNode.connect(context.destination, 5, 0),
                 'audioNode.connect(context.destination, 5, 0)')
@@ -77,7 +77,7 @@
             should(
                 () => context3 = new AudioContext(1, 44100, 44100),
                 'context3 = new AudioContext(1, 44100, 44100)')
-                .throw('TypeError');
+                .throw(TypeError);
 
             // Ensure it is an EventTarget
             should(
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values-expected.txt
new file mode 100644
index 0000000..d85a2ac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values-expected.txt
@@ -0,0 +1,62 @@
+This is a testharness.js-based test.
+Found 58 tests; 44 PASS, 14 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [initialize] 
+PASS   Creating context for testing did not throw an exception.
+PASS < [initialize] All assertions passed. (total 1 assertions)
+PASS > [test value] Test non-finite arguments for AudioParam value
+PASS   gain.gain.setValueAtTime(Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'setValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.linearRampToValueAtTime(Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'linearRampToValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.exponentialRampToValueAtTime(Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.setTargetAtTime(Infinity,1,1) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.setValueAtTime(-Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'setValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.linearRampToValueAtTime(-Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'linearRampToValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.exponentialRampToValueAtTime(-Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.setTargetAtTime(-Infinity,1,1) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.setValueAtTime(NaN,1) threw EcmaScript error TypeError: "Failed to execute 'setValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.linearRampToValueAtTime(NaN,1) threw EcmaScript error TypeError: "Failed to execute 'linearRampToValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.exponentialRampToValueAtTime(NaN,1) threw EcmaScript error TypeError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.setTargetAtTime(NaN,1,1) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS < [test value] All assertions passed. (total 12 assertions)
+PASS > [test time] Test non-finite arguments for AudioParam time
+PASS   gain.gain.setValueAtTime(1,Infinity) threw EcmaScript error TypeError: "Failed to execute 'setValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.linearRampToValueAtTime(1,Infinity) threw EcmaScript error TypeError: "Failed to execute 'linearRampToValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.exponentialRampToValueAtTime(1,Infinity) threw EcmaScript error TypeError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setTargetAtTime(1,Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setTargetAtTime(1,1,Infinity) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setValueAtTime(1,-Infinity) threw EcmaScript error TypeError: "Failed to execute 'setValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.linearRampToValueAtTime(1,-Infinity) threw EcmaScript error TypeError: "Failed to execute 'linearRampToValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.exponentialRampToValueAtTime(1,-Infinity) threw EcmaScript error TypeError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setTargetAtTime(1,-Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setTargetAtTime(1,1,-Infinity) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setValueAtTime(1,NaN) threw EcmaScript error TypeError: "Failed to execute 'setValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.linearRampToValueAtTime(1,NaN) threw EcmaScript error TypeError: "Failed to execute 'linearRampToValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.exponentialRampToValueAtTime(1,NaN) threw EcmaScript error TypeError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setTargetAtTime(1,NaN,1) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setTargetAtTime(1,1,NaN) threw EcmaScript error TypeError: "Failed to execute 'setTargetAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS < [test time] All assertions passed. (total 15 assertions)
+PASS > [test setValueCurve] Test non-finite arguments for setValueCurveAtTime
+PASS   gain.gain.setValueCurveAtTime([0,0,0],Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setValueCurveAtTime([0,0,0],-Infinity,1) threw EcmaScript error TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setValueCurveAtTime([0,0,0],NaN,1) threw EcmaScript error TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': The provided double value is non-finite.".
+PASS   gain.gain.setValueCurveAtTime([1,2,Infinity,3],1,1) threw EcmaScript error TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS   gain.gain.setValueCurveAtTime([1,NaN,2,3],1,1) threw EcmaScript error TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': The provided float value is non-finite.".
+PASS < [test setValueCurve] All assertions passed. (total 5 assertions)
+PASS > [special cases 1] Test exceptions for finite values
+FAIL X gain.gain.setValueAtTime(1,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.linearRampToValueAtTime(1,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.exponentialRampToValueAtTime(1,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.setTargetAtTime(1,-1,1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.setTargetAtTime(1,1,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.setValueCurveAtTime([0,0,0],-1,1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.setValueCurveAtTime([0,0,0],1,-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.setValueCurveAtTime(curve, 1, 0) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL < [special cases 1] 8 out of 8 assertions were failed. assert_true: expected true got false
+PASS > [special cases 2] Test special cases for expeonentialRamp
+FAIL X gain.gain.exponentialRampToValueAtTime(0,1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.exponentialRampToValueAtTime(-1e-100,1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X gain.gain.exponentialRampToValueAtTime(1e-100,1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL < [special cases 2] 3 out of 3 assertions were failed. assert_true: expected true got false
+FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 6 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html
index c2d18de..1bda93e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-exceptional-values.html
@@ -45,7 +45,7 @@
             let defaultFuncArg = (value) => [value, 1];
 
             // Test the value parameter
-            doTests(should, gain, 'TypeError', nonFiniteValues, [
+            doTests(should, gain, TypeError, nonFiniteValues, [
               {automationName: 'setValueAtTime', funcArg: defaultFuncArg}, {
                 automationName: 'linearRampToValueAtTime',
                 funcArg: defaultFuncArg
@@ -75,7 +75,7 @@
             let defaultFuncArg = (startTime) => [1, startTime];
 
             // Test the time parameter
-            doTests(should, gain, 'TypeError', nonFiniteValues, [
+            doTests(should, gain, TypeError, nonFiniteValues, [
               {automationName: 'setValueAtTime', funcArg: defaultFuncArg},
               {
                 automationName: 'linearRampToValueAtTime',
@@ -112,7 +112,7 @@
             // contents of the array are not important.
             let curve = new Float32Array(3);
 
-            doTests(should, gain, 'TypeError', nonFiniteValues, [
+            doTests(should, gain, TypeError, nonFiniteValues, [
               {
                 automationName: 'setValueCurveAtTime',
                 funcArg: (startTime) => [curve, startTime, 1]
@@ -121,7 +121,7 @@
 
             // Non-finite values for the curve should signal an error
             doTests(
-                should, gain, 'TypeError',
+                should, gain, TypeError,
                 [[1, 2, Infinity, 3], [1, NaN, 2, 3]], [{
                   automationName: 'setValueCurveAtTime',
                   funcArg: (c) => [c, 1, 1]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining-expected.txt
new file mode 100644
index 0000000..0804800
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-method-chaining-expected.txt
@@ -0,0 +1,22 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [from-dictionary] 
+PASS   The return value of AudioParam.setValueAtTime() matches the source AudioParam is equal to true.
+PASS   The return value of AudioParam.linearRampToValueAtTime() matches the source AudioParam is equal to true.
+PASS   The return value of AudioParam.exponentialRampToValueAtTime() matches the source AudioParam is equal to true.
+PASS   The return value of AudioParam.setTargetAtTime() matches the source AudioParam is equal to true.
+PASS   The return value of AudioParam.setValueCurveAtTime() matches the source AudioParam is equal to true.
+PASS   The return value of AudioParam.cancelScheduledValues() matches the source AudioParam is equal to true.
+PASS < [from-dictionary] All assertions passed. (total 6 assertions)
+PASS > [invalid-operation] 
+FAIL X Calling setValueAtTime() with a negative end time threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X Calling exponentialRampToValueAtTime() with a zero target value threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   The gain value of the first gain node is equal to 1.
+PASS   The gain value of the second gain node is equal to 0.5.
+FAIL < [invalid-operation] 2 out of 4 assertions were failed. assert_true: expected true got false
+PASS > [verification] 
+PASS   The rendered envelope equals [0,0.000125,0.00025,0.000375,0.0005,0.000625,0.00075,0.000875,0.001,0.001125,0.00125,0.001375,0.0015,0.001625,0.00175,0.001875...] with an element-wise tolerance of {"absoluteThreshold":0.0000040532,"relativeThreshold":0}.
+PASS < [verification] All assertions passed. (total 1 assertions)
+FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 3 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html
index 590dcbd5..31405eb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html
@@ -130,7 +130,7 @@
                   Float32Array.from([NaN, NaN]), time, 0.01);
             },
             'setValueCurveAtTime([NaN, NaN], ' + time + ', 0.01)')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             () => {
@@ -138,7 +138,7 @@
                   Float32Array.from([1, Infinity]), time, 0.01);
             },
             'setValueCurveAtTime([1, Infinity], ' + time + ', 0.01)')
-            .throw('TypeError');
+            .throw(TypeError);
 
         let d = context.createDelay();
         // Check that we get warnings for out-of-range values and also throw for
@@ -158,7 +158,7 @@
             },
             'delayTime.setValueCurveAtTime([1, 5, Infinity], ' + time +
                 ', 0.01)')
-            .throw('TypeError');
+            .throw(TypeError);
 
         // One last test that prints out lots of digits for the time.
         time = Math.PI / 100;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html
index 254c07e93..31e204c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletnode-constructor-options.https.html
@@ -116,7 +116,7 @@
         should(
             () => new AudioWorkletNode(context, 'dummy', options1),
             'Creating AudioWorkletNode with channelCountMode "foobar"')
-            .throw('TypeError');
+            .throw(TypeError);
 
         task.done();
       });
@@ -138,7 +138,7 @@
         should(
             () => new AudioWorkletNode(context, 'dummy', options1),
             'Creating AudioWorkletNode with channelCountMode "foobar"')
-            .throw('TypeError');
+            .throw(TypeError);
 
         task.done();
       });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html
index c4f7c07..83f53aa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-biquadfilternode-interface/biquad-basic.html
@@ -73,7 +73,7 @@
                 'null, ' +
                 'new Float32Array(1), ' +
                 'new Float32Array(1))')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             function() {
@@ -85,7 +85,7 @@
                 'new Float32Array(1), ' +
                 'null, ' +
                 'new Float32Array(1))')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             function() {
@@ -97,7 +97,7 @@
                 'new Float32Array(1), ' +
                 'new Float32Array(1), ' +
                 'null)')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic-expected.txt
new file mode 100644
index 0000000..e676d07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-constantsourcenode-interface/constant-source-basic-expected.txt
@@ -0,0 +1,43 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [createConstantSource()] 
+PASS   Factory method: node = context.createConstantSource() did not throw an exception.
+PASS   Factory method: node instance of ConstantSourceNode is equal to true.
+PASS   Factory method: node.numberOfInputs is equal to 0.
+PASS   Factory method: node.numberOfOutputs is equal to 1.
+PASS   Factory method: node.channelCount is equal to 2.
+PASS   Factory method: node.channelCountMode is equal to max.
+PASS   Factory method: node.channelInterpretation is equal to speakers.
+PASS   Factory method: node.offset.value is equal to 1.
+PASS   Factory method: node.offset.defaultValue is equal to 1.
+PASS   Factory method: node.offset.minValue is equal to -3.4028234663852886e+38.
+PASS   Factory method: node.offset.maxValue is equal to 3.4028234663852886e+38.
+PASS < [createConstantSource()] All assertions passed. (total 11 assertions)
+PASS > [new ConstantSourceNode()] 
+PASS   Constructor: node = new ConstantSourceNode() did not throw an exception.
+PASS   Constructor: node instance of ConstantSourceNode is equal to true.
+PASS   Constructor: node.numberOfInputs is equal to 0.
+PASS   Constructor: node.numberOfOutputs is equal to 1.
+PASS   Constructor: node.channelCount is equal to 2.
+PASS   Constructor: node.channelCountMode is equal to max.
+PASS   Constructor: node.channelInterpretation is equal to speakers.
+PASS   Constructor: node.offset.value is equal to 1.
+PASS   Constructor: node.offset.defaultValue is equal to 1.
+PASS   Constructor: node.offset.minValue is equal to -3.4028234663852886e+38.
+PASS   Constructor: node.offset.maxValue is equal to 3.4028234663852886e+38.
+PASS < [new ConstantSourceNode()] All assertions passed. (total 11 assertions)
+PASS > [start/stop exceptions] 
+PASS   start(NaN) threw EcmaScript error TypeError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   start(Infinity) threw EcmaScript error TypeError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   start(-Infinity) threw EcmaScript error TypeError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   Calling stop() before start() threw InvalidStateError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first.".
+FAIL X start(-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   Calling start() twice threw InvalidStateError: "Failed to execute 'start' on 'AudioScheduledSourceNode': cannot call start more than once.".
+FAIL X stop(-1) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   stop(NaN) threw EcmaScript error TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   stop(Infinity) threw EcmaScript error TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+PASS   stop(-Infinity) threw EcmaScript error TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.".
+FAIL < [start/stop exceptions] 2 out of 10 assertions were failed. assert_true: expected true got false
+FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 3 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html
index 3f4c020..7bbff41 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-delaynode-interface/delaynode-maxdelaylimit.html
@@ -32,11 +32,15 @@
             bufferSource.buffer = toneBuffer;
 
             window.context = context;
-            should(() => context.createDelay(180)).throw();
-            should(() => context.createDelay(0)).throw();
-            should(() => context.createDelay(-1)).throw();
-            should(() => context.createDelay(NaN)).throw();
-            ;
+            should(() => context.createDelay(180)).throw("NotSupportedError",
+              "Delay length cannot be 180 seconds or more");
+            should(() => context.createDelay(0)).throw("NotSupportedError",
+              "Delay length cannot be 0");
+            should(() => context.createDelay(-1)).throw("NotSupportedError",
+              "Delay length cannot be negative");
+            should(() => context.createDelay(NaN)).throw(TypeError,
+              "Delay length cannot be a NaN");
+
             let delay = context.createDelay(179);
             delay.delayTime.value = delayTimeSeconds;
             window.delay = delay;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html
index 799c1872..98d5dbfd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-dynamicscompressornode-interface/ctor-dynamicscompressor.html
@@ -99,7 +99,7 @@
           {
             testAttribute: 'channelCountMode',
             testValue: 'foobar',
-            expectedErrorType: 'TypeError'
+            expectedErrorType: TypeError
           },
           // Test channel interpretation
           {
@@ -113,7 +113,7 @@
           {
             testAttribute: 'channelInterpretation',
             testValue: 'foobar',
-            expectedErrorType: 'TypeError'
+            expectedErrorType: TypeError
           }
         ];
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html
index bb89512..e884d48 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/ctor-iirfilter.html
@@ -57,7 +57,7 @@
               node = new IIRFilterNode(context, options);
             },
             'node = new IIRFilterNode(, ' + JSON.stringify(options) + ')')
-            .throw('TypeError');
+            .throw(TypeError);
 
         options = {feedforward: [1, 0.5]};
         should(
@@ -65,7 +65,7 @@
               node = new IIRFilterNode(context, options);
             },
             'node = new IIRFilterNode(c, ' + JSON.stringify(options) + ')')
-            .throw('TypeError');
+            .throw(TypeError);
 
         task.done();
       });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html
index da36d58..79c40dc0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/iirfilter-basic.html
@@ -51,17 +51,17 @@
         should(function() {
           // Two args are required.
           context.createIIRFilter();
-        }, 'createIIRFilter()').throw('TypeError');
+        }, 'createIIRFilter()').throw(TypeError);
 
         should(function() {
           // Two args are required.
           context.createIIRFilter(new Float32Array(1));
-        }, 'createIIRFilter(new Float32Array(1))').throw('TypeError');
+        }, 'createIIRFilter(new Float32Array(1))').throw(TypeError);
 
         should(function() {
           // null is not valid
           context.createIIRFilter(null, null);
-        }, 'createIIRFilter(null, null)').throw('TypeError');
+        }, 'createIIRFilter(null, null)').throw(TypeError);
 
         should(function() {
           // There has to be at least one coefficient.
@@ -127,17 +127,17 @@
         should(function() {
           // Feedback coefficients must be finite.
           context.createIIRFilter([1], [1, Infinity, NaN]);
-        }, 'createIIRFilter([1], [1, NaN, Infinity])').throw('TypeError');
+        }, 'createIIRFilter([1], [1, NaN, Infinity])').throw(TypeError);
 
         should(function() {
           // Feedforward coefficients must be finite.
           context.createIIRFilter([1, Infinity, NaN], [1]);
-        }, 'createIIRFilter([1, NaN, Infinity], [1])').throw('TypeError');
+        }, 'createIIRFilter([1, NaN, Infinity], [1])').throw(TypeError);
 
         should(function() {
           // Test that random junk in the array is converted to NaN.
           context.createIIRFilter([1, 'abc', []], [1]);
-        }, 'createIIRFilter([1, \'abc\', []], [1])').throw('TypeError');
+        }, 'createIIRFilter([1, \'abc\', []], [1])').throw(TypeError);
 
         task.done();
       });
@@ -155,7 +155,7 @@
                   null, new Float32Array(1), new Float32Array(1));
             },
             'getFrequencyResponse(null, new Float32Array(1), new Float32Array(1))')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             function() {
@@ -164,7 +164,7 @@
                   new Float32Array(1), null, new Float32Array(1));
             },
             'getFrequencyResponse(new Float32Array(1), null, new Float32Array(1))')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             function() {
@@ -173,7 +173,7 @@
                   new Float32Array(1), new Float32Array(1), null);
             },
             'getFrequencyResponse(new Float32Array(1), new Float32Array(1), null)')
-            .throw('TypeError');
+            .throw(TypeError);
 
         should(
             function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html
index 79aafe7..f480ec8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html
@@ -23,12 +23,12 @@
             // First and only arg should be a dictionary.
             should(() => {
               new OfflineAudioContext(3);
-            }, 'new OfflineAudioContext(3)').throw('TypeError');
+            }, 'new OfflineAudioContext(3)').throw(TypeError);
 
             // Constructor needs 1 or 3 args, so 2 should throw.
             should(() => {
               new OfflineAudioContext(3, 42);
-            }, 'new OfflineAudioContext(3, 42)').throw('TypeError');
+            }, 'new OfflineAudioContext(3, 42)').throw(TypeError);
 
             // Valid constructor
             should(() => {
@@ -63,12 +63,12 @@
             // No args should throw
             should(() => {
               new OfflineAudioContext();
-            }, 'new OfflineAudioContext()').throw('TypeError');
+            }, 'new OfflineAudioContext()').throw(TypeError);
 
             // Empty OfflineAudioContextOptions should throw
             should(() => {
               new OfflineAudioContext({});
-            }, 'new OfflineAudioContext({})').throw('TypeError');
+            }, 'new OfflineAudioContext({})').throw(TypeError);
 
             let options = {length: 42};
             // sampleRate is required.
@@ -77,7 +77,7 @@
                   new OfflineAudioContext(options);
                 },
                 'new OfflineAudioContext(' + JSON.stringify(options) + ')')
-                .throw('TypeError');
+                .throw(TypeError);
 
             options = {sampleRate: 12345};
             // length is required.
@@ -86,7 +86,7 @@
                   new OfflineAudioContext(options);
                 },
                 'new OfflineAudioContext(' + JSON.stringify(options) + ')')
-                .throw('TypeError');
+                .throw(TypeError);
 
             // Valid constructor.  Verify that the resulting context has the
             // correct values.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html
index 48b368d..5475a621 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html
@@ -161,7 +161,7 @@
               node = new PannerNode(context, options);
             },
             'new PannerNode(c, " + JSON.stringify(options) + ")')
-            .throw('TypeError');
+            .throw(TypeError);
 
         // Test channelInterpretation.
         options = {channelInterpretation: 'speakers'};
@@ -190,7 +190,7 @@
               node = new PannerNode(context, options);
             },
             'new PannerNode(c, ' + JSON.stringify(options) + ')')
-            .throw('TypeError');
+            .throw(TypeError);
 
         task.done();
       });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html
index 9de58cf..caa99aa 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webaudio/the-audio-api/the-stereopanner-interface/ctor-stereopanner.html
@@ -65,7 +65,7 @@
            tests: [
              {value: 'clamped-max'}, {value: 'explicit'},
              {value: 'max', error: 'NotSupportedError'},
-             {value: 'foobar', error: 'TypeError'}
+             {value: 'foobar', error: TypeError}
            ]
          },
          {
@@ -74,7 +74,7 @@
            attribute: 'channelInterpretation',
            tests: [
              {value: 'speakers'}, {value: 'discrete'},
-             {value: 'foobar', error: 'TypeError'}
+             {value: 'foobar', error: TypeError}
            ]
          }].forEach(entry => {
           entry.tests.forEach(testItem => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webusb/insecure-context.any.js b/third_party/WebKit/LayoutTests/external/wpt/webusb/insecure-context.any.js
new file mode 100644
index 0000000..42452b53
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webusb/insecure-context.any.js
@@ -0,0 +1,22 @@
+// META: global=sharedworker
+'use strict';
+
+test(() => {
+  assert_false(isSecureContext);
+  assert_false('usb' in navigator);
+}, '"usb" should not be present on navigator in an insecure context.');
+
+[
+    'USB', 'USBAlternateInterface', 'USBConfiguration', 'USBConnectionEvent',
+    'USBDevice', 'USBEndpoint', 'USBInterface', 'USBInTransferResult',
+    'USBOutTransferResult', 'USBIsochronousInTransferResult',
+    'USBIsochronousOutTransferResult', 'USBIsochronousInTransferPacket',
+    'USBIsochronousOutTransferPacket',
+].forEach((symbol) => {
+  test(() => {
+    assert_false(isSecureContext);
+    assert_false(symbol in this)
+  }, '"' + symbol + '" should not be visible in an insecure context.');
+});
+
+done();
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/select-initial-position.html b/third_party/WebKit/LayoutTests/fast/forms/select/select-initial-position.html
index 7e24851..c14b1db 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/select-initial-position.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/select-initial-position.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <html>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/fast/frames/iframe-with-frameborder.html b/third_party/WebKit/LayoutTests/fast/frames/iframe-with-frameborder.html
index 40574731..8bf414c 100644
--- a/third_party/WebKit/LayoutTests/fast/frames/iframe-with-frameborder.html
+++ b/third_party/WebKit/LayoutTests/fast/frames/iframe-with-frameborder.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 This iframe should have a border.<br>
 
 <iframe frameborder="1" src="about:blank"></iframe>
diff --git a/third_party/WebKit/LayoutTests/fast/parser/001.html b/third_party/WebKit/LayoutTests/fast/parser/001.html
index 9ee3581..934d792 100644
--- a/third_party/WebKit/LayoutTests/fast/parser/001.html
+++ b/third_party/WebKit/LayoutTests/fast/parser/001.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <dir>One
 <dir>Two
 <dir>Three
diff --git a/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks-collapsed-border.html b/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks-collapsed-border.html
index 942e083..1df9445d 100644
--- a/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks-collapsed-border.html
+++ b/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks-collapsed-border.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Background on 'table'</title>
diff --git a/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks.html b/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks.html
index 595c55d..7c6a345 100644
--- a/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks.html
+++ b/third_party/WebKit/LayoutTests/fast/table/backgr_border-table-quirks.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Background on 'table'</title>
diff --git a/third_party/WebKit/LayoutTests/fast/table/dynamic-descendant-percentage-height.html b/third_party/WebKit/LayoutTests/fast/table/dynamic-descendant-percentage-height.html
index c296dc9..dec7478 100644
--- a/third_party/WebKit/LayoutTests/fast/table/dynamic-descendant-percentage-height.html
+++ b/third_party/WebKit/LayoutTests/fast/table/dynamic-descendant-percentage-height.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
 <script>
     if (window.testRunner)
         testRunner.waitUntilDone();
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/box-shadow/basic-shadows-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/box-shadow/basic-shadows-expected.txt
new file mode 100644
index 0000000..980bd429
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/box-shadow/basic-shadows-expected.txt
@@ -0,0 +1,89 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 687
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x687 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutNGBlockFlow {HTML} at (0,0) size 785x687
+    LayoutNGBlockFlow {BODY} at (8,8) size 769x652
+      LayoutNGBlockFlow (anonymous) at (0,0) size 769x150
+        LayoutInline {SPAN} at (0,0) size 264x129 [border: (5px solid #000000)]
+          LayoutText {#text} at (5,15) size 55x19
+            text run at (5,15) width 55: "This text"
+          LayoutBR {BR} at (60,15) size 0x0
+          LayoutText {#text} at (0,65) size 76x19
+            text run at (0,65) width 76: "should have"
+          LayoutBR {BR} at (76,65) size 0x0
+          LayoutText {#text} at (0,115) size 259x19
+            text run at (0,115) width 259: "a multi-line shadow with a border-radius."
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutNGBlockFlow {DIV} at (0,150) size 120x120 [border: (10px solid #000000)]
+        LayoutText {#text} at (10,10) size 87x59
+          text run at (10,10) width 29: "50%"
+          text run at (10,30) width 69: "transparent"
+          text run at (10,50) width 87: "black shadow"
+      LayoutTable {TABLE} at (0,270) size 184x270
+        LayoutTableSection {TBODY} at (0,0) size 184x270
+          LayoutTableRow {TR} at (0,10) size 184x42
+            LayoutNGTableCell {TD} at (10,10) size 48x42 [border: (1px solid #000000)] [r=0 c=0 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (68,10) size 48x42 [border: (1px solid #000000)] [r=0 c=1 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (126,10) size 48x42 [border: (1px solid #000000)] [r=0 c=2 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+          LayoutTableRow {TR} at (0,62) size 184x42
+            LayoutNGTableCell {TD} at (10,62) size 48x42 [border: (1px solid #000000)] [r=1 c=0 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (68,62) size 48x42 [border: (1px solid #000000)] [r=1 c=1 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (126,62) size 48x42 [border: (1px solid #000000)] [r=1 c=2 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+          LayoutTableRow {TR} at (0,114) size 184x42
+            LayoutNGTableCell {TD} at (10,114) size 48x42 [border: (1px solid #000000)] [r=2 c=0 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (68,114) size 48x42 [border: (1px solid #000000)] [r=2 c=1 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (126,114) size 48x42 [border: (1px solid #000000)] [r=2 c=2 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+          LayoutTableRow {TR} at (0,166) size 184x42
+            LayoutNGTableCell {TD} at (10,166) size 48x42 [border: (1px solid #000000)] [r=3 c=0 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (68,166) size 48x42 [border: (1px solid #000000)] [r=3 c=1 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (126,166) size 48x42 [border: (1px solid #000000)] [r=3 c=2 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+          LayoutTableRow {TR} at (0,218) size 184x42
+            LayoutNGTableCell {TD} at (10,218) size 48x42 [border: (1px solid #000000)] [r=4 c=0 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (68,218) size 48x42 [border: (1px solid #000000)] [r=4 c=1 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+            LayoutNGTableCell {TD} at (126,218) size 48x42 [border: (1px solid #000000)] [r=4 c=2 rs=1 cs=1]
+              LayoutText {#text} at (11,11) size 26x19
+                text run at (11,11) width 26: "Cell"
+      LayoutNGBlockFlow {P} at (0,556) size 769x40
+        LayoutInline (anonymous) at (0,0) size 356x39
+          LayoutText {#text} at (0,0) size 356x19
+            text run at (0,0) width 356: "The first line of this div should have a box-shadow on it."
+          LayoutBR {BR} at (356,0) size 0x0
+          LayoutText {#text} at (0,20) size 177x19
+            text run at (0,20) width 177: "This second line should not."
+      LayoutNGBlockFlow {P} at (0,612) size 769x40
+        LayoutNGBlockFlow (floating) {<pseudo:first-letter>} at (0,0) size 39x67 [bgcolor=#EEEEEE] [border: (1px solid #000000)]
+          LayoutTextFragment (anonymous) at (5,6) size 29x55
+            text run at (5,6) width 29: "T"
+        LayoutTextFragment {#text} at (43,0) size 488x19
+          text run at (43,0) width 488: "he first letter of this paragraph should have a border and a nice shadow effect."
+        LayoutBR {BR} at (531,0) size 0x0
+        LayoutText {#text} at (43,20) size 162x19
+          text run at (43,20) width 162: "It should look pretty cool."
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/form-hides-table-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/form-hides-table-expected.txt
new file mode 100644
index 0000000..7ffaf533
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/form-hides-table-expected.txt
@@ -0,0 +1,170 @@
+layer at (0,0) size 800x600 scrollHeight 674
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x674 backgroundClip at (0,0) size 800x600 clip at (0,0) size 800x600
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x674
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x658
+      LayoutNGBlockFlow {P} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 551x19
+          text run at (0,0) width 551: "This page has a few tables within form elements within divs with various display styles."
+      LayoutNGBlockFlow {P} at (0,36) size 784x20
+        LayoutText {#text} at (0,0) size 27x19
+          text run at (0,0) width 27: "See "
+        LayoutInline {A} at (0,0) size 120x19 [color=#0000EE]
+          LayoutText {#text} at (27,0) size 120x19
+            text run at (27,0) width 120: "Bugzilla Bug 4977"
+        LayoutText {#text} at (147,0) size 4x19
+          text run at (147,0) width 4: "."
+      LayoutNGBlockFlow {DIV} at (0,72) size 784x26
+        LayoutNGBlockFlow (anonymous) at (0,0) size 784x0
+          LayoutInline {DIV} at (0,0) size 0x0
+        LayoutNGBlockFlow (anonymous) at (0,0) size 784x26
+          LayoutNGBlockFlow {FORM} at (0,0) size 784x26
+            LayoutTable {TABLE} at (0,0) size 94x26
+              LayoutTableSection {TBODY} at (0,0) size 94x26
+                LayoutTableRow {TR} at (0,2) size 94x22
+                  LayoutNGTableCell {TD} at (2,2) size 90x22 [r=0 c=0 rs=1 cs=1]
+                    LayoutText {#text} at (1,1) size 88x19
+                      text run at (1,1) width 88: "display: inline"
+        LayoutNGBlockFlow (anonymous) at (0,42) size 784x0
+          LayoutInline {DIV} at (0,0) size 0x0
+      LayoutNGBlockFlow {DIV} at (0,114) size 784x26
+        LayoutNGBlockFlow {DIV} at (0,0) size 784x26
+          LayoutNGBlockFlow {FORM} at (0,0) size 784x26
+            LayoutTable {TABLE} at (0,0) size 94x26
+              LayoutTableSection {TBODY} at (0,0) size 94x26
+                LayoutTableRow {TR} at (0,2) size 94x22
+                  LayoutNGTableCell {TD} at (2,2) size 90x22 [r=0 c=0 rs=1 cs=1]
+                    LayoutText {#text} at (1,1) size 88x19
+                      text run at (1,1) width 88: "display: block"
+      LayoutNGBlockFlow {DIV} at (0,156) size 784x26
+        LayoutNGListItem {DIV} at (0,0) size 784x26
+          LayoutNGListMarker (anonymous) at (-18,8) size 7x20
+            LayoutText (anonymous) at (0,0) size 7x19
+              text run at (0,0) width 7: "\x{2022} "
+          LayoutNGBlockFlow {FORM} at (0,0) size 784x26
+            LayoutTable {TABLE} at (0,0) size 109x26
+              LayoutTableSection {TBODY} at (0,0) size 109x26
+                LayoutTableRow {TR} at (0,2) size 109x22
+                  LayoutNGTableCell {TD} at (2,2) size 105x22 [r=0 c=0 rs=1 cs=1]
+                    LayoutText {#text} at (1,1) size 103x19
+                      text run at (1,1) width 103: "display: list-item"
+      LayoutNGBlockFlow {DIV} at (0,198) size 784x26
+        LayoutNGBlockFlow {DIV} at (0,0) size 784x26
+          LayoutNGBlockFlow {FORM} at (0,0) size 784x26
+            LayoutTable {TABLE} at (0,0) size 112x26
+              LayoutTableSection {TBODY} at (0,0) size 112x26
+                LayoutTableRow {TR} at (0,2) size 112x22
+                  LayoutNGTableCell {TD} at (2,2) size 108x22 [r=0 c=0 rs=1 cs=1]
+                    LayoutText {#text} at (1,1) size 106x19
+                      text run at (1,1) width 106: "display: compact"
+      LayoutNGBlockFlow {DIV} at (0,240) size 784x42
+        LayoutNGBlockFlow {DIV} at (0,0) size 134x42
+          LayoutNGBlockFlow {FORM} at (0,0) size 134x26
+            LayoutTable {TABLE} at (0,0) size 134x26
+              LayoutTableSection {TBODY} at (0,0) size 134x26
+                LayoutTableRow {TR} at (0,2) size 134x22
+                  LayoutNGTableCell {TD} at (2,2) size 130x22 [r=0 c=0 rs=1 cs=1]
+                    LayoutText {#text} at (1,1) size 128x19
+                      text run at (1,1) width 128: "display: inline-block"
+      LayoutNGBlockFlow {DIV} at (0,282) size 784x42
+        LayoutTable {DIV} at (0,0) size 89x42
+          LayoutTableSection (anonymous) at (0,0) size 89x42
+            LayoutTableRow (anonymous) at (0,0) size 89x42
+              LayoutNGTableCell (anonymous) at (0,0) size 89x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 89x26
+                  LayoutTable {TABLE} at (0,0) size 89x26
+                    LayoutTableSection {TBODY} at (0,0) size 89x26
+                      LayoutTableRow {TR} at (0,2) size 89x22
+                        LayoutNGTableCell {TD} at (2,2) size 85x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 83x19
+                            text run at (1,1) width 83: "display: table"
+      LayoutNGBlockFlow {DIV} at (0,324) size 784x42
+        LayoutTable {DIV} at (0,0) size 129x42
+          LayoutTableSection (anonymous) at (0,0) size 129x42
+            LayoutTableRow (anonymous) at (0,0) size 129x42
+              LayoutNGTableCell (anonymous) at (0,0) size 129x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 129x26
+                  LayoutTable {TABLE} at (0,0) size 129x26
+                    LayoutTableSection {TBODY} at (0,0) size 129x26
+                      LayoutTableRow {TR} at (0,2) size 129x22
+                        LayoutNGTableCell {TD} at (2,2) size 125x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 123x19
+                            text run at (1,1) width 123: "display: inline-table"
+      LayoutNGBlockFlow {DIV} at (0,366) size 784x42
+        LayoutTable (anonymous) at (0,0) size 161x42
+          LayoutTableSection {DIV} at (0,0) size 161x42
+            LayoutTableRow (anonymous) at (0,0) size 161x42
+              LayoutNGTableCell (anonymous) at (0,0) size 161x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 161x26
+                  LayoutTable {TABLE} at (0,0) size 161x26
+                    LayoutTableSection {TBODY} at (0,0) size 161x26
+                      LayoutTableRow {TR} at (0,2) size 161x22
+                        LayoutNGTableCell {TD} at (2,2) size 157x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 155x19
+                            text run at (1,1) width 155: "display: table-row-group"
+      LayoutNGBlockFlow {DIV} at (0,408) size 784x42
+        LayoutTable (anonymous) at (0,0) size 178x42
+          LayoutTableSection {DIV} at (0,0) size 178x42
+            LayoutTableRow (anonymous) at (0,0) size 178x42
+              LayoutNGTableCell (anonymous) at (0,0) size 178x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 178x26
+                  LayoutTable {TABLE} at (0,0) size 178x26
+                    LayoutTableSection {TBODY} at (0,0) size 178x26
+                      LayoutTableRow {TR} at (0,2) size 178x22
+                        LayoutNGTableCell {TD} at (2,2) size 174x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 172x19
+                            text run at (1,1) width 172: "display: table-header-group"
+      LayoutNGBlockFlow {DIV} at (0,450) size 784x42
+        LayoutTable (anonymous) at (0,0) size 173x42
+          LayoutTableSection {DIV} at (0,0) size 173x42
+            LayoutTableRow (anonymous) at (0,0) size 173x42
+              LayoutNGTableCell (anonymous) at (0,0) size 173x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 173x26
+                  LayoutTable {TABLE} at (0,0) size 173x26
+                    LayoutTableSection {TBODY} at (0,0) size 173x26
+                      LayoutTableRow {TR} at (0,2) size 173x22
+                        LayoutNGTableCell {TD} at (2,2) size 169x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 167x19
+                            text run at (1,1) width 167: "display: table-footer-group"
+      LayoutNGBlockFlow {DIV} at (0,492) size 784x42
+        LayoutTable (anonymous) at (0,0) size 119x42
+          LayoutTableSection (anonymous) at (0,0) size 119x42
+            LayoutTableRow {DIV} at (0,0) size 119x42
+              LayoutNGTableCell (anonymous) at (0,0) size 119x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 119x26
+                  LayoutTable {TABLE} at (0,0) size 119x26
+                    LayoutTableSection {TBODY} at (0,0) size 119x26
+                      LayoutTableRow {TR} at (0,2) size 119x22
+                        LayoutNGTableCell {TD} at (2,2) size 115x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 113x19
+                            text run at (1,1) width 113: "display: table-row"
+      LayoutNGBlockFlow {DIV} at (0,534) size 784x0
+        LayoutTable (anonymous) at (0,0) size 0x0
+          LayoutTableCol {DIV} at (0,0) size 0x0
+      LayoutNGBlockFlow {DIV} at (0,534) size 784x0
+        LayoutTable (anonymous) at (0,0) size 0x0
+          LayoutTableCol {DIV} at (0,0) size 0x0
+      LayoutNGBlockFlow {DIV} at (0,534) size 784x42
+        LayoutTable (anonymous) at (0,0) size 116x42
+          LayoutTableSection (anonymous) at (0,0) size 116x42
+            LayoutTableRow (anonymous) at (0,0) size 116x42
+              LayoutNGTableCell {DIV} at (0,0) size 116x42 [r=0 c=0 rs=1 cs=1]
+                LayoutNGBlockFlow {FORM} at (0,0) size 116x26
+                  LayoutTable {TABLE} at (0,0) size 116x26
+                    LayoutTableSection {TBODY} at (0,0) size 116x26
+                      LayoutTableRow {TR} at (0,2) size 116x22
+                        LayoutNGTableCell {TD} at (2,2) size 112x22 [r=0 c=0 rs=1 cs=1]
+                          LayoutText {#text} at (1,1) size 110x19
+                            text run at (1,1) width 110: "display: table-cell"
+      LayoutNGBlockFlow {DIV} at (0,576) size 784x82
+        LayoutTable (anonymous) at (0,0) size 55x82
+          LayoutNGTableCaption {DIV} at (0,0) size 55x82
+            LayoutNGBlockFlow {FORM} at (0,0) size 55x66
+              LayoutTable {TABLE} at (0,0) size 55x66
+                LayoutTableSection {TBODY} at (0,0) size 55x66
+                  LayoutTableRow {TR} at (0,2) size 55x62
+                    LayoutNGTableCell {TD} at (2,2) size 51x62 [r=0 c=0 rs=1 cs=1]
+                      LayoutText {#text} at (1,1) size 49x59
+                        text run at (1,1) width 49: "display:"
+                        text run at (1,21) width 35: "table-"
+                        text run at (1,41) width 46: "caption"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/search/search-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/search/search-appearance-basic-expected.txt
index 8512cf8..cf9f44ff 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/search/search-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/search/search-appearance-basic-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x444
-  LayoutNGBlockFlow {HTML} at (0,0) size 800x444
-    LayoutNGBlockFlow {BODY} at (8,8) size 784x428
+layer at (0,0) size 800x445
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x445
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x429
       LayoutNGBlockFlow (anonymous) at (0,0) size 784x92
         LayoutTextControl {INPUT} at (4,4) size 183x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
           LayoutFlexibleBox {DIV} at (3,3) size 177x16
@@ -39,7 +39,7 @@
           LayoutFlexibleBox {DIV} at (3,3) size 127x16
             LayoutBlockFlow {DIV} at (0,0) size 114x16
         LayoutText {#text} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,137) size 784x291
+      LayoutNGBlockFlow (anonymous) at (0,137) size 784x292
         LayoutTextControl {INPUT} at (4,4) size 183x22 [border: (2px inset #EEEEEE)]
           LayoutFlexibleBox {DIV} at (3,3) size 177x16
             LayoutBlockFlow {DIV} at (0,0) size 164x16
@@ -84,9 +84,9 @@
             LayoutBlockFlow {DIV} at (0,0) size 307x33
         LayoutText {#text} at (0,0) size 0x0
         LayoutBR {BR} at (633,226) size 0x0
-        LayoutTextControl {INPUT} at (4,266) size 152x21 [bgcolor=#FFFFFF] [border: (1px solid #BDC7D8)]
-          LayoutFlexibleBox {DIV} at (18,4) size 130x13
-            LayoutBlockFlow {DIV} at (0,0) size 118x13
+        LayoutTextControl {INPUT} at (4,266) size 156x22 [bgcolor=#FFFFFF] [border: (1px solid #BDC7D8)]
+          LayoutFlexibleBox {DIV} at (18,4) size 134x14
+            LayoutBlockFlow {DIV} at (0,0) size 122x14
         LayoutText {#text} at (0,0) size 0x0
 layer at (15,15) size 164x16
   LayoutBlockFlow {DIV} at (0,0) size 164x16
@@ -152,12 +152,12 @@
   LayoutBlockFlow {DIV} at (0,0) size 307x33
     LayoutText {#text} at (0,0) size 38x32
       text run at (0,0) width 38: "foo"
-layer at (30,415) size 118x13
-  LayoutBlockFlow {DIV} at (18,4) size 118x13 [color=#757575]
-    LayoutText {#text} at (0,0) size 102x13
-      text run at (0,0) width 102: "Search for Events"
-layer at (30,415) size 118x13
-  LayoutBlockFlow {DIV} at (0,0) size 118x13
+layer at (30,415) size 122x14
+  LayoutBlockFlow {DIV} at (18,4) size 122x14 [color=#757575]
+    LayoutText {#text} at (0,0) size 88x14
+      text run at (0,0) width 88: "Search for Events"
+layer at (30,415) size 122x14
+  LayoutBlockFlow {DIV} at (0,0) size 122x14
 layer at (180,19) size 9x9 transparent
   LayoutBlockFlow {DIV} at (165,3.50) size 9x9
 layer at (180,49) size 9x9 transparent
@@ -188,6 +188,6 @@
   LayoutBlockFlow {DIV} at (227.50,5) size 14x14
 layer at (602,367) size 19x19 transparent
   LayoutBlockFlow {DIV} at (309,7) size 19x19
-layer at (149,418) size 8x8 transparent
-  LayoutBlockFlow {DIV} at (119,2.50) size 8x8
+layer at (153,418) size 8x8 transparent
+  LayoutBlockFlow {DIV} at (123,3) size 8x8
 caret: position 0 of child 0 {#text} of child 0 {DIV} of child 0 {DIV} of child 0 {DIV} of {#document-fragment} of child 10 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-initial-position-expected.txt
new file mode 100644
index 0000000..b392c3a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-initial-position-expected.txt
@@ -0,0 +1,160 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x409
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x409
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x393
+      LayoutText {#text} at (0,0) size 93x19
+        text run at (0,0) width 93: "initial selected:"
+      LayoutBR {BR} at (93,0) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (155,71) size 0x0
+      LayoutText {#text} at (0,91) size 161x19
+        text run at (0,91) width 161: "dynamic selected change:"
+      LayoutBR {BR} at (161,91) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (155,162) size 0x0
+      LayoutText {#text} at (0,182) size 211x19
+        text run at (0,182) width 211: "dynamic insert of selected option:"
+      LayoutBR {BR} at (211,182) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (155,253) size 0x0
+      LayoutText {#text} at (0,273) size 93x19
+        text run at (0,273) width 93: "initial selected:"
+      LayoutBR {BR} at (93,273) size 0x0
+      LayoutMenuList {SELECT} at (0,293) size 156x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 154x18
+          LayoutText (anonymous) at (4,1) size 134x16
+            text run at (4,1) width 134: "this should be selected"
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (156,293) size 0x0
+      LayoutText {#text} at (0,313) size 161x19
+        text run at (0,313) width 161: "dynamic selected change:"
+      LayoutBR {BR} at (161,313) size 0x0
+      LayoutMenuList {SELECT} at (0,333) size 156x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 154x18
+          LayoutText (anonymous) at (4,1) size 134x16
+            text run at (4,1) width 134: "this should be selected"
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (156,333) size 0x0
+      LayoutText {#text} at (0,353) size 211x19
+        text run at (0,353) width 211: "dynamic insert of selected option:"
+      LayoutBR {BR} at (211,353) size 0x0
+      LayoutMenuList {SELECT} at (0,373) size 156x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 154x18
+          LayoutText (anonymous) at (4,1) size 134x16
+            text run at (4,1) width 134: "this should be selected"
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,28) size 155x70 clip at (9,29) size 138x68 scrollY 119.00 scrollHeight 238
+  LayoutListBox {SELECT} at (0,20) size 155x70 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
+    LayoutBlockFlow {OPTION} at (1,1) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,18) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,35) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,52) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,69) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,86) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,103) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,120) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,137) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,154) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,171) size 138x17 [color=#FFFFFF] [bgcolor=#999999]
+      LayoutText {#text} at (2,0) size 134x16
+        text run at (2,0) width 134: "this should be selected"
+    LayoutBlockFlow {OPTION} at (1,188) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,205) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,222) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+layer at (8,119) size 155x70 clip at (9,120) size 138x68 scrollY 119.00 scrollHeight 238
+  LayoutListBox {SELECT} at (0,111) size 155x70 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
+    LayoutBlockFlow {OPTION} at (1,1) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,18) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,35) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,52) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,69) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,86) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,103) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,120) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,137) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,154) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,171) size 138x17 [color=#FFFFFF] [bgcolor=#999999]
+      LayoutText {#text} at (2,0) size 134x16
+        text run at (2,0) width 134: "this should be selected"
+    LayoutBlockFlow {OPTION} at (1,188) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,205) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,222) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+layer at (8,210) size 155x70 clip at (9,211) size 138x68 scrollY 51.00 scrollHeight 136
+  LayoutListBox {SELECT} at (0,202) size 155x70 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
+    LayoutBlockFlow {OPTION} at (1,1) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,18) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,35) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,52) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,69) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,86) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
+    LayoutBlockFlow {OPTION} at (1,103) size 138x17 [color=#FFFFFF] [bgcolor=#999999]
+      LayoutText {#text} at (2,0) size 134x16
+        text run at (2,0) width 134: "this should be selected"
+    LayoutBlockFlow {OPTION} at (1,120) size 138x17
+      LayoutText {#text} at (2,0) size 18x16
+        text run at (2,0) width 18: "opt"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/iframe-with-frameborder-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/iframe-with-frameborder-expected.txt
new file mode 100644
index 0000000..c5216a39
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/iframe-with-frameborder-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x549
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x549
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x533
+      LayoutText {#text} at (0,0) size 211x19
+        text run at (0,0) width 211: "This iframe should have a border."
+      LayoutBR {BR} at (211,0) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (304,159) size 0x0
+      LayoutText {#text} at (0,179) size 146x19
+        text run at (0,179) width 146: "This iframe should not."
+      LayoutBR {BR} at (146,179) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
+      LayoutBR {BR} at (300,334) size 0x0
+      LayoutText {#text} at (0,354) size 211x19
+        text run at (0,354) width 211: "This iframe should have a border."
+      LayoutBR {BR} at (211,354) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,28) size 304x154
+  LayoutIFrame {IFRAME} at (0,20) size 304x154 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x150
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 300x150
+      LayoutNGBlockFlow {HTML} at (0,0) size 300x150
+        LayoutNGBlockFlow {BODY} at (8,8) size 284x134
+layer at (8,207) size 300x150
+  LayoutIFrame {IFRAME} at (0,199) size 300x150
+    layer at (0,0) size 300x150
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 300x150
+      LayoutNGBlockFlow {HTML} at (0,0) size 300x150
+        LayoutNGBlockFlow {BODY} at (8,8) size 284x134
+layer at (8,382) size 304x154
+  LayoutIFrame {IFRAME} at (0,374) size 304x154 [border: (2px inset #EEEEEE)]
+    layer at (0,0) size 300x150
+      LayoutView at (0,0) size 300x150
+    layer at (0,0) size 300x150
+      LayoutNGBlockFlow {HTML} at (0,0) size 300x150
+        LayoutNGBlockFlow {BODY} at (8,8) size 284x134
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/parser/001-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/parser/001-expected.txt
new file mode 100644
index 0000000..f23ae24
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/parser/001-expected.txt
@@ -0,0 +1,43 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x583
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x583
+    LayoutNGBlockFlow {BODY} at (8,16) size 784x559
+      LayoutNGBlockFlow {DIR} at (0,0) size 784x112
+        LayoutNGBlockFlow (anonymous) at (40,0) size 744x20
+          LayoutText {#text} at (0,0) size 27x19
+            text run at (0,0) width 27: "One"
+        LayoutNGBlockFlow {DIR} at (40,36) size 744x76
+          LayoutNGBlockFlow (anonymous) at (40,0) size 704x20
+            LayoutText {#text} at (0,0) size 29x19
+              text run at (0,0) width 29: "Two"
+          LayoutNGBlockFlow {DIR} at (40,36) size 704x40
+            LayoutNGBlockFlow (anonymous) at (40,0) size 664x20
+              LayoutText {#text} at (0,0) size 37x19
+                text run at (0,0) width 37: "Three"
+            LayoutNGBlockFlow {CENTER} at (40,20) size 664x20
+              LayoutText {#text} at (317,0) size 30x19
+                text run at (317,0) width 30: "Four"
+      LayoutNGBlockFlow {PRE} at (0,128) size 784x336
+        LayoutText {#text} at (0,0) size 64x16
+          text run at (0,0) width 64: "Pre text"
+          text run at (64,0) width 0: " "
+        LayoutText {#text} at (300,304) size 104x16
+          text run at (300,304) width 0: " "
+          text run at (0,320) width 104: "Also pre text"
+          text run at (104,320) width 0: " "
+      LayoutNGBlockFlow (anonymous) at (0,477) size 784x20
+        LayoutInline {NOBR} at (0,0) size 137x19 [bgcolor=#CCCCCC]
+          LayoutText {#text} at (0,0) size 137x19
+            text run at (0,0) width 137: "This text won't break."
+      LayoutNGBlockFlow (anonymous) at (0,510) size 784x16
+        LayoutNGBlockFlow {PRE} at (0,0) size 784x16
+          LayoutText {#text} at (0,0) size 208x16
+            text run at (0,0) width 208: "This will be preformatted."
+      LayoutNGBlockFlow (anonymous) at (0,539) size 784x20
+        LayoutInline {NOBR} at (0,0) size 234x19 [bgcolor=#CCCCCC]
+          LayoutText {#text} at (0,0) size 234x19
+            text run at (0,0) width 234: "Now we're back to nonbreaking text."
+        LayoutText {#text} at (0,0) size 0x0
+layer at (8,160) size 300x300
+  LayoutEmbeddedObject {OBJECT} at (0,16) size 300x300 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/as-border-image/svg-as-border-image-2-expected.txt
new file mode 100644
index 0000000..afb01f6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x600
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x584
+      LayoutNGBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutNGBlockFlow {H2} at (1,20.91) size 364x27
+          LayoutText {#text} at (0,0) size 195x26
+            text run at (0,0) width 195: "SVG border-image"
+        LayoutNGBlockFlow (anonymous) at (1,67.81) size 364x370
+          LayoutNGBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,165) size 4x19
+            text run at (180,165) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
+          LayoutBR {BR} at (364,165) size 0x0
+          LayoutNGBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,350) size 4x19
+            text run at (180,350) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (0,0) size 0x0
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutNGBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutNGBlockFlow {H2} at (1,20.91) size 364x27
+          LayoutText {#text} at (0,0) size 197x26
+            text run at (0,0) width 197: "PNG border-image"
+        LayoutNGBlockFlow (anonymous) at (1,67.81) size 364x370
+          LayoutNGBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,165) size 4x19
+            text run at (180,165) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
+          LayoutBR {BR} at (364,165) size 0x0
+          LayoutNGBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,350) size 4x19
+            text run at (180,350) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (0,0) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/as-border-image/svg-as-border-image-expected.txt
new file mode 100644
index 0000000..afb01f6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/svg/as-border-image/svg-as-border-image-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  LayoutNGBlockFlow {HTML} at (0,0) size 800x600
+    LayoutNGBlockFlow {BODY} at (8,8) size 784x584
+      LayoutNGBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutNGBlockFlow {H2} at (1,20.91) size 364x27
+          LayoutText {#text} at (0,0) size 195x26
+            text run at (0,0) width 195: "SVG border-image"
+        LayoutNGBlockFlow (anonymous) at (1,67.81) size 364x370
+          LayoutNGBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,165) size 4x19
+            text run at (180,165) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
+          LayoutBR {BR} at (364,165) size 0x0
+          LayoutNGBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,350) size 4x19
+            text run at (180,350) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (0,0) size 0x0
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutNGBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutNGBlockFlow {H2} at (1,20.91) size 364x27
+          LayoutText {#text} at (0,0) size 197x26
+            text run at (0,0) width 197: "PNG border-image"
+        LayoutNGBlockFlow (anonymous) at (1,67.81) size 364x370
+          LayoutNGBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,165) size 4x19
+            text run at (180,165) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
+          LayoutBR {BR} at (364,165) size 0x0
+          LayoutNGBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (180,350) size 4x19
+            text run at (180,350) width 4: " "
+          LayoutNGBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
+          LayoutText {#text} at (0,0) size 0x0
+      LayoutText {#text} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html
index a063a8b..78e1904 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html
@@ -118,13 +118,6 @@
 
 promise_test(t => {
   mockAuthenticator.setAuthenticatorStatus(
-      webauth.mojom.AuthenticatorStatus.AUTHENTICATOR_CRITERIA_UNSUPPORTED);
-  return promise_rejects(t, "NotSupportedError",
-      navigator.credentials.create({ publicKey : MAKE_CREDENTIAL_OPTIONS}));
-}, "Verify that authenticator criteria unsupported error returned by mock is properly handled.");
-
-promise_test(t => {
-  mockAuthenticator.setAuthenticatorStatus(
       webauth.mojom.AuthenticatorStatus.ALGORITHM_UNSUPPORTED);
   return promise_rejects(t, "NotSupportedError",
       navigator.credentials.create({ publicKey : MAKE_CREDENTIAL_OPTIONS}));
@@ -205,7 +198,7 @@
 promise_test(t => {
   mockAuthenticator.reset();
   mockAuthenticator.setAuthenticatorStatus(
-      webauth.mojom.AuthenticatorStatus.AUTHENTICATOR_CRITERIA_UNSUPPORTED);
+      webauth.mojom.AuthenticatorStatus.EMPTY_ALLOW_CREDENTIALS);
   var customMakeCredOptions = deepCopy(MAKE_CREDENTIAL_OPTIONS);
   return promise_rejects(t, "NotSupportedError",
       navigator.credentials.create({publicKey: customMakeCredOptions}));
@@ -214,7 +207,7 @@
 promise_test(t => {
   mockAuthenticator.reset();
   mockAuthenticator.setAuthenticatorStatus(
-      webauth.mojom.AuthenticatorStatus.AUTHENTICATOR_CRITERIA_UNSUPPORTED);
+      webauth.mojom.AuthenticatorStatus.USER_VERIFICATION_UNSUPPORTED);
   var customMakeCredOptions = deepCopy(MAKE_CREDENTIAL_OPTIONS);
   customMakeCredOptions.authenticatorSelection.userVerification = 'required';
   return promise_rejects(t, "NotSupportedError",
@@ -234,7 +227,7 @@
 promise_test(t => {
   mockAuthenticator.reset();
   mockAuthenticator.setAuthenticatorStatus(
-      webauth.mojom.AuthenticatorStatus.AUTHENTICATOR_CRITERIA_UNSUPPORTED);
+      webauth.mojom.AuthenticatorStatus.USER_VERIFICATION_UNSUPPORTED);
   var customMakeCredOptions = deepCopy(MAKE_CREDENTIAL_OPTIONS);
   customMakeCredOptions.authenticatorSelection.authenticatorAttachment = 'platform';
   return promise_rejects(t, "NotSupportedError",
diff --git a/third_party/WebKit/LayoutTests/http/tests/usb/insecure-context.html b/third_party/WebKit/LayoutTests/http/tests/usb/insecure-context.html
deleted file mode 100644
index 06afc29e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/usb/insecure-context.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js"></script>
-<script>
-'use strict';
-
-if (window.location.origin != get_host_info().UNAUTHENTICATED_ORIGIN) {
-  window.location = get_host_info().UNAUTHENTICATED_ORIGIN +
-                    window.location.pathname;
-} else {
-  test(t => {
-    assert_false(window.isSecureContext);
-    assert_true(navigator.usb == undefined);
-  }, 'navigator.usb is not present in an insecure context');
-}
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/frame-with-insecure-xhr.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/frame-with-insecure-xhr.html
deleted file mode 100644
index 18bcf9d..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/resources/frame-with-insecure-xhr.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!DOCTYPE html>
-<script src="insecure-xhr.js"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/resources/frame-with-insecure-xhr.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/resources/frame-with-insecure-xhr.html
deleted file mode 100644
index 7048e2c2..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/resources/frame-with-insecure-xhr.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<script>
-var w = new Worker("/xmlhttprequest/resources/insecure-xhr.js");
-w.onmessage = function (e) {
-    if (window.opener)
-        window.opener.postMessage(e.data, '*');
-};
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security-expected.txt
deleted file mode 100644
index d6af8fc..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-CONSOLE MESSAGE: line 11: PASS: Origin: <missing>
-Test that disabling web security permits cross-origin XMLHttpRequest requests from a Worker.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html
deleted file mode 100644
index 5e52349..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/xmlhttprequest-allowed-with-disabled-web-security.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="/js-test-resources/js-test.js"></script>
-</head>
-<body>
-<script>
-description("Test that disabling web security permits cross-origin XMLHttpRequest requests from a Worker.");
-
-window.jsTestIsAsync = true;
-
-if (window.testRunner) {
-    testRunner.waitUntilDone();
-    testRunner.dumpAsText();
-    testRunner.setCanOpenWindows();
-    testRunner.setCloseRemainingWindowsWhenComplete(true);
-    testRunner.overridePreference("WebKitWebSecurityEnabled", false);
-}
-
-window.addEventListener("message", function (e) {
-    finishJSTest();
-}, false);
-
-window.open("resources/frame-with-insecure-xhr.html");
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security-expected.txt
deleted file mode 100644
index e5795da..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-CONSOLE MESSAGE: line 11: PASS: Origin: <missing>
-Test that disabling web security permits cross-origin XMLHttpRequest requests.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security.html
deleted file mode 100644
index 91f1713..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-allowed-with-disabled-web-security.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="/js-test-resources/js-test.js"></script>
-</head>
-<body>
-<script>
-description("Test that disabling web security permits cross-origin XMLHttpRequest requests.");
-
-window.jsTestIsAsync = true;
-
-if (window.testRunner) {
-    testRunner.waitUntilDone();
-    testRunner.dumpAsText();
-    testRunner.setCanOpenWindows();
-    testRunner.setCloseRemainingWindowsWhenComplete(true);
-    testRunner.overridePreference("WebKitWebSecurityEnabled", false);
-}
-
-window.addEventListener("message", function (e) {
-    window.win.close();
-    finishJSTest();
-}, false);
-
-window.win = window.open("resources/frame-with-insecure-xhr.html");
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png
index 0dd049d..aee31e9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-fixed-scrolling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png
index 7a93399..afe0a12f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/geometry/video-opacity-overlay-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.txt
index 391908c..11767590 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/css1/box_properties/float_on_text_elements-expected.txt
@@ -26,7 +26,7 @@
         LayoutImage {IMG} at (0,80) size 15x15
         LayoutText {#text} at (15,80) size 4x19
           text run at (15,80) width 4: " "
-        LayoutBR {BR} at (19,95) size 0x0
+        LayoutBR {BR} at (19,80) size 0x19
       LayoutBlockFlow (anonymous) at (0,256) size 769x120
         LayoutBlockFlow (floating) {P} at (0,0) size 384.50x120 [bgcolor=#FFFF00]
           LayoutText {#text} at (0,0) size 384x119
@@ -39,7 +39,7 @@
         LayoutImage {IMG} at (384.50,0) size 15x15
         LayoutText {#text} at (399,0) size 5x19
           text run at (399,0) width 5: " "
-        LayoutBR {BR} at (403,15) size 1x0
+        LayoutBR {BR} at (403,0) size 1x19
       LayoutBlockFlow (anonymous) at (0,394) size 769x120
         LayoutBlockFlow (floating) {P} at (384.50,0) size 384.50x120 [bgcolor=#FFFF00]
           LayoutText {#text} at (0,0) size 384x119
@@ -52,7 +52,7 @@
         LayoutImage {IMG} at (0,0) size 15x15
         LayoutText {#text} at (15,0) size 4x19
           text run at (15,0) width 4: " "
-        LayoutBR {BR} at (19,15) size 0x0
+        LayoutBR {BR} at (19,0) size 0x19
       LayoutBlockFlow {P} at (0,532) size 769x60
         LayoutBlockFlow (floating) {SPAN} at (0,0) size 48x37 [bgcolor=#C0C0C0]
           LayoutText {#text} at (0,0) size 21x36
@@ -195,7 +195,7 @@
                 LayoutImage {IMG} at (0,80) size 15x15
                 LayoutText {#text} at (15,80) size 4x19
                   text run at (15,80) width 4: " "
-                LayoutBR {BR} at (19,95) size 0x0
+                LayoutBR {BR} at (19,80) size 0x19
               LayoutBlockFlow (anonymous) at (4,260) size 747x120
                 LayoutBlockFlow (floating) {P} at (0,0) size 373.50x120 [bgcolor=#FFFF00]
                   LayoutText {#text} at (0,0) size 373x119
@@ -208,7 +208,7 @@
                 LayoutImage {IMG} at (373.50,0) size 15x15
                 LayoutText {#text} at (388,0) size 5x19
                   text run at (388,0) width 5: " "
-                LayoutBR {BR} at (392,15) size 1x0
+                LayoutBR {BR} at (392,0) size 1x19
               LayoutBlockFlow (anonymous) at (4,398) size 747x120
                 LayoutBlockFlow (floating) {P} at (373.50,0) size 373.50x120 [bgcolor=#FFFF00]
                   LayoutText {#text} at (0,0) size 373x119
@@ -221,7 +221,7 @@
                 LayoutImage {IMG} at (0,0) size 15x15
                 LayoutText {#text} at (15,0) size 4x19
                   text run at (15,0) width 4: " "
-                LayoutBR {BR} at (19,15) size 0x0
+                LayoutBR {BR} at (19,0) size 0x19
               LayoutBlockFlow {P} at (4,536) size 747x60
                 LayoutBlockFlow (floating) {SPAN} at (0,0) size 48x37 [bgcolor=#C0C0C0]
                   LayoutText {#text} at (0,0) size 21x36
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/select-initial-position-expected.txt
index c396e62..0382ada6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/select-initial-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/select-initial-position-expected.txt
@@ -1,49 +1,49 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x409
+  LayoutBlockFlow {HTML} at (0,0) size 800x409
+    LayoutBlockFlow {BODY} at (8,8) size 784x393
       LayoutText {#text} at (0,0) size 93x19
         text run at (0,0) width 93: "initial selected:"
-      LayoutBR {BR} at (93,15) size 0x0
+      LayoutBR {BR} at (93,0) size 0x19
       LayoutText {#text} at (155,71) size 4x19
         text run at (155,71) width 4: " "
-      LayoutBR {BR} at (159,86) size 0x0
+      LayoutBR {BR} at (159,71) size 0x19
       LayoutText {#text} at (0,91) size 161x19
         text run at (0,91) width 161: "dynamic selected change:"
-      LayoutBR {BR} at (161,106) size 0x0
+      LayoutBR {BR} at (161,91) size 0x19
       LayoutText {#text} at (155,162) size 4x19
         text run at (155,162) width 4: " "
-      LayoutBR {BR} at (159,177) size 0x0
+      LayoutBR {BR} at (159,162) size 0x19
       LayoutText {#text} at (0,182) size 211x19
         text run at (0,182) width 211: "dynamic insert of selected option:"
-      LayoutBR {BR} at (211,197) size 0x0
+      LayoutBR {BR} at (211,182) size 0x19
       LayoutText {#text} at (155,253) size 4x19
         text run at (155,253) width 4: " "
-      LayoutBR {BR} at (159,268) size 0x0
+      LayoutBR {BR} at (159,253) size 0x19
       LayoutText {#text} at (0,273) size 93x19
         text run at (0,273) width 93: "initial selected:"
-      LayoutBR {BR} at (93,288) size 0x0
+      LayoutBR {BR} at (93,273) size 0x19
       LayoutMenuList {SELECT} at (0,293) size 156x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 154x18
           LayoutText (anonymous) at (4,1) size 134x16
             text run at (4,1) width 134: "this should be selected"
       LayoutText {#text} at (156,293) size 4x19
         text run at (156,293) width 4: " "
-      LayoutBR {BR} at (160,308) size 0x0
+      LayoutBR {BR} at (160,293) size 0x19
       LayoutText {#text} at (0,313) size 161x19
         text run at (0,313) width 161: "dynamic selected change:"
-      LayoutBR {BR} at (161,328) size 0x0
+      LayoutBR {BR} at (161,313) size 0x19
       LayoutMenuList {SELECT} at (0,333) size 156x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 154x18
           LayoutText (anonymous) at (4,1) size 134x16
             text run at (4,1) width 134: "this should be selected"
       LayoutText {#text} at (156,333) size 4x19
         text run at (156,333) width 4: " "
-      LayoutBR {BR} at (160,348) size 0x0
+      LayoutBR {BR} at (160,333) size 0x19
       LayoutText {#text} at (0,353) size 211x19
         text run at (0,353) width 211: "dynamic insert of selected option:"
-      LayoutBR {BR} at (211,368) size 0x0
+      LayoutBR {BR} at (211,353) size 0x19
       LayoutMenuList {SELECT} at (0,373) size 156x20 [bgcolor=#C0C0C0] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 154x18
           LayoutText (anonymous) at (4,1) size 134x16
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/frames/iframe-with-frameborder-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/frames/iframe-with-frameborder-expected.txt
index d2737013..775c4391 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/frames/iframe-with-frameborder-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/frames/iframe-with-frameborder-expected.txt
@@ -1,23 +1,23 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x549
+  LayoutBlockFlow {HTML} at (0,0) size 800x549
+    LayoutBlockFlow {BODY} at (8,8) size 784x533
       LayoutText {#text} at (0,0) size 211x19
         text run at (0,0) width 211: "This iframe should have a border."
-      LayoutBR {BR} at (211,15) size 0x0
+      LayoutBR {BR} at (211,0) size 0x19
       LayoutText {#text} at (304,159) size 4x19
         text run at (304,159) width 4: " "
       LayoutBR {BR} at (0,0) size 0x0
       LayoutText {#text} at (0,179) size 146x19
         text run at (0,179) width 146: "This iframe should not."
-      LayoutBR {BR} at (146,194) size 0x0
+      LayoutBR {BR} at (146,179) size 0x19
       LayoutText {#text} at (300,334) size 4x19
         text run at (300,334) width 4: " "
-      LayoutBR {BR} at (304,349) size 0x0
+      LayoutBR {BR} at (304,334) size 0x19
       LayoutText {#text} at (0,354) size 215x19
         text run at (0,354) width 215: "This iframe should have a border. "
-      LayoutBR {BR} at (215,369) size 0x0
+      LayoutBR {BR} at (215,354) size 0x19
       LayoutText {#text} at (0,0) size 0x0
 layer at (8,28) size 304x154
   LayoutIFrame {IFRAME} at (0,20) size 304x154 [border: (2px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.png
index fc002793..546483b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.txt
index 7f45351c..05359e4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/parser/001-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x583
+  LayoutBlockFlow {HTML} at (0,0) size 800x583
+    LayoutBlockFlow {BODY} at (8,16) size 784x559
       LayoutBlockFlow {DIR} at (0,0) size 784x112
         LayoutBlockFlow (anonymous) at (40,0) size 744x20
           LayoutText {#text} at (0,0) size 27x19
@@ -39,5 +39,5 @@
           LayoutText {#text} at (0,0) size 234x19
             text run at (0,0) width 234: "Now we're back to nonbreaking text."
         LayoutText {#text} at (0,0) size 0x0
-layer at (8,152) size 300x300
+layer at (8,160) size 300x300
   LayoutEmbeddedObject {OBJECT} at (0,16) size 300x300 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index c6fa676..60f5a79 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.png
index 5ca7612..edfe5321 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/dynamic-descendant-percentage-height-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/dynamic-descendant-percentage-height-expected.png
index 1a714328..c173a48 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/dynamic-descendant-percentage-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/dynamic-descendant-percentage-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png
index 85f6436..e531dd0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
index cb7001e..8a2e016 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 197x26
             text run at (0,0) width 197: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
index 659d31bc..d80f7c8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
index cb7001e..8a2e016 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 197x26
             text run at (0,0) width 197: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.png
index 8fb6bc84..7951722 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.txt
index 85ee655..dc93c4f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/select-initial-position-expected.txt
@@ -1,50 +1,50 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x357
+  LayoutBlockFlow {HTML} at (0,0) size 800x357.25
+    LayoutBlockFlow {BODY} at (8,8) size 784x341.25
       LayoutText {#text} at (0,0) size 98x18
         text run at (0,0) width 98: "initial selected:"
-      LayoutBR {BR} at (97,14) size 1x0
+      LayoutBR {BR} at (97,0) size 1x18
       LayoutText {#text} at (132,58) size 5x19
         text run at (132,58) width 5: " "
-      LayoutBR {BR} at (136,72) size 1x1
+      LayoutBR {BR} at (136,58) size 1x19
       LayoutText {#text} at (0,76) size 165x19
         text run at (0,76) width 165: "dynamic selected change:"
-      LayoutBR {BR} at (164,90) size 1x1
+      LayoutBR {BR} at (164,76) size 1x19
       LayoutText {#text} at (132,135) size 5x19
         text run at (132,135) width 5: " "
-      LayoutBR {BR} at (136,149) size 1x1
+      LayoutBR {BR} at (136,135) size 1x19
       LayoutText {#text} at (0,153) size 217x19
         text run at (0,153) width 217: "dynamic insert of selected option:"
-      LayoutBR {BR} at (216,167) size 1x1
+      LayoutBR {BR} at (216,153) size 1x19
       LayoutText {#text} at (132,212) size 5x19
         text run at (132,212) width 5: " "
-      LayoutBR {BR} at (136,226) size 1x1
+      LayoutBR {BR} at (136,212) size 1x19
       LayoutText {#text} at (0,230) size 98x19
         text run at (0,230) width 98: "initial selected:"
-      LayoutBR {BR} at (97,244) size 1x1
+      LayoutBR {BR} at (97,230) size 1x19
       LayoutMenuList {SELECT} at (0,249.25) size 147x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 147x18
           LayoutText (anonymous) at (8,2) size 116x13
             text run at (8,2) width 116: "this should be selected"
       LayoutText {#text} at (147,248) size 4x19
         text run at (147,248) width 4: " "
-      LayoutBR {BR} at (151,262) size 0x1
+      LayoutBR {BR} at (151,248) size 0x19
       LayoutText {#text} at (0,267) size 165x19
         text run at (0,267) width 165: "dynamic selected change:"
-      LayoutBR {BR} at (164,281) size 1x1
+      LayoutBR {BR} at (164,267) size 1x19
       LayoutMenuList {SELECT} at (0,286.25) size 147x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 147x18
           LayoutText (anonymous) at (8,2) size 116x13
             text run at (8,2) width 116: "this should be selected"
       LayoutText {#text} at (147,285) size 4x19
         text run at (147,285) width 4: " "
-      LayoutBR {BR} at (151,299) size 0x1
+      LayoutBR {BR} at (151,285) size 0x19
       LayoutText {#text} at (0,304) size 217x19
         text run at (0,304) width 217: "dynamic insert of selected option:"
-      LayoutBR {BR} at (216,318) size 1x1
-      LayoutMenuList {SELECT} at (0,322.25) size 147x18 [bgcolor=#F8F8F8]
+      LayoutBR {BR} at (216,304) size 1x19
+      LayoutMenuList {SELECT} at (0,323.25) size 147x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 147x18
           LayoutText (anonymous) at (8,2) size 116x13
             text run at (8,2) width 116: "this should be selected"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/parser/001-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/parser/001-expected.png
index 2c12743..8aae02db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/parser/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/parser/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index 638aece..01cb8d5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-expected.png
index 677d815..8f7ccea5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
new file mode 100644
index 0000000..b4d9e25f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
@@ -0,0 +1,49 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [ref-distance-error] 
+FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
+PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
+FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.refDistance = 0 did not throw an exception.
+PASS   panner.refDistance = 5e-324 did not throw an exception.
+FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [max-distance-error] 
+FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
+FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.maxDistance = 5e-324 did not throw an exception.
+FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [min-distance] 
+PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS < [min-distance] All assertions passed. (total 12 assertions)
+PASS > [max-distance] 
+PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351098328828812,0.23690398037433624,-0.11514916270971298,-0.20979724824428558,-0.012793892063200474,0.021439947187900543,0.2256566733121872,0.07854988425970078,-0.24533408880233765,-0.08270072191953659,0.0001093835016945377,0.12551122903823853,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
+PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.0014285872457548976,0.0032695855479687452,-0.0015892094234004617,-0.002895476995036006,-0.0001765724882716313,0.000295899371849373,0.0031143580563366413,0.0010840913746505976,-0.003385932184755802,-0.0011413784231990576,0.0000015096356946742162,0.0017322194762527943,0.0030744909308850765,-0.002051546471193433,-0.002635899931192398...].
+PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001128410105594,0.000041198902181349695,-0.000020025070625706576,-0.000036484892916632816,-0.00000222492803914065,0.0000037285244616214186,0.000039242931961780414,0.00001366025571769569,-0.00004266494215698913,-0.000014382108929567039,1.902239077367085e-8,0.000021827090677106753,0.00003874058529618196,-0.00002585081892902963,-0.000033214051654795185...].
+PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351098328828812,0.23690398037433624,-0.11514916270971298,-0.20979724824428558,-0.012793892063200474,0.021439947187900543,0.2256566733121872,0.07854988425970078,-0.24533408880233765,-0.08270072191953659,0.0001093835016945377,0.12551122903823853,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
+PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.009258303791284561,0.021189337596297264,-0.010299254208803177,-0.018764836713671684,-0.0011443205876275897,0.001917647197842598,0.020183347165584564,0.007025715429335833,-0.021943349391222,-0.007396977860480547,0.00000978355819825083,0.011226066388189793,0.019924979656934738,-0.013295541517436504,-0.017082585021853447...].
+PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264349889941514,0.0018914489774033427,-0.0009193546138703823,-0.0016750278882682323,-0.00010214684152742848,0.000171177220181562,0.0018016500398516655,0.0006271447637118399,-0.001958755310624838,-0.0006602851790376008,8.733213689993136e-7,0.0010020856279879808,0.0017785871168598533,-0.0011868156725540757,-0.0015248629497364163...].
+PASS < [max-distance] All assertions passed. (total 12 assertions)
+FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.png
index 519c79b..28230db 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.txt
index 6e529e4..378ed9d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/forms/select/select-initial-position-expected.txt
@@ -1,50 +1,50 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x357
+  LayoutBlockFlow {HTML} at (0,0) size 800x357.25
+    LayoutBlockFlow {BODY} at (8,8) size 784x341.25
       LayoutText {#text} at (0,0) size 98x18
         text run at (0,0) width 98: "initial selected:"
-      LayoutBR {BR} at (97,14) size 1x0
+      LayoutBR {BR} at (97,0) size 1x18
       LayoutText {#text} at (137,58) size 5x19
         text run at (137,58) width 5: " "
-      LayoutBR {BR} at (141,72) size 1x1
+      LayoutBR {BR} at (141,58) size 1x19
       LayoutText {#text} at (0,76) size 165x19
         text run at (0,76) width 165: "dynamic selected change:"
-      LayoutBR {BR} at (164,90) size 1x1
+      LayoutBR {BR} at (164,76) size 1x19
       LayoutText {#text} at (137,135) size 5x19
         text run at (137,135) width 5: " "
-      LayoutBR {BR} at (141,149) size 1x1
+      LayoutBR {BR} at (141,135) size 1x19
       LayoutText {#text} at (0,153) size 217x19
         text run at (0,153) width 217: "dynamic insert of selected option:"
-      LayoutBR {BR} at (216,167) size 1x1
+      LayoutBR {BR} at (216,153) size 1x19
       LayoutText {#text} at (137,212) size 5x19
         text run at (137,212) width 5: " "
-      LayoutBR {BR} at (141,226) size 1x1
+      LayoutBR {BR} at (141,212) size 1x19
       LayoutText {#text} at (0,230) size 98x19
         text run at (0,230) width 98: "initial selected:"
-      LayoutBR {BR} at (97,244) size 1x1
+      LayoutBR {BR} at (97,230) size 1x19
       LayoutMenuList {SELECT} at (0,249.25) size 152x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 152x18
           LayoutText (anonymous) at (8,2) size 121x13
             text run at (8,2) width 121: "this should be selected"
       LayoutText {#text} at (152,248) size 4x19
         text run at (152,248) width 4: " "
-      LayoutBR {BR} at (156,262) size 0x1
+      LayoutBR {BR} at (156,248) size 0x19
       LayoutText {#text} at (0,267) size 165x19
         text run at (0,267) width 165: "dynamic selected change:"
-      LayoutBR {BR} at (164,281) size 1x1
+      LayoutBR {BR} at (164,267) size 1x19
       LayoutMenuList {SELECT} at (0,286.25) size 152x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 152x18
           LayoutText (anonymous) at (8,2) size 121x13
             text run at (8,2) width 121: "this should be selected"
       LayoutText {#text} at (152,285) size 4x19
         text run at (152,285) width 4: " "
-      LayoutBR {BR} at (156,299) size 0x1
+      LayoutBR {BR} at (156,285) size 0x19
       LayoutText {#text} at (0,304) size 217x19
         text run at (0,304) width 217: "dynamic insert of selected option:"
-      LayoutBR {BR} at (216,318) size 1x1
-      LayoutMenuList {SELECT} at (0,322.25) size 152x18 [bgcolor=#F8F8F8]
+      LayoutBR {BR} at (216,304) size 1x19
+      LayoutMenuList {SELECT} at (0,323.25) size 152x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 152x18
           LayoutText (anonymous) at (8,2) size 121x13
             text run at (8,2) width 121: "this should be selected"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index 4f55549..16af7aab 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-expected.png
index 26381287..69282d2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-2-expected.png
index d7605218..a356e5c1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-expected.png
index e248e4f8..e7d160b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/video-fixed-scrolling-expected.png
new file mode 100644
index 0000000..ddbbda9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/video-fixed-scrolling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/video-opacity-overlay-expected.png
new file mode 100644
index 0000000..1e784e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/geometry/video-opacity-overlay-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/visibility/visibility-simple-video-layer-expected.png
new file mode 100644
index 0000000..a5e147f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/compositing/visibility/visibility-simple-video-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
new file mode 100644
index 0000000..b4d9e25f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
@@ -0,0 +1,49 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [ref-distance-error] 
+FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
+PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
+FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.refDistance = 0 did not throw an exception.
+PASS   panner.refDistance = 5e-324 did not throw an exception.
+FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [max-distance-error] 
+FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
+FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.maxDistance = 5e-324 did not throw an exception.
+FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [min-distance] 
+PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702196657657623,0.4738079607486725,-0.23029832541942596,-0.41959449648857117,-0.025587784126400948,0.042879894375801086,0.4513133466243744,0.15709976851940155,-0.4906681776046753,-0.16540144383907318,0.0002187670033890754,0.25102245807647705,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS < [min-distance] All assertions passed. (total 12 assertions)
+PASS > [max-distance] 
+PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351098328828812,0.23690398037433624,-0.11514916270971298,-0.20979724824428558,-0.012793892063200474,0.021439947187900543,0.2256566733121872,0.07854988425970078,-0.24533408880233765,-0.08270072191953659,0.0001093835016945377,0.12551122903823853,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
+PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.0014285872457548976,0.0032695855479687452,-0.0015892094234004617,-0.002895476995036006,-0.0001765724882716313,0.000295899371849373,0.0031143580563366413,0.0010840913746505976,-0.003385932184755802,-0.0011413784231990576,0.0000015096356946742162,0.0017322194762527943,0.0030744909308850765,-0.002051546471193433,-0.002635899931192398...].
+PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001128410105594,0.000041198902181349695,-0.000020025070625706576,-0.000036484892916632816,-0.00000222492803914065,0.0000037285244616214186,0.000039242931961780414,0.00001366025571769569,-0.00004266494215698913,-0.000014382108929567039,1.902239077367085e-8,0.000021827090677106753,0.00003874058529618196,-0.00002585081892902963,-0.000033214051654795185...].
+PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351098328828812,0.23690398037433624,-0.11514916270971298,-0.20979724824428558,-0.012793892063200474,0.021439947187900543,0.2256566733121872,0.07854988425970078,-0.24533408880233765,-0.08270072191953659,0.0001093835016945377,0.12551122903823853,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
+PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.009258303791284561,0.021189337596297264,-0.010299254208803177,-0.018764836713671684,-0.0011443205876275897,0.001917647197842598,0.020183347165584564,0.007025715429335833,-0.021943349391222,-0.007396977860480547,0.00000978355819825083,0.011226066388189793,0.019924979656934738,-0.013295541517436504,-0.017082585021853447...].
+PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264349889941514,0.0018914489774033427,-0.0009193546138703823,-0.0016750278882682323,-0.00010214684152742848,0.000171177220181562,0.0018016500398516655,0.0006271447637118399,-0.001958755310624838,-0.0006602851790376008,8.733213689993136e-7,0.0010020856279879808,0.0017785871168598533,-0.0011868156725540757,-0.0015248629497364163...].
+PASS < [max-distance] All assertions passed. (total 12 assertions)
+FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-initial-position-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-initial-position-expected.png
new file mode 100644
index 0000000..7951722
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-initial-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-initial-position-expected.txt
new file mode 100644
index 0000000..dc93c4f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/forms/select/select-initial-position-expected.txt
@@ -0,0 +1,165 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x357
+  LayoutBlockFlow {HTML} at (0,0) size 800x357.25
+    LayoutBlockFlow {BODY} at (8,8) size 784x341.25
+      LayoutText {#text} at (0,0) size 98x18
+        text run at (0,0) width 98: "initial selected:"
+      LayoutBR {BR} at (97,0) size 1x18
+      LayoutText {#text} at (132,58) size 5x19
+        text run at (132,58) width 5: " "
+      LayoutBR {BR} at (136,58) size 1x19
+      LayoutText {#text} at (0,76) size 165x19
+        text run at (0,76) width 165: "dynamic selected change:"
+      LayoutBR {BR} at (164,76) size 1x19
+      LayoutText {#text} at (132,135) size 5x19
+        text run at (132,135) width 5: " "
+      LayoutBR {BR} at (136,135) size 1x19
+      LayoutText {#text} at (0,153) size 217x19
+        text run at (0,153) width 217: "dynamic insert of selected option:"
+      LayoutBR {BR} at (216,153) size 1x19
+      LayoutText {#text} at (132,212) size 5x19
+        text run at (132,212) width 5: " "
+      LayoutBR {BR} at (136,212) size 1x19
+      LayoutText {#text} at (0,230) size 98x19
+        text run at (0,230) width 98: "initial selected:"
+      LayoutBR {BR} at (97,230) size 1x19
+      LayoutMenuList {SELECT} at (0,249.25) size 147x18 [bgcolor=#F8F8F8]
+        LayoutBlockFlow (anonymous) at (0,0) size 147x18
+          LayoutText (anonymous) at (8,2) size 116x13
+            text run at (8,2) width 116: "this should be selected"
+      LayoutText {#text} at (147,248) size 4x19
+        text run at (147,248) width 4: " "
+      LayoutBR {BR} at (151,248) size 0x19
+      LayoutText {#text} at (0,267) size 165x19
+        text run at (0,267) width 165: "dynamic selected change:"
+      LayoutBR {BR} at (164,267) size 1x19
+      LayoutMenuList {SELECT} at (0,286.25) size 147x18 [bgcolor=#F8F8F8]
+        LayoutBlockFlow (anonymous) at (0,0) size 147x18
+          LayoutText (anonymous) at (8,2) size 116x13
+            text run at (8,2) width 116: "this should be selected"
+      LayoutText {#text} at (147,285) size 4x19
+        text run at (147,285) width 4: " "
+      LayoutBR {BR} at (151,285) size 0x19
+      LayoutText {#text} at (0,304) size 217x19
+        text run at (0,304) width 217: "dynamic insert of selected option:"
+      LayoutBR {BR} at (216,304) size 1x19
+      LayoutMenuList {SELECT} at (0,323.25) size 147x18 [bgcolor=#F8F8F8]
+        LayoutBlockFlow (anonymous) at (0,0) size 147x18
+          LayoutText (anonymous) at (8,2) size 116x13
+            text run at (8,2) width 116: "this should be selected"
+      LayoutText {#text} at (0,0) size 0x0
+layer at (8,26) size 133x59 clip at (9,27) size 120x57 scrollY 99.00 scrollHeight 199
+  LayoutListBox {SELECT} at (0,18) size 132.55x58.75 [bgcolor=#FFFFFF] [border: (1px solid #999999)]
+    LayoutBlockFlow {OPTION} at (1,1) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,15.19) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,29.38) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,43.56) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,57.75) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,71.94) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,86.13) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,100.31) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,114.50) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,128.69) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,142.88) size 119.55x14.19 [bgcolor=#D4D4D4]
+      LayoutText {#text} at (2,0) size 116x13
+        text run at (2,0) width 116: "this should be selected"
+    LayoutBlockFlow {OPTION} at (1,157.06) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,171.25) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,185.44) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+layer at (8,103) size 133x59 clip at (9,104) size 120x57 scrollY 99.00 scrollHeight 198
+  LayoutListBox {SELECT} at (0,94.75) size 132.55x58.75 [bgcolor=#FFFFFF] [border: (1px solid #999999)]
+    LayoutBlockFlow {OPTION} at (1,1) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,15.19) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,29.38) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,43.56) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,57.75) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,71.94) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,86.13) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,100.31) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,114.50) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,128.69) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,142.88) size 119.55x14.19 [bgcolor=#D4D4D4]
+      LayoutText {#text} at (2,0) size 116x13
+        text run at (2,0) width 116: "this should be selected"
+    LayoutBlockFlow {OPTION} at (1,157.06) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,171.25) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,185.44) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+layer at (8,180) size 133x58 clip at (9,181) size 120x56 scrollY 43.00 scrollHeight 113
+  LayoutListBox {SELECT} at (0,171.50) size 132.55x58.75 [bgcolor=#FFFFFF] [border: (1px solid #999999)]
+    LayoutBlockFlow {OPTION} at (1,1) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,15.19) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,29.38) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,43.56) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,57.75) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,71.94) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
+    LayoutBlockFlow {OPTION} at (1,86.13) size 119.55x14.19 [bgcolor=#D4D4D4]
+      LayoutText {#text} at (2,0) size 116x13
+        text run at (2,0) width 116: "this should be selected"
+    LayoutBlockFlow {OPTION} at (1,100.31) size 119.55x14.19
+      LayoutText {#text} at (2,0) size 17x13
+        text run at (2,0) width 17: "opt"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/parser/001-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/parser/001-expected.png
new file mode 100644
index 0000000..8aae02db
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/parser/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
new file mode 100644
index 0000000..01cb8d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-quirks-expected.png
new file mode 100644
index 0000000..8f7ccea5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/media/color-profile-video-seek-object-fit-expected.png
new file mode 100644
index 0000000..ed5a172f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/media/color-profile-video-seek-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.png
new file mode 100644
index 0000000..a356e5c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.png
new file mode 100644
index 0000000..e7d160b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png
new file mode 100644
index 0000000..a5e147f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/threaded/compositing/visibility/visibility-simple-video-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/video-surface-layer/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/video-surface-layer/media/color-profile-video-seek-object-fit-expected.png
new file mode 100644
index 0000000..ed5a172f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/video-surface-layer/media/color-profile-video-seek-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png
index ddbbda9..25267c40 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-fixed-scrolling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png
index 1e784e4..8f9f1ff 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/geometry/video-opacity-overlay-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png
index a5e147f..9f5fb0a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/visibility/visibility-simple-video-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css1/box_properties/float_on_text_elements-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/css1/box_properties/float_on_text_elements-expected.txt
index 0d664fd..20628d5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css1/box_properties/float_on_text_elements-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/css1/box_properties/float_on_text_elements-expected.txt
@@ -26,7 +26,7 @@
         LayoutImage {IMG} at (0,72) size 15x15
         LayoutText {#text} at (15,73) size 4x18
           text run at (15,73) width 4: " "
-        LayoutBR {BR} at (19,87) size 0x0
+        LayoutBR {BR} at (19,73) size 0x18
       LayoutBlockFlow (anonymous) at (0,235) size 769x108
         LayoutBlockFlow (floating) {P} at (0,0) size 384.50x108 [bgcolor=#FFFF00]
           LayoutText {#text} at (0,0) size 385x108
@@ -39,7 +39,7 @@
         LayoutImage {IMG} at (384.50,0) size 15x15
         LayoutText {#text} at (399,1) size 5x18
           text run at (399,1) width 5: " "
-        LayoutBR {BR} at (403,15) size 1x0
+        LayoutBR {BR} at (403,1) size 1x18
       LayoutBlockFlow (anonymous) at (0,361) size 769x108
         LayoutBlockFlow (floating) {P} at (384.50,0) size 384.50x108 [bgcolor=#FFFF00]
           LayoutText {#text} at (0,0) size 385x108
@@ -52,7 +52,7 @@
         LayoutImage {IMG} at (0,0) size 15x15
         LayoutText {#text} at (15,1) size 4x18
           text run at (15,1) width 4: " "
-        LayoutBR {BR} at (19,15) size 0x0
+        LayoutBR {BR} at (19,1) size 0x18
       LayoutBlockFlow {P} at (0,487) size 769x72
         LayoutBlockFlow (floating) {SPAN} at (0,0) size 48x37 [bgcolor=#C0C0C0]
           LayoutText {#text} at (0,0) size 22x37
@@ -199,7 +199,7 @@
                 LayoutImage {IMG} at (0,72) size 15x15
                 LayoutText {#text} at (15,73) size 4x18
                   text run at (15,73) width 4: " "
-                LayoutBR {BR} at (19,87) size 0x0
+                LayoutBR {BR} at (19,73) size 0x18
               LayoutBlockFlow (anonymous) at (4,239) size 747x108
                 LayoutBlockFlow (floating) {P} at (0,0) size 373.50x108 [bgcolor=#FFFF00]
                   LayoutText {#text} at (0,0) size 374x108
@@ -212,7 +212,7 @@
                 LayoutImage {IMG} at (373.50,0) size 15x15
                 LayoutText {#text} at (388,1) size 5x18
                   text run at (388,1) width 5: " "
-                LayoutBR {BR} at (392,15) size 1x0
+                LayoutBR {BR} at (392,1) size 1x18
               LayoutBlockFlow (anonymous) at (4,365) size 747x108
                 LayoutBlockFlow (floating) {P} at (373.50,0) size 373.50x108 [bgcolor=#FFFF00]
                   LayoutText {#text} at (0,0) size 374x108
@@ -225,7 +225,7 @@
                 LayoutImage {IMG} at (0,0) size 15x15
                 LayoutText {#text} at (15,1) size 4x18
                   text run at (15,1) width 4: " "
-                LayoutBR {BR} at (19,15) size 0x0
+                LayoutBR {BR} at (19,1) size 0x18
               LayoutBlockFlow {P} at (4,491) size 747x72
                 LayoutBlockFlow (floating) {SPAN} at (0,0) size 48x37 [bgcolor=#C0C0C0]
                   LayoutText {#text} at (0,0) size 22x37
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
new file mode 100644
index 0000000..88b87d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
@@ -0,0 +1,49 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [ref-distance-error] 
+FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
+PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
+FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.refDistance = 0 did not throw an exception.
+PASS   panner.refDistance = 5e-324 did not throw an exception.
+FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [max-distance-error] 
+FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
+FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.maxDistance = 5e-324 did not throw an exception.
+FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [min-distance] 
+PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
+PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
+PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
+PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
+PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
+PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702192187309265,0.4738078713417053,-0.23029834032058716,-0.4195944368839264,-0.025587772950530052,0.042879875749349594,0.45131322741508484,0.15709976851940155,-0.49066805839538574,-0.1654014140367508,0.00021875571110285819,0.25102242827415466,0.4455359876155853,-0.29729729890823364,-0.3819781541824341...].
+PASS < [min-distance] All assertions passed. (total 12 assertions)
+PASS > [max-distance] 
+PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351096093654633,0.23690393567085266,-0.11514917016029358,-0.2097972184419632,-0.012793886475265026,0.021439937874674797,0.22565661370754242,0.07854988425970078,-0.24533402919769287,-0.0827007070183754,0.00010937785555142909,0.12551121413707733,0.22276799380779266,-0.14864864945411682,-0.19098907709121704...].
+PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.001428587012924254,0.0032695848494768143,-0.0015892095398157835,-0.0028954767622053623,-0.00017657240096013993,0.00029589925543405116,0.0031143571250140667,0.0010840913746505976,-0.0033859312534332275,-0.001141378190368414,0.000001509557819190377,0.0017322193598374724,0.003074490465223789,-0.002051546238362789,-0.0026358996983617544...].
+PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001124772126786,0.00004119889490539208,-0.00002002507244469598,-0.0000364848856406752,-0.0000022249271296459483,0.0000037285228700056905,0.0000392429246858228,0.00001366025571769569,-0.00004266493488103151,-0.000014382106201082934,1.902140844833866e-8,0.00002182708885811735,0.00003874057802022435,-0.00002585081529105082,-0.00003321404801681638...].
+PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351096093654633,0.23690393567085266,-0.11514917016029358,-0.2097972184419632,-0.012793886475265026,0.021439937874674797,0.22565661370754242,0.07854988425970078,-0.24533402919769287,-0.0827007070183754,0.00010937785555142909,0.12551121413707733,0.22276799380779266,-0.14864864945411682,-0.19098907709121704...].
+PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.009258301928639412,0.021189333871006966,-0.010299255140125751,-0.018764834851026535,-0.0011443200055509806,0.0019176463829353452,0.020183341577649117,0.007025715429335833,-0.021943343803286552,-0.007396976463496685,0.000009783053428691346,0.011226064525544643,0.01992497593164444,-0.013295539654791355,-0.017082583159208298...].
+PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264348143711686,0.0018914486281573772,-0.0009193546720780432,-0.0016750276554375887,-0.00010214679787168279,0.00017117714742198586,0.0018016495741903782,0.0006271447637118399,-0.001958754612132907,-0.0006602850626222789,8.732762921681569e-7,0.001002085511572659,0.0017785867676138878,-0.0011868155561387539,-0.0015248628333210945...].
+PASS < [max-distance] All assertions passed. (total 12 assertions)
+FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.png
index 64aff6b..4530cca2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.txt
index 5f617d5..68eec9c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/select-initial-position-expected.txt
@@ -1,50 +1,50 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x357
+  LayoutBlockFlow {HTML} at (0,0) size 800x357.25
+    LayoutBlockFlow {BODY} at (8,8) size 784x341.25
       LayoutText {#text} at (0,0) size 98x18
         text run at (0,0) width 98: "initial selected:"
-      LayoutBR {BR} at (97,14) size 1x0
+      LayoutBR {BR} at (97,0) size 1x18
       LayoutText {#text} at (138,58) size 5x19
         text run at (138,58) width 5: " "
-      LayoutBR {BR} at (142,72) size 1x1
+      LayoutBR {BR} at (142,58) size 1x19
       LayoutText {#text} at (0,76) size 165x19
         text run at (0,76) width 165: "dynamic selected change:"
-      LayoutBR {BR} at (164,90) size 1x1
+      LayoutBR {BR} at (164,76) size 1x19
       LayoutText {#text} at (138,135) size 5x19
         text run at (138,135) width 5: " "
-      LayoutBR {BR} at (142,149) size 1x1
+      LayoutBR {BR} at (142,135) size 1x19
       LayoutText {#text} at (0,153) size 217x19
         text run at (0,153) width 217: "dynamic insert of selected option:"
-      LayoutBR {BR} at (216,167) size 1x1
+      LayoutBR {BR} at (216,153) size 1x19
       LayoutText {#text} at (138,212) size 5x19
         text run at (138,212) width 5: " "
-      LayoutBR {BR} at (142,226) size 1x1
+      LayoutBR {BR} at (142,212) size 1x19
       LayoutText {#text} at (0,230) size 98x19
         text run at (0,230) width 98: "initial selected:"
-      LayoutBR {BR} at (97,244) size 1x1
+      LayoutBR {BR} at (97,230) size 1x19
       LayoutMenuList {SELECT} at (0,249.25) size 153x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 153x18
           LayoutText (anonymous) at (8,2) size 122x13
             text run at (8,2) width 122: "this should be selected"
       LayoutText {#text} at (153,248) size 4x19
         text run at (153,248) width 4: " "
-      LayoutBR {BR} at (157,262) size 0x1
+      LayoutBR {BR} at (157,248) size 0x19
       LayoutText {#text} at (0,267) size 165x19
         text run at (0,267) width 165: "dynamic selected change:"
-      LayoutBR {BR} at (164,281) size 1x1
+      LayoutBR {BR} at (164,267) size 1x19
       LayoutMenuList {SELECT} at (0,286.25) size 153x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 153x18
           LayoutText (anonymous) at (8,2) size 122x13
             text run at (8,2) width 122: "this should be selected"
       LayoutText {#text} at (153,285) size 4x19
         text run at (153,285) width 4: " "
-      LayoutBR {BR} at (157,299) size 0x1
+      LayoutBR {BR} at (157,285) size 0x19
       LayoutText {#text} at (0,304) size 217x19
         text run at (0,304) width 217: "dynamic insert of selected option:"
-      LayoutBR {BR} at (216,318) size 1x1
-      LayoutMenuList {SELECT} at (0,322.25) size 153x18 [bgcolor=#F8F8F8]
+      LayoutBR {BR} at (216,304) size 1x19
+      LayoutMenuList {SELECT} at (0,323.25) size 153x18 [bgcolor=#F8F8F8]
         LayoutBlockFlow (anonymous) at (0,0) size 153x18
           LayoutText (anonymous) at (8,2) size 122x13
             text run at (8,2) width 122: "this should be selected"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-with-frameborder-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-with-frameborder-expected.txt
index 6eb410f..1f02f31 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-with-frameborder-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/frames/iframe-with-frameborder-expected.txt
@@ -1,23 +1,23 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x540
+  LayoutBlockFlow {HTML} at (0,0) size 800x540
+    LayoutBlockFlow {BODY} at (8,8) size 784x524
       LayoutText {#text} at (0,0) size 216x18
         text run at (0,0) width 216: "This iframe should have a border."
-      LayoutBR {BR} at (215,14) size 1x0
+      LayoutBR {BR} at (215,0) size 1x18
       LayoutText {#text} at (304,158) size 4x18
         text run at (304,158) width 4: " "
       LayoutBR {BR} at (0,0) size 0x0
       LayoutText {#text} at (0,176) size 150x18
         text run at (0,176) width 150: "This iframe should not."
-      LayoutBR {BR} at (149,190) size 1x0
+      LayoutBR {BR} at (149,176) size 1x18
       LayoutText {#text} at (300,330) size 4x18
         text run at (300,330) width 4: " "
-      LayoutBR {BR} at (304,344) size 0x0
+      LayoutBR {BR} at (304,330) size 0x18
       LayoutText {#text} at (0,348) size 220x18
         text run at (0,348) width 220: "This iframe should have a border. "
-      LayoutBR {BR} at (219,362) size 1x0
+      LayoutBR {BR} at (219,348) size 1x18
       LayoutText {#text} at (0,0) size 0x0
 layer at (8,26) size 304x154
   LayoutIFrame {IFRAME} at (0,18) size 304x154 [border: (2px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.png
index c4d46ce..2cea4381 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.txt
index c246604..7d5645f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/parser/001-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x567
+  LayoutBlockFlow {HTML} at (0,0) size 800x567
+    LayoutBlockFlow {BODY} at (8,16) size 784x543
       LayoutBlockFlow {DIR} at (0,0) size 784x104
         LayoutBlockFlow (anonymous) at (40,0) size 744x18
           LayoutText {#text} at (0,0) size 27x18
@@ -39,5 +39,5 @@
           LayoutText {#text} at (0,0) size 236x18
             text run at (0,0) width 236: "Now we're back to nonbreaking text."
         LayoutText {#text} at (0,0) size 0x0
-layer at (8,143) size 300x300
+layer at (8,151) size 300x300
   LayoutEmbeddedObject {OBJECT} at (0,15) size 300x300 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index 17f5fc6c..3eaebbda 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.png
index e82dc957..155a4f06 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/dynamic-descendant-percentage-height-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/dynamic-descendant-percentage-height-expected.png
index d3e14130..81d732bb 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/dynamic-descendant-percentage-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/dynamic-descendant-percentage-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png
index ed5a172f..38cad4d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/color-profile-video-seek-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.png
index e39aee78..c66c89f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.txt
index a3a2b52..72dea9f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x437.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x28
+      LayoutBlockFlow {DIV} at (0,0) size 366x437.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x28
           LayoutText {#text} at (0,0) size 195x28
             text run at (0,0) width 195: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
+        LayoutBlockFlow (anonymous) at (1,68.81) size 364x368
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,166) size 4x18
-            text run at (364,166) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,418) size 4x19
-        text run at (370,418) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x437.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x28
+      LayoutText {#text} at (366,418) size 4x19
+        text run at (366,418) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x437.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x28
           LayoutText {#text} at (0,0) size 196x28
             text run at (0,0) width 196: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
+        LayoutBlockFlow (anonymous) at (1,68.81) size 364x368
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,166) size 4x18
-            text run at (364,166) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.png
index f26415c0..448f910 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.txt
index a3a2b52..72dea9f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x437.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x28
+      LayoutBlockFlow {DIV} at (0,0) size 366x437.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x28
           LayoutText {#text} at (0,0) size 195x28
             text run at (0,0) width 195: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
+        LayoutBlockFlow (anonymous) at (1,68.81) size 364x368
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,166) size 4x18
-            text run at (364,166) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,418) size 4x19
-        text run at (370,418) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x437.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x28
+      LayoutText {#text} at (366,418) size 4x19
+        text run at (366,418) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x437.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x28
           LayoutText {#text} at (0,0) size 196x28
             text run at (0,0) width 196: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,68.81) size 368x368
+        LayoutBlockFlow (anonymous) at (1,68.81) size 364x368
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,166) size 4x18
             text run at (180,166) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,166) size 4x18
-            text run at (364,166) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,194) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x18
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png
index c96560a..8706c32 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-fixed-scrolling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png
index d25d7f6..2c183da6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/geometry/video-opacity-overlay-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png
index 38543cc..f4a325b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/visibility/visibility-simple-video-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css1/box_properties/float_on_text_elements-expected.txt b/third_party/WebKit/LayoutTests/platform/win/css1/box_properties/float_on_text_elements-expected.txt
index 41c7b73..7c7d192 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css1/box_properties/float_on_text_elements-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/css1/box_properties/float_on_text_elements-expected.txt
@@ -25,7 +25,7 @@
         LayoutImage {IMG} at (0,80) size 15x15
         LayoutText {#text} at (15,80) size 4x19
           text run at (15,80) width 4: " "
-        LayoutBR {BR} at (19,95) size 0x0
+        LayoutBR {BR} at (19,80) size 0x19
       LayoutBlockFlow (anonymous) at (0,236) size 769x100
         LayoutBlockFlow (floating) {P} at (0,0) size 384.50x100 [bgcolor=#FFFF00]
           LayoutText {#text} at (0,0) size 384x99
@@ -37,7 +37,7 @@
         LayoutImage {IMG} at (384.50,0) size 15x15
         LayoutText {#text} at (399,0) size 5x19
           text run at (399,0) width 5: " "
-        LayoutBR {BR} at (403,15) size 1x0
+        LayoutBR {BR} at (403,0) size 1x19
       LayoutBlockFlow (anonymous) at (0,354) size 769x120
         LayoutBlockFlow (floating) {P} at (384.50,0) size 384.50x120 [bgcolor=#FFFF00]
           LayoutText {#text} at (0,0) size 384x119
@@ -50,7 +50,7 @@
         LayoutImage {IMG} at (0,0) size 15x15
         LayoutText {#text} at (15,0) size 4x19
           text run at (15,0) width 4: " "
-        LayoutBR {BR} at (19,15) size 0x0
+        LayoutBR {BR} at (19,0) size 0x19
       LayoutBlockFlow {P} at (0,492) size 769x60
         LayoutBlockFlow (floating) {SPAN} at (0,0) size 48x37 [bgcolor=#C0C0C0]
           LayoutText {#text} at (0,0) size 21x36
@@ -192,7 +192,7 @@
                 LayoutImage {IMG} at (0,80) size 15x15
                 LayoutText {#text} at (15,80) size 4x19
                   text run at (15,80) width 4: " "
-                LayoutBR {BR} at (19,95) size 0x0
+                LayoutBR {BR} at (19,80) size 0x19
               LayoutBlockFlow (anonymous) at (4,240) size 747x120
                 LayoutBlockFlow (floating) {P} at (0,0) size 373.50x120 [bgcolor=#FFFF00]
                   LayoutText {#text} at (0,0) size 373x119
@@ -205,7 +205,7 @@
                 LayoutImage {IMG} at (373.50,0) size 15x15
                 LayoutText {#text} at (388,0) size 5x19
                   text run at (388,0) width 5: " "
-                LayoutBR {BR} at (392,15) size 1x0
+                LayoutBR {BR} at (392,0) size 1x19
               LayoutBlockFlow (anonymous) at (4,378) size 747x120
                 LayoutBlockFlow (floating) {P} at (373.50,0) size 373.50x120 [bgcolor=#FFFF00]
                   LayoutText {#text} at (0,0) size 373x119
@@ -218,7 +218,7 @@
                 LayoutImage {IMG} at (0,0) size 15x15
                 LayoutText {#text} at (15,0) size 4x19
                   text run at (15,0) width 4: " "
-                LayoutBR {BR} at (19,15) size 0x0
+                LayoutBR {BR} at (19,0) size 0x19
               LayoutBlockFlow {P} at (4,516) size 747x60
                 LayoutBlockFlow (floating) {SPAN} at (0,0) size 48x37 [bgcolor=#C0C0C0]
                   LayoutText {#text} at (0,0) size 21x36
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
new file mode 100644
index 0000000..e5c3097
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/webaudio/the-audio-api/the-pannernode-interface/panner-distance-clamping-expected.txt
@@ -0,0 +1,49 @@
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED.
+PASS > [ref-distance-error] 
+FAIL X new PannerNode(c, {refDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {refDistance: 0}) did not throw an exception.
+PASS   new PannerNode(c, {refDistance: 5e-324}) did not throw an exception.
+FAIL X panner.refDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.refDistance = 0 did not throw an exception.
+PASS   panner.refDistance = 5e-324 did not throw an exception.
+FAIL < [ref-distance-error] 2 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [max-distance-error] 
+FAIL X new PannerNode(c, {maxDistance: -1}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X new PannerNode(c, {maxDistance: 0}) threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   new PannerNode(c, {maxDistance: 5e-324}) did not throw an exception.
+FAIL X panner.maxDistance = -1 threw "RangeError" instead of RangeError. assert_true: expected true got false
+FAIL X panner.maxDistance = 0 threw "RangeError" instead of RangeError. assert_true: expected true got false
+PASS   panner.maxDistance = 5e-324 did not throw an exception.
+FAIL < [max-distance-error] 4 out of 6 assertions were failed. assert_true: expected true got false
+PASS > [min-distance] 
+PASS   Model: linear: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"linear"} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: exponential: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"exponential"} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: inverse: Distance (0.01) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":0.01,"distanceModel":"inverse"} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: linear: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: exponential: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS   Model: inverse: Distance (2) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":2,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.20702199637889862,0.4738079607486725,-0.23029837012290955,-0.41959449648857117,-0.025587808340787888,0.04287990927696228,0.4513133466243744,0.15709976851940155,-0.4906681180000305,-0.16540144383907318,0.00021876610117033124,0.25102248787879944,0.4455360770225525,-0.29729732871055603,-0.38197818398475647...].
+PASS < [min-distance] All assertions passed. (total 12 assertions)
+PASS > [max-distance] 
+PASS   Model: linear: Distance (20000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":20000,"distanceModel":"linear"} is identical to the array [0,0.10351099818944931,0.23690398037433624,-0.11514918506145477,-0.20979724824428558,-0.012793904170393944,0.02143995463848114,0.2256566733121872,0.07854988425970078,-0.24533405900001526,-0.08270072191953659,0.00010938305058516562,0.12551124393939972,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
+PASS   Model: exponential: Distance (21000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":21000,"distanceModel":"exponential"} is identical to the array [0,0.0014285874785855412,0.0032695855479687452,-0.0015892097726464272,-0.002895476995036006,-0.0001765726483426988,0.0002958994882646948,0.0031143580563366413,0.0010840913746505976,-0.003385931719094515,-0.0011413784231990576,0.0000015096295555849792,0.001732219709083438,0.0030744909308850765,-0.002051546471193433,-0.002635899931192398...].
+PASS   Model: inverse: Distance (23000) is outside the range [1, 10000] is equal to true.
+PASS   Test panner output {"distance":23000,"distanceModel":"inverse"} is identical to the array [0,0.000018001130229094997,0.000041198902181349695,-0.000020025074263685383,-0.000036484892916632816,-0.000002224930085503729,0.0000037285258258634713,0.000039242931961780414,0.00001366025571769569,-0.00004266493851901032,-0.000014382108929567039,1.9022312613969916e-8,0.00002182709431508556,0.00003874058529618196,-0.00002585081892902963,-0.000033214051654795185...].
+PASS   Model: linear: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"linear","maxDistance":1000,"refDistance":10} is identical to the array [0,0.10351099818944931,0.23690398037433624,-0.11514918506145477,-0.20979724824428558,-0.012793904170393944,0.02143995463848114,0.2256566733121872,0.07854988425970078,-0.24533405900001526,-0.08270072191953659,0.00010938305058516562,0.12551124393939972,0.22276803851127625,-0.14864866435527802,-0.19098909199237823...].
+PASS   Model: exponential: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"exponential","maxDistance":1000,"refDistance":10} is identical to the array [0,0.00925830565392971,0.021189337596297264,-0.0102992570027709,-0.018764836713671684,-0.0011443216353654861,0.001917647896334529,0.020183347165584564,0.007025715429335833,-0.0219433456659317,-0.007396977860480547,0.000009783518180483952,0.011226067319512367,0.019924979656934738,-0.013295541517436504,-0.017082585021853447...].
+PASS   Model: inverse: Distance (5000) is outside the range [10, 1000] is equal to true.
+PASS   Test panner output {"distance":5000,"distanceModel":"inverse","maxDistance":1000,"refDistance":10} is identical to the array [0,0.0008264351054094732,0.0018914489774033427,-0.000919354788493365,-0.0016750278882682323,-0.00010214693611487746,0.00017117727838922292,0.0018016500398516655,0.0006271447637118399,-0.0019587548449635506,-0.0006602851790376008,8.733177878639253e-7,0.0010020857444033027,0.0017785871168598533,-0.0011868156725540757,-0.0015248629497364163...].
+PASS < [max-distance] All assertions passed. (total 12 assertions)
+FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 4 tasks were failed. assert_true: expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/select-initial-position-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/select-initial-position-expected.txt
index 592605f..c5cb618 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/select-initial-position-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/select-initial-position-expected.txt
@@ -1,49 +1,49 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x409
+  LayoutBlockFlow {HTML} at (0,0) size 800x409
+    LayoutBlockFlow {BODY} at (8,8) size 784x393
       LayoutText {#text} at (0,0) size 86x19
         text run at (0,0) width 86: "initial selected:"
-      LayoutBR {BR} at (86,15) size 0x0
+      LayoutBR {BR} at (86,0) size 0x19
       LayoutText {#text} at (155,71) size 4x19
         text run at (155,71) width 4: " "
-      LayoutBR {BR} at (159,86) size 0x0
+      LayoutBR {BR} at (159,71) size 0x19
       LayoutText {#text} at (0,91) size 152x19
         text run at (0,91) width 152: "dynamic selected change:"
-      LayoutBR {BR} at (152,106) size 0x0
+      LayoutBR {BR} at (152,91) size 0x19
       LayoutText {#text} at (155,162) size 4x19
         text run at (155,162) width 4: " "
-      LayoutBR {BR} at (159,177) size 0x0
+      LayoutBR {BR} at (159,162) size 0x19
       LayoutText {#text} at (0,182) size 200x19
         text run at (0,182) width 200: "dynamic insert of selected option:"
-      LayoutBR {BR} at (200,197) size 0x0
+      LayoutBR {BR} at (200,182) size 0x19
       LayoutText {#text} at (155,253) size 4x19
         text run at (155,253) width 4: " "
-      LayoutBR {BR} at (159,268) size 0x0
+      LayoutBR {BR} at (159,253) size 0x19
       LayoutText {#text} at (0,273) size 86x19
         text run at (0,273) width 86: "initial selected:"
-      LayoutBR {BR} at (86,288) size 0x0
+      LayoutBR {BR} at (86,273) size 0x19
       LayoutMenuList {SELECT} at (0,293) size 156x20 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 154x18
           LayoutText (anonymous) at (4,1) size 134x16
             text run at (4,1) width 134: "this should be selected"
       LayoutText {#text} at (156,293) size 4x19
         text run at (156,293) width 4: " "
-      LayoutBR {BR} at (160,308) size 0x0
+      LayoutBR {BR} at (160,293) size 0x19
       LayoutText {#text} at (0,313) size 152x19
         text run at (0,313) width 152: "dynamic selected change:"
-      LayoutBR {BR} at (152,328) size 0x0
+      LayoutBR {BR} at (152,313) size 0x19
       LayoutMenuList {SELECT} at (0,333) size 156x20 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 154x18
           LayoutText (anonymous) at (4,1) size 134x16
             text run at (4,1) width 134: "this should be selected"
       LayoutText {#text} at (156,333) size 4x19
         text run at (156,333) width 4: " "
-      LayoutBR {BR} at (160,348) size 0x0
+      LayoutBR {BR} at (160,333) size 0x19
       LayoutText {#text} at (0,353) size 200x19
         text run at (0,353) width 200: "dynamic insert of selected option:"
-      LayoutBR {BR} at (200,368) size 0x0
+      LayoutBR {BR} at (200,353) size 0x19
       LayoutMenuList {SELECT} at (0,373) size 156x20 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 154x18
           LayoutText (anonymous) at (4,1) size 134x16
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/frames/iframe-with-frameborder-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/frames/iframe-with-frameborder-expected.txt
index cc73174..0421413 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/frames/iframe-with-frameborder-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/frames/iframe-with-frameborder-expected.txt
@@ -1,23 +1,23 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x549
+  LayoutBlockFlow {HTML} at (0,0) size 800x549
+    LayoutBlockFlow {BODY} at (8,8) size 784x533
       LayoutText {#text} at (0,0) size 200x19
         text run at (0,0) width 200: "This iframe should have a border."
-      LayoutBR {BR} at (200,15) size 0x0
+      LayoutBR {BR} at (200,0) size 0x19
       LayoutText {#text} at (304,159) size 4x19
         text run at (304,159) width 4: " "
       LayoutBR {BR} at (0,0) size 0x0
       LayoutText {#text} at (0,179) size 136x19
         text run at (0,179) width 136: "This iframe should not."
-      LayoutBR {BR} at (136,194) size 0x0
+      LayoutBR {BR} at (136,179) size 0x19
       LayoutText {#text} at (300,334) size 4x19
         text run at (300,334) width 4: " "
-      LayoutBR {BR} at (304,349) size 0x0
+      LayoutBR {BR} at (304,334) size 0x19
       LayoutText {#text} at (0,354) size 204x19
         text run at (0,354) width 204: "This iframe should have a border. "
-      LayoutBR {BR} at (204,369) size 0x0
+      LayoutBR {BR} at (204,354) size 0x19
       LayoutText {#text} at (0,0) size 0x0
 layer at (8,28) size 304x154
   LayoutIFrame {IFRAME} at (0,20) size 304x154 [border: (2px inset #EEEEEE)]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.png
index 7a3e7f7..f1c25d2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.txt
index e76a697..1d6fd58b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/parser/001-expected.txt
@@ -1,8 +1,8 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
+layer at (0,0) size 800x583
+  LayoutBlockFlow {HTML} at (0,0) size 800x583
+    LayoutBlockFlow {BODY} at (8,16) size 784x559
       LayoutBlockFlow {DIR} at (0,0) size 784x112
         LayoutBlockFlow (anonymous) at (40,0) size 744x20
           LayoutText {#text} at (0,0) size 26x19
@@ -39,5 +39,5 @@
           LayoutText {#text} at (0,0) size 226x19
             text run at (0,0) width 226: "Now we're back to nonbreaking text."
         LayoutText {#text} at (0,0) size 0x0
-layer at (8,152) size 300x300
+layer at (8,160) size 300x300
   LayoutEmbeddedObject {OBJECT} at (0,16) size 300x300 [bgcolor=#008000]
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index 7fce2d66..2a1c3c27 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.png
index ad49523..914f30e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/dynamic-descendant-percentage-height-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/dynamic-descendant-percentage-height-expected.png
index 7791047..8e8e1c84 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/table/dynamic-descendant-percentage-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/table/dynamic-descendant-percentage-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png
index dffb76a..406f546 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/color-profile-video-seek-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png
index 9c6d810..72538246 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
index 393845f..6088ad2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-2-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 193x26
             text run at (0,0) width 193: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
index a741647..43c7ca80 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
index 393845f..6088ad2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/as-border-image/svg-as-border-image-expected.txt
@@ -3,37 +3,33 @@
 layer at (0,0) size 800x600
   LayoutBlockFlow {HTML} at (0,0) size 800x600
     LayoutBlockFlow {BODY} at (8,8) size 784x584
-      LayoutBlockFlow {DIV} at (0,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutBlockFlow {DIV} at (0,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 193x26
             text run at (0,0) width 193: "SVG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
           LayoutBlockFlow {DIV} at (194,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (0,0) size 0x0
-      LayoutText {#text} at (370,417) size 4x20
-        text run at (370,417) width 4: " "
-      LayoutBlockFlow {DIV} at (374,0) size 370x438.81 [border: (1px solid #000000)]
-        LayoutBlockFlow {H2} at (1,20.91) size 368x27
+      LayoutText {#text} at (366,417) size 4x20
+        text run at (366,417) width 4: " "
+      LayoutBlockFlow {DIV} at (370,0) size 366x438.81 [border: (1px solid #000000)]
+        LayoutBlockFlow {H2} at (1,20.91) size 364x27
           LayoutText {#text} at (0,0) size 195x26
             text run at (0,0) width 195: "PNG border-image"
-        LayoutBlockFlow (anonymous) at (1,67.81) size 368x370
+        LayoutBlockFlow (anonymous) at (1,67.81) size 364x370
           LayoutBlockFlow {DIV} at (10,10) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,165) size 4x19
             text run at (180,165) width 4: " "
           LayoutBlockFlow {DIV} at (194,10) size 160x160 [border: (30px solid #000000)]
-          LayoutText {#text} at (364,165) size 4x19
-            text run at (364,165) width 4: " "
-          LayoutBR {BR} at (0,0) size 0x0
+          LayoutBR {BR} at (364,180) size 0x0
           LayoutBlockFlow {DIV} at (10,195) size 160x160 [border: (30px solid #000000)]
           LayoutText {#text} at (180,350) size 4x19
             text run at (180,350) width 4: " "
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index 7c649995..a170c16 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.png
index bfb79b9..19008de 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
index 57346e0..a9f2868 100644
--- a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
+++ b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image-2.html
@@ -57,8 +57,7 @@
   <div class="svg">
     <h2>SVG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
@@ -66,8 +65,7 @@
   <div class="image">
     <h2>PNG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
diff --git a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
index a9bf8b9f..a3d7aeb 100644
--- a/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
+++ b/third_party/WebKit/LayoutTests/svg/as-border-image/svg-as-border-image.html
@@ -57,8 +57,7 @@
   <div class="svg">
     <h2>SVG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
@@ -66,8 +65,7 @@
   <div class="image">
     <h2>PNG border-image</h2>
     <div class="rr"></div>
-    <div class="rs"></div>
-    <br>
+    <div class="rs"></div><br>
     <div class="sr"></div>
     <div class="ss"></div>
   </div>
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/fetch/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/fetch/README.txt
new file mode 100644
index 0000000..87c6416
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/fetch/README.txt
@@ -0,0 +1,4 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "external/wpt/fetch" directory for testing basic loading
+functionalities through fetching html files.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/http/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/http/README.txt
new file mode 100644
index 0000000..6d7938f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/http/README.txt
@@ -0,0 +1,4 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "external/wpt/http" directory for testing basic loading
+functionalities through http tests.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/referrer-policy/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/referrer-policy/README.txt
new file mode 100644
index 0000000..03840de3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/referrer-policy/README.txt
@@ -0,0 +1,4 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "external/wpt/referrer-policy" directory for testing CORS
+referrer handling.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/README.txt
new file mode 100644
index 0000000..d630b09
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/README.txt
@@ -0,0 +1,4 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "external/wpt/service-workers" directory for testing CORS with
+service workers.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt
new file mode 100644
index 0000000..1f2011a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/clients-matchall-client-types.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Verify matchAll() with window client type assert_unreached: unexpected rejection: assert_array_equals: property 2, expected "https://web-platform.test:8444/service-workers/service-worker/resources/clients-matchall-client-types-iframe.html" but got "https://web-platform.test:8444/service-workers/service-worker/resources/url-modified-via-pushstate.html" Reached unreachable code
+FAIL Verify matchAll() with {window, sharedworker, worker} client types promise_test: Unhandled rejection with value: object "Error: wait_for_state must be passed a ServiceWorker"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/fetch/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/fetch/README.txt
new file mode 100644
index 0000000..25c7135
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/fetch/README.txt
@@ -0,0 +1,3 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "http/tests/fetch" directory for testing fetch with CORS.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/README.txt
new file mode 100644
index 0000000..ce95561
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/README.txt
@@ -0,0 +1,3 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "http/tests/xmlhttprequest" directory for testing XHR with CORS.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
new file mode 100644
index 0000000..5e6e463
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
@@ -0,0 +1,19 @@
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+XMLHttpRequest doesn't crash even when open() is invoked synchronously to handling of a redirect response to a cross-origin request.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt
new file mode 100644
index 0000000..7386346
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
+PASS: Cross-domain access allowed.
+HTTP_ORIGIN: http://127.0.0.1:8000
+
+
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt
new file mode 100644
index 0000000..7386346
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
+PASS: Cross-domain access allowed.
+HTTP_ORIGIN: http://127.0.0.1:8000
+
+
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt
new file mode 100644
index 0000000..7386346
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
+PASS: Cross-domain access allowed.
+HTTP_ORIGIN: http://127.0.0.1:8000
+
+
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
new file mode 100644
index 0000000..ce34f64
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
@@ -0,0 +1,6 @@
+CONSOLE WARNING: line 25: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
+CONSOLE ERROR: line 26: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+Test that a cross-origin chain of redirects to a server that responds is indistinguishable from one that does not. Should say PASS:
+
+PASS
+
diff --git a/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom b/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
index 9d473a10..9a4e59a 100644
--- a/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
+++ b/third_party/blink/public/platform/modules/credentialmanager/credential_manager.mojom
@@ -25,15 +25,15 @@
   PENDING_REQUEST,
   PASSWORD_STORE_UNAVAILABLE,
   NOT_ALLOWED,
-  AUTHENTICATOR_CRITERIA_UNSUPPORTED,
-  ALGORITHM_UNSUPPORTED,
-  EMPTY_ALLOW_CREDENTIALS,
-  USER_VERIFICATION_UNSUPPORTED,
   INVALID_DOMAIN,
   CREDENTIAL_EXCLUDED,
   CREDENTIAL_NOT_RECOGNIZED,
   NOT_IMPLEMENTED,
   NOT_FOCUSED,
+  ANDROID_ALGORITHM_UNSUPPORTED,
+  ANDROID_EMPTY_ALLOW_CREDENTIALS,
+  ANDROID_NOT_SUPPORTED_ERROR,
+  ANDROID_USER_VERIFICATION_UNSUPPORTED,
   UNKNOWN
 };
 
diff --git a/third_party/blink/public/platform/modules/webauth/authenticator.mojom b/third_party/blink/public/platform/modules/webauth/authenticator.mojom
index fbc108f7..e0b1badb 100644
--- a/third_party/blink/public/platform/modules/webauth/authenticator.mojom
+++ b/third_party/blink/public/platform/modules/webauth/authenticator.mojom
@@ -16,15 +16,15 @@
   SUCCESS,
   PENDING_REQUEST,
   NOT_ALLOWED_ERROR,
-  AUTHENTICATOR_CRITERIA_UNSUPPORTED,
-  ALGORITHM_UNSUPPORTED,
-  EMPTY_ALLOW_CREDENTIALS,
-  USER_VERIFICATION_UNSUPPORTED,
   INVALID_DOMAIN,
   CREDENTIAL_EXCLUDED,
   CREDENTIAL_NOT_RECOGNIZED,
   NOT_IMPLEMENTED,
   NOT_FOCUSED,
+  USER_VERIFICATION_UNSUPPORTED,
+  ALGORITHM_UNSUPPORTED,
+  EMPTY_ALLOW_CREDENTIALS,
+  ANDROID_NOT_SUPPORTED_ERROR,
   UNKNOWN_ERROR,
 };
 
diff --git a/third_party/blink/public/platform/web_media_player_client.h b/third_party/blink/public/platform/web_media_player_client.h
index 570640ec..092556d 100644
--- a/third_party/blink/public/platform/web_media_player_client.h
+++ b/third_party/blink/public/platform/web_media_player_client.h
@@ -136,8 +136,9 @@
   virtual void PictureInPictureStopped() = 0;
 
   // Informs that a custom Picture-in-Picture control was clicked for the media
-  // element.
-  virtual void PictureInPictureControlClicked() = 0;
+  // element. |control_id| is the identifier for its custom control. This is
+  // defined by the site that calls the web API.
+  virtual void PictureInPictureControlClicked(const WebString& control_id) = 0;
 
   // Returns whether the media element has native controls. It does not mean
   // that the controls are currently visible.
diff --git a/third_party/blink/renderer/core/css/html.css b/third_party/blink/renderer/core/css/html.css
index abcd0a8..d5305dee 100644
--- a/third_party/blink/renderer/core/css/html.css
+++ b/third_party/blink/renderer/core/css/html.css
@@ -467,6 +467,7 @@
     -webkit-margin-start: 1px;
     opacity: 0;
     pointer-events: none;
+    user-select: none !important;
 }
 
 input[type="search" i]:enabled:read-write:-webkit-any(:focus,:hover)::-webkit-search-cancel-button {
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index ec34465..5bfe30b 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -51,6 +51,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
 #include "third_party/blink/renderer/bindings/core/v8/string_or_dictionary.h"
+#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
 #include "third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_element_creation_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
@@ -240,6 +241,7 @@
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
 #include "third_party/blink/renderer/core/workers/shared_worker_repository_client.h"
 #include "third_party/blink/renderer/core/xml/parser/xml_document_parser.h"
 #include "third_party/blink/renderer/core/xml_names.h"
@@ -3240,7 +3242,7 @@
 
 DOMWindow* Document::open(LocalDOMWindow* current_window,
                           LocalDOMWindow* entered_window,
-                          const AtomicString& url,
+                          const USVStringOrTrustedURL& stringOrUrl,
                           const AtomicString& name,
                           const AtomicString& features,
                           ExceptionState& exception_state) {
@@ -3250,7 +3252,8 @@
     return nullptr;
   }
   AtomicString frame_name = name.IsEmpty() ? "_blank" : name;
-  return domWindow()->open(url, frame_name, features, current_window,
+
+  return domWindow()->open(stringOrUrl, frame_name, features, current_window,
                            entered_window, exception_state);
 }
 
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index a41486e1..9fdbca8 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -181,6 +181,7 @@
 class TextAutosizer;
 class TransformSource;
 class TreeWalker;
+class USVStringOrTrustedURL;
 class V8NodeFilter;
 class ViewportData;
 class VisitedLinkState;
@@ -613,7 +614,7 @@
                  ExceptionState&);
   DOMWindow* open(LocalDOMWindow* current_window,
                   LocalDOMWindow* entered_window,
-                  const AtomicString& url,
+                  const USVStringOrTrustedURL& stringOrUrl,
                   const AtomicString& name,
                   const AtomicString& features,
                   ExceptionState&);
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl
index ccda5e64..7d88ef1 100644
--- a/third_party/blink/renderer/core/dom/document.idl
+++ b/third_party/blink/renderer/core/dom/document.idl
@@ -120,7 +120,7 @@
 
     // dynamic markup insertion
     [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException, MeasureAs=DocumentOpenTwoArgs] Document open(optional DOMString type = "text/html", optional DOMString replace = "");
-    [CallWith=(CurrentWindow,EnteredWindow), RaisesException, MeasureAs=DocumentOpenThreeArgs] Window open(USVString url, DOMString name, DOMString features);
+    [CallWith=(CurrentWindow,EnteredWindow), RaisesException, MeasureAs=DocumentOpenThreeArgs] Window open(URLString url, DOMString name, DOMString features);
     [CEReactions, RaisesException] void close();
     [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void write(DOMString... text);
     [CallWith=EnteredWindow, CEReactions, CustomElementCallbacks, RaisesException] void writeln(DOMString... text);
diff --git a/third_party/blink/renderer/core/frame/frame_view.h b/third_party/blink/renderer/core/frame/frame_view.h
index 3ea14499..429a2e0 100644
--- a/third_party/blink/renderer/core/frame/frame_view.h
+++ b/third_party/blink/renderer/core/frame/frame_view.h
@@ -5,7 +5,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VIEW_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_VIEW_H_
 
-#include "third_party/blink/renderer/core/dom/document_lifecycle.h"
 #include "third_party/blink/renderer/core/frame/embedded_content_view.h"
 
 namespace blink {
@@ -15,8 +14,7 @@
 class CORE_EXPORT FrameView : public EmbeddedContentView {
  public:
   ~FrameView() override = default;
-  virtual void UpdateViewportIntersectionsForSubtree(
-      DocumentLifecycle::LifecycleState) = 0;
+  virtual void UpdateViewportIntersectionsForSubtree() = 0;
 
   virtual bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const = 0;
   virtual bool HasIntrinsicSizingInfo() const = 0;
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index b85527f..4b1dd4d6 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -37,6 +37,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
 #include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
 #include "third_party/blink/renderer/core/aom/computed_accessible_node.h"
 #include "third_party/blink/renderer/core/css/css_computed_style_declaration.h"
@@ -97,6 +98,7 @@
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
 #include "third_party/blink/renderer/platform/scroll/scroll_types.h"
@@ -1532,6 +1534,46 @@
                                 const AtomicString& target,
                                 const String& features,
                                 ExceptionState& exception_state) {
+  if (document_->RequireTrustedTypes()) {
+    exception_state.ThrowTypeError(
+        "This document requires `TrustedURL` assignment.");
+    return nullptr;
+  }
+  return openFromString(executionContext, current_window, entered_window, url,
+                        target, features, exception_state);
+}
+
+DOMWindow* LocalDOMWindow::open(ExecutionContext* executionContext,
+                                LocalDOMWindow* current_window,
+                                LocalDOMWindow* entered_window,
+                                const USVStringOrTrustedURL& stringOrUrl,
+                                const AtomicString& target,
+                                const String& features,
+                                ExceptionState& exception_state) {
+  DCHECK(stringOrUrl.IsUSVString() ||
+         RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+
+  if (!stringOrUrl.IsTrustedURL() && document_->RequireTrustedTypes()) {
+    exception_state.ThrowTypeError(
+        "This document requires `TrustedURL` assignment.");
+    return nullptr;
+  }
+
+  String url = stringOrUrl.IsUSVString()
+                   ? stringOrUrl.GetAsUSVString()
+                   : stringOrUrl.GetAsTrustedURL()->toString();
+
+  return openFromString(executionContext, current_window, entered_window, url,
+                        target, features, exception_state);
+}
+
+DOMWindow* LocalDOMWindow::openFromString(ExecutionContext* executionContext,
+                                          LocalDOMWindow* current_window,
+                                          LocalDOMWindow* entered_window,
+                                          const String& url,
+                                          const AtomicString& target,
+                                          const String& features,
+                                          ExceptionState& exception_state) {
   // If the bindings implementation is 100% correct, the current realm and the
   // entered realm should be same origin-domain. However, to be on the safe
   // side and add some defense in depth, we'll check against the entered realm
@@ -1542,16 +1584,54 @@
     return nullptr;
   }
   DCHECK(!target.IsNull());
-  return open(url, target, features, current_window, entered_window,
-              exception_state);
+  return openFromString(url, target, features, current_window, entered_window,
+                        exception_state);
 }
 
-DOMWindow* LocalDOMWindow::open(const String& url_string,
+DOMWindow* LocalDOMWindow::open(const String& url,
                                 const AtomicString& frame_name,
                                 const String& window_features_string,
                                 LocalDOMWindow* calling_window,
                                 LocalDOMWindow* entered_window,
                                 ExceptionState& exception_state) {
+  if (document_->RequireTrustedTypes()) {
+    exception_state.ThrowTypeError(
+        "This document requires `TrustedURL` assignment.");
+    return nullptr;
+  }
+  return openFromString(url, frame_name, window_features_string, calling_window,
+                        entered_window, exception_state);
+}
+
+DOMWindow* LocalDOMWindow::open(const USVStringOrTrustedURL& stringOrUrl,
+                                const AtomicString& frame_name,
+                                const String& window_features_string,
+                                LocalDOMWindow* calling_window,
+                                LocalDOMWindow* entered_window,
+                                ExceptionState& exception_state) {
+  DCHECK(stringOrUrl.IsUSVString() ||
+         RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
+
+  if (!stringOrUrl.IsTrustedURL() && document_->RequireTrustedTypes()) {
+    exception_state.ThrowTypeError(
+        "This document requires `TrustedURL` assignment.");
+    return nullptr;
+  }
+
+  String url = stringOrUrl.IsUSVString()
+                   ? stringOrUrl.GetAsUSVString()
+                   : stringOrUrl.GetAsTrustedURL()->toString();
+
+  return openFromString(url, frame_name, window_features_string, calling_window,
+                        entered_window, exception_state);
+}
+
+DOMWindow* LocalDOMWindow::openFromString(const String& url_string,
+                                          const AtomicString& frame_name,
+                                          const String& window_features_string,
+                                          LocalDOMWindow* calling_window,
+                                          LocalDOMWindow* entered_window,
+                                          ExceptionState& exception_state) {
   if (!IsCurrentlyDisplayedInFrame())
     return nullptr;
   if (!calling_window->GetFrame())
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index d116122..f64aaa4 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -69,6 +69,7 @@
 class SerializedScriptValue;
 class SourceLocation;
 class StyleMedia;
+class USVStringOrTrustedURL;
 class V8FrameRequestCallback;
 class V8IdleRequestCallback;
 
@@ -267,12 +268,27 @@
   DOMWindow* open(ExecutionContext*,
                   LocalDOMWindow* current_window,
                   LocalDOMWindow* entered_window,
-                  const String& url,
+                  const USVStringOrTrustedURL& stringOrUrl,
                   const AtomicString& target,
                   const String& features,
                   ExceptionState&);
 
-  DOMWindow* open(const String& url_string,
+  DOMWindow* open(const USVStringOrTrustedURL& stringOrUrl,
+                  const AtomicString& frame_name,
+                  const String& window_features_string,
+                  LocalDOMWindow* calling_window,
+                  LocalDOMWindow* entered_window,
+                  ExceptionState&);
+
+  DOMWindow* open(ExecutionContext*,
+                  LocalDOMWindow* current_window,
+                  LocalDOMWindow* entered_window,
+                  const String& str_url,
+                  const AtomicString& target,
+                  const String& features,
+                  ExceptionState&);
+
+  DOMWindow* open(const String& str_url,
                   const AtomicString& frame_name,
                   const String& window_features_string,
                   LocalDOMWindow* calling_window,
@@ -339,6 +355,21 @@
   void DispatchLoadEvent();
   void ClearDocument();
 
+  DOMWindow* openFromString(ExecutionContext*,
+                            LocalDOMWindow* current_window,
+                            LocalDOMWindow* entered_window,
+                            const String& url,
+                            const AtomicString& target,
+                            const String& features,
+                            ExceptionState&);
+
+  DOMWindow* openFromString(const String& url_string,
+                            const AtomicString& frame_name,
+                            const String& window_features_string,
+                            LocalDOMWindow* calling_window,
+                            LocalDOMWindow* entered_window,
+                            ExceptionState&);
+
   // Return the viewport size including scrollbars.
   IntSize GetViewportSize() const;
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index c5e4c55..1a81188 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2379,8 +2379,7 @@
       &current_update_lifecycle_phases_target_state_, target_state);
 
   if (ShouldThrottleRendering()) {
-    UpdateViewportIntersectionsForSubtree(
-        std::min(target_state, DocumentLifecycle::kCompositingClean));
+    UpdateThrottlingStatusForSubtree();
     return Lifecycle().GetState() == target_state;
   }
 
@@ -2410,7 +2409,7 @@
   }
 
   if (target_state == DocumentLifecycle::kLayoutClean) {
-    UpdateViewportIntersectionsForSubtree(target_state);
+    UpdateThrottlingStatusForSubtree();
     return Lifecycle().GetState() == target_state;
   }
 
@@ -2420,7 +2419,9 @@
   // OOPIF local frame roots that are throttled can return now that layout
   // is clean and intersection observations can be calculated.
   if (ShouldThrottleRendering()) {
-    UpdateViewportIntersectionsForSubtree(target_state);
+    if (target_state == DocumentLifecycle::kPaintClean)
+      UpdateViewportIntersectionsForSubtree();
+    UpdateThrottlingStatusForSubtree();
     return Lifecycle().GetState() == target_state;
   }
 
@@ -2515,6 +2516,14 @@
         }
       }
 
+      {
+        TRACE_EVENT0("blink,benchmark",
+                     "LocalFrameView::UpdateViewportIntersectionsForSubtree");
+        SCOPED_UMA_AND_UKM_TIMER("Blink.IntersectionObservation.UpdateTime",
+                                 UkmMetricNames::kIntersectionObservation);
+        UpdateViewportIntersectionsForSubtree();
+      }
+
       DCHECK(!frame_->Selection().NeedsLayoutSelectionUpdate());
       DCHECK(ShouldThrottleRendering() ||
              (frame_->GetDocument()->Printing() &&
@@ -2530,13 +2539,7 @@
     });
   }
 
-  {
-    TRACE_EVENT0("blink,benchmark",
-                 "LocalFrameView::UpdateViewportIntersectionsForSubtree");
-    SCOPED_UMA_AND_UKM_TIMER("Blink.IntersectionObservation.UpdateTime",
-                             UkmMetricNames::kIntersectionObservation);
-    UpdateViewportIntersectionsForSubtree(target_state);
-  }
+  UpdateThrottlingStatusForSubtree();
 
   return Lifecycle().GetState() == target_state;
 }
@@ -3871,8 +3874,7 @@
     CollectAnnotatedRegions(*curr, regions);
 }
 
-void LocalFrameView::UpdateViewportIntersectionsForSubtree(
-    DocumentLifecycle::LifecycleState target_state) {
+void LocalFrameView::UpdateViewportIntersectionsForSubtree() {
   // TODO(dcheng): Since LocalFrameView tree updates are deferred, FrameViews
   // might still be in the LocalFrameView hierarchy even though the associated
   // Document is already detached. Investigate if this check and a similar check
@@ -3881,19 +3883,29 @@
   if (!GetFrame().GetDocument()->IsActive())
     return;
 
-  if (target_state == DocumentLifecycle::kPaintClean) {
-    RecordDeferredLoadingStats();
-    if (!NeedsLayout()) {
-      // Notify javascript IntersectionObservers
-      if (GetFrame().GetDocument()->GetIntersectionObserverController()) {
-        GetFrame()
-            .GetDocument()
-            ->GetIntersectionObserverController()
-            ->ComputeTrackedIntersectionObservations();
-      }
+  RecordDeferredLoadingStats();
+  if (!NeedsLayout()) {
+    // Notify javascript IntersectionObservers
+    if (GetFrame().GetDocument()->GetIntersectionObserverController()) {
+      GetFrame()
+          .GetDocument()
+          ->GetIntersectionObserverController()
+          ->ComputeTrackedIntersectionObservations();
     }
   }
 
+  for (Frame* child = frame_->Tree().FirstChild(); child;
+       child = child->Tree().NextSibling()) {
+    child->View()->UpdateViewportIntersectionsForSubtree();
+  }
+
+  needs_intersection_observation_ = false;
+}
+
+void LocalFrameView::UpdateThrottlingStatusForSubtree() {
+  if (!GetFrame().GetDocument()->IsActive())
+    return;
+
   // Don't throttle display:none frames (see updateRenderThrottlingStatus).
   HTMLFrameOwnerElement* owner_element = frame_->DeprecatedLocalOwner();
   if (hidden_for_throttling_ && owner_element &&
@@ -3905,11 +3917,9 @@
                                  kDontNotifyChildren);
   }
 
-  for (Frame* child = frame_->Tree().FirstChild(); child;
-       child = child->Tree().NextSibling()) {
-    child->View()->UpdateViewportIntersectionsForSubtree(target_state);
-  }
-  needs_intersection_observation_ = false;
+  ForAllChildLocalFrameViews([](LocalFrameView& child_view) {
+    child_view.UpdateThrottlingStatusForSubtree();
+  });
 }
 
 void LocalFrameView::UpdateRenderThrottlingStatusForTesting() {
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 5c4d983..30519b5 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -734,8 +734,8 @@
   template <typename Function>
   void ForAllNonThrottledLocalFrameViews(const Function&);
 
-  void UpdateViewportIntersectionsForSubtree(
-      DocumentLifecycle::LifecycleState) override;
+  void UpdateViewportIntersectionsForSubtree() override;
+  void UpdateThrottlingStatusForSubtree();
 
   void NotifyResizeObservers();
 
diff --git a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
index b24f2b2..92dfb88 100644
--- a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
+++ b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
@@ -59,8 +59,10 @@
   virtual void OnExitedPictureInPicture(ScriptPromiseResolver*) = 0;
 
   // Should be called when a custom control on a video element in
-  // Picture-in-Picture is clicked.
-  virtual void OnPictureInPictureControlClicked() = 0;
+  // Picture-in-Picture is clicked. |control_id| is the identifier for its
+  // custom control. This is defined by the site that calls the web API.
+  virtual void OnPictureInPictureControlClicked(
+      const WebString& control_id) = 0;
 
   // Returns whether the given element is currently in Picture-in-Picture.
   virtual bool IsPictureInPictureElement(const Element*) const = 0;
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.cc b/third_party/blink/renderer/core/frame/remote_frame_view.cc
index f3f61fa1..47f1be0 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame_view.cc
@@ -63,12 +63,9 @@
   return view;
 }
 
-void RemoteFrameView::UpdateViewportIntersectionsForSubtree(
-    DocumentLifecycle::LifecycleState target_state) {
+void RemoteFrameView::UpdateViewportIntersectionsForSubtree() {
   if (!remote_frame_->OwnerLayoutObject())
     return;
-  if (target_state < DocumentLifecycle::kPaintClean)
-    return;
 
   LocalFrameView* local_root_view =
       ToLocalFrame(remote_frame_->Tree().Parent())->LocalFrameRoot().View();
diff --git a/third_party/blink/renderer/core/frame/remote_frame_view.h b/third_party/blink/renderer/core/frame/remote_frame_view.h
index 1f6fba0e..25b94e7 100644
--- a/third_party/blink/renderer/core/frame/remote_frame_view.h
+++ b/third_party/blink/renderer/core/frame/remote_frame_view.h
@@ -56,8 +56,7 @@
   void Show() override;
   void SetParentVisible(bool) override;
 
-  void UpdateViewportIntersectionsForSubtree(
-      DocumentLifecycle::LifecycleState) override;
+  void UpdateViewportIntersectionsForSubtree() override;
 
   bool GetIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
 
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index 73b88999..2b97ed8 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -74,7 +74,7 @@
     [CrossOrigin, Custom=Setter] attribute Window opener;
     [Replaceable, CrossOrigin] readonly attribute Window? parent;
     [CheckSecurity=ReturnValue, Custom=Getter] readonly attribute Element? frameElement;
-    [CallWith=(ExecutionContext,CurrentWindow,EnteredWindow), RaisesException] Window? open(optional [TreatNullAs=EmptyString] USVString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "");
+    [CallWith=(ExecutionContext,CurrentWindow,EnteredWindow), RaisesException] Window? open(optional [TreatNullAs=EmptyString] URLString url="", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "");
 
     // indexed properties
     // https://html.spec.whatwg.org/C/browsers.html#windowproxy-getownproperty
diff --git a/third_party/blink/renderer/core/html/media/html_audio_element.h b/third_party/blink/renderer/core/html/media/html_audio_element.h
index e00d8d9..87e78d0 100644
--- a/third_party/blink/renderer/core/html/media/html_audio_element.h
+++ b/third_party/blink/renderer/core/html/media/html_audio_element.h
@@ -50,7 +50,9 @@
       const WebString& remote_device_friendly_name) override {}
   void MediaRemotingStopped(WebLocalizedString::Name error_msg) override {}
   void PictureInPictureStopped() override { NOTREACHED(); }
-  void PictureInPictureControlClicked() override { NOTREACHED(); }
+  void PictureInPictureControlClicked(const WebString& control_id) override {
+    NOTREACHED();
+  }
 
  private:
   HTMLAudioElement(Document&);
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 87638ea..9ec32c4 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -554,9 +554,10 @@
       .OnExitedPictureInPicture(nullptr);
 }
 
-void HTMLVideoElement::PictureInPictureControlClicked() {
+void HTMLVideoElement::PictureInPictureControlClicked(
+    const WebString& control_id) {
   PictureInPictureController::From(GetDocument())
-      .OnPictureInPictureControlClicked();
+      .OnPictureInPictureControlClicked(control_id);
 }
 
 WebMediaPlayer::DisplayType HTMLVideoElement::DisplayType() const {
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h
index b4a5f476..9eabe30 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -149,7 +149,7 @@
   void MediaRemotingStarted(const WebString& remote_device_friendly_name) final;
   bool SupportsPictureInPicture() const final;
   void PictureInPictureStopped() final;
-  void PictureInPictureControlClicked() final;
+  void PictureInPictureControlClicked(const WebString& control_id) final;
   void MediaRemotingStopped(WebLocalizedString::Name error_msg) final;
   WebMediaPlayer::DisplayType DisplayType() const final;
   bool IsInAutoPIP() const final;
diff --git a/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index b5991e0..9b1a6882 100644
--- a/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -292,19 +292,16 @@
 }
 
 LayoutRect LayoutEmbeddedContent::ReplacedContentRect() const {
+  LayoutRect content_rect = ContentBoxRect();
+  // IFrames set as the root scroller should get their size from their parent.
+  if (ChildFrameView() && View() && RootScrollerUtil::IsEffective(*this))
+    content_rect = LayoutRect(LayoutPoint(), View()->ViewRect().Size());
+
   // We don't propagate sub-pixel into sub-frame layout, in other words, the
   // rect is snapped at the document boundary, and sub-pixel movement could
   // cause the sub-frame to layout due to the 1px snap difference. In order to
   // avoid that, the size of sub-frame is rounded in advance.
-  LayoutRect size_rounded_rect = ContentBoxRect();
-
-  // IFrames set as the root scroller should get their size from their parent.
-  if (ChildFrameView() && View() && RootScrollerUtil::IsEffective(*this))
-    size_rounded_rect = LayoutRect(LayoutPoint(), View()->ViewRect().Size());
-
-  size_rounded_rect.SetSize(
-      LayoutSize(RoundedIntSize(size_rounded_rect.Size())));
-  return size_rounded_rect;
+  return PreSnappedRectForPersistentSizing(content_rect);
 }
 
 void LayoutEmbeddedContent::UpdateOnEmbeddedContentViewChange() {
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.cc b/third_party/blink/renderer/core/layout/layout_replaced.cc
index f61b8984..34f4b1e 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -636,6 +636,11 @@
   return ComputeObjectFit();
 }
 
+LayoutRect LayoutReplaced::PreSnappedRectForPersistentSizing(LayoutRect rect) {
+  rect.SetSize(LayoutSize(RoundedIntSize(rect.Size())));
+  return rect;
+}
+
 void LayoutReplaced::ComputeIntrinsicSizingInfo(
     IntrinsicSizingInfo& intrinsic_sizing_info) const {
   if (ShouldApplySizeContainment()) {
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.h b/third_party/blink/renderer/core/layout/layout_replaced.h
index 6d403787..5074401 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -63,6 +63,12 @@
   // This function returns the local rect of the replaced content.
   virtual LayoutRect ReplacedContentRect() const;
 
+  // This is used by a few special elements, e.g. <video>, <iframe> to ensure
+  // a persistent sizing under different subpixel offset, because these
+  // elements have a high cost to resize. The drawback is that we may overflow
+  // or underflow the final content box by 1px.
+  static LayoutRect PreSnappedRectForPersistentSizing(LayoutRect);
+
   bool NeedsPreferredWidthsRecalculation() const override;
 
   // These values are specified to be 300 and 150 pixels in the CSS 2.1 spec.
diff --git a/third_party/blink/renderer/core/layout/layout_video.cc b/third_party/blink/renderer/core/layout/layout_video.cc
index dbb9797..964735e 100644
--- a/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/third_party/blink/renderer/core/layout/layout_video.cc
@@ -171,10 +171,7 @@
   if (ShouldDisplayVideo()) {
     // Video codecs may need to restart from an I-frame when the output is
     // resized. Round size in advance to avoid 1px snap difference.
-    // TODO(trchen): The way of rounding is different from LayoutEmbeddedContent
-    // just to match existing behavior. This is probably a bug and We should
-    // unify it with LayoutEmbeddedContent.
-    return LayoutRect(PixelSnappedIntRect(ComputeObjectFit()));
+    return PreSnappedRectForPersistentSizing(ComputeObjectFit());
   }
   // If we are displaying the poster image no pre-rounding is needed, but the
   // size of the image should be used for fitting instead.
diff --git a/third_party/blink/renderer/core/loader/idleness_detector.h b/third_party/blink/renderer/core/loader/idleness_detector.h
index 499bad86..e898c71 100644
--- a/third_party/blink/renderer/core/loader/idleness_detector.h
+++ b/third_party/blink/renderer/core/loader/idleness_detector.h
@@ -16,11 +16,11 @@
 class LocalFrame;
 class ResourceFetcher;
 
-// IdlenessDetector observes network request count everytime a load is
-// finshed after DOMContentLoadedEventEnd is fired, and emit network almost idle
-// signal when there are no more than 2 network connection active in 0.5 second,
-// and emit network idle signal when there is 0 network connection active in 0.5
-// second.
+// IdlenessDetector observes the resource request count every time a load is
+// finshed after DOMContentLoadedEventEnd is fired. It emits a network almost
+// idle signal when there are no more than 2 network connections active in 0.5
+// seconds, and a network idle signal when there are 0 network connections
+// active in 0.5 seconds.
 class CORE_EXPORT IdlenessDetector
     : public GarbageCollectedFinalized<IdlenessDetector>,
       public base::sequence_manager::TaskTimeObserver {
diff --git a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
index be4f3b59..ff6f60d8 100644
--- a/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
+++ b/third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h
@@ -20,7 +20,7 @@
 class PaintTiming;
 
 // FirstMeaningfulPaintDetector observes layout operations during page load
-// until network stable (2 seconds of no network activity), and computes the
+// until network stable (0.5 seconds of no network activity), and computes the
 // layout-based First Meaningful Paint.
 // See https://goo.gl/vpaxv6 and http://goo.gl/TEiMi4 for more details.
 class CORE_EXPORT FirstMeaningfulPaintDetector
diff --git a/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc b/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
index 63f4af4..d4c09dc 100644
--- a/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
+++ b/third_party/blink/renderer/core/scheduler/frame_throttling_test.cc
@@ -710,6 +710,9 @@
   // layout, but should still unthrottle the frame.
   frame_element->setAttribute(styleAttr, "transform: translateY(0px)");
   CompositeFrame();  // Unthrottle the frame.
+
+  EXPECT_FALSE(
+      frame_element->contentDocument()->View()->ShouldThrottleRendering());
   CompositeFrame();  // Handle the pending visual update of the unthrottled
                      // frame.
   EXPECT_EQ(DocumentLifecycle::kPaintClean,
diff --git a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
index bac492f..cb8714d 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
@@ -114,16 +114,6 @@
 TypeConverter<CredentialManagerError, AuthenticatorStatus>::Convert(
     const AuthenticatorStatus& status) {
   switch (status) {
-    case webauth::mojom::blink::AuthenticatorStatus::
-        AUTHENTICATOR_CRITERIA_UNSUPPORTED:
-      return CredentialManagerError::AUTHENTICATOR_CRITERIA_UNSUPPORTED;
-    case webauth::mojom::blink::AuthenticatorStatus::ALGORITHM_UNSUPPORTED:
-      return CredentialManagerError::ALGORITHM_UNSUPPORTED;
-    case webauth::mojom::blink::AuthenticatorStatus::EMPTY_ALLOW_CREDENTIALS:
-      return CredentialManagerError::EMPTY_ALLOW_CREDENTIALS;
-    case webauth::mojom::blink::AuthenticatorStatus::
-        USER_VERIFICATION_UNSUPPORTED:
-      return CredentialManagerError::USER_VERIFICATION_UNSUPPORTED;
     case webauth::mojom::blink::AuthenticatorStatus::NOT_ALLOWED_ERROR:
       return CredentialManagerError::NOT_ALLOWED;
     case webauth::mojom::blink::AuthenticatorStatus::UNKNOWN_ERROR:
@@ -140,6 +130,16 @@
       return CredentialManagerError::NOT_IMPLEMENTED;
     case webauth::mojom::blink::AuthenticatorStatus::NOT_FOCUSED:
       return CredentialManagerError::NOT_FOCUSED;
+    case webauth::mojom::blink::AuthenticatorStatus::ALGORITHM_UNSUPPORTED:
+      return CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED;
+    case webauth::mojom::blink::AuthenticatorStatus::EMPTY_ALLOW_CREDENTIALS:
+      return CredentialManagerError::ANDROID_EMPTY_ALLOW_CREDENTIALS;
+    case webauth::mojom::blink::AuthenticatorStatus::
+        ANDROID_NOT_SUPPORTED_ERROR:
+      return CredentialManagerError::ANDROID_NOT_SUPPORTED_ERROR;
+    case webauth::mojom::blink::AuthenticatorStatus::
+        USER_VERIFICATION_UNSUPPORTED:
+      return CredentialManagerError::ANDROID_USER_VERIFICATION_UNSUPPORTED;
     case webauth::mojom::blink::AuthenticatorStatus::SUCCESS:
       NOTREACHED();
       break;
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index 42b4d7a..72c17c6 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -219,30 +219,6 @@
           DOMExceptionCode::kNotAllowedError,
           "The operation either timed out or was not allowed. See: "
           "https://w3c.github.io/webauthn/#sec-assertion-privacy.");
-    case CredentialManagerError::AUTHENTICATOR_CRITERIA_UNSUPPORTED:
-      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
-                                  "The specified `authenticatorSelection` "
-                                  "criteria cannot be fulfilled by CTAP1/U2F "
-                                  "authenticators, and CTAP2 authenticators "
-                                  "are not yet supported.");
-    case CredentialManagerError::ALGORITHM_UNSUPPORTED:
-      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
-                                  "None of the algorithms specified in "
-                                  "`pubKeyCredParams` are compatible with "
-                                  "CTAP1/U2F authenticators, and CTAP2 "
-                                  "authenticators are not yet supported.");
-    case CredentialManagerError::EMPTY_ALLOW_CREDENTIALS:
-      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
-                                  "The `allowCredentials` list cannot be left "
-                                  "empty for CTAP1/U2F authenticators, and "
-                                  "support for CTAP2 authenticators is not yet "
-                                  "implemented.");
-    case CredentialManagerError::USER_VERIFICATION_UNSUPPORTED:
-      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
-                                  "The specified `userVerification` "
-                                  "requirement cannot be fulfilled by "
-                                  "CTAP1/U2F authenticators, and CTAP2 "
-                                  "authenticators are not yet supported.");
     case CredentialManagerError::INVALID_DOMAIN:
       return DOMException::Create(DOMExceptionCode::kSecurityError,
                                   "This is an invalid domain.");
@@ -263,6 +239,26 @@
       return DOMException::Create(DOMExceptionCode::kNotAllowedError,
                                   "The operation is not allowed at this time "
                                   "because the page does not have focus.");
+    case CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED:
+      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                                  "None of the algorithms specified in "
+                                  "`pubKeyCredParams` are supported by "
+                                  "this device.");
+    case CredentialManagerError::ANDROID_EMPTY_ALLOW_CREDENTIALS:
+      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                                  "Use of an empty `allowCredentials` list is "
+                                  "not supported on this device.");
+    case CredentialManagerError::ANDROID_NOT_SUPPORTED_ERROR:
+      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                                  "Either the device has received unexpected "
+                                  "request parameters, or the device "
+                                  "cannot support this request.");
+    case CredentialManagerError::ANDROID_USER_VERIFICATION_UNSUPPORTED:
+      return DOMException::Create(DOMExceptionCode::kNotSupportedError,
+                                  "The specified `userVerification` "
+                                  "requirement cannot be fulfilled by "
+                                  "this device unless the device is secured "
+                                  "with a screen lock.");
     case CredentialManagerError::UNKNOWN:
       return DOMException::Create(DOMExceptionCode::kNotReadableError,
                                   "An unknown error occurred while talking "
diff --git a/third_party/blink/renderer/modules/permissions/permissions.cc b/third_party/blink/renderer/modules/permissions/permissions.cc
index 795677a..20d74e84 100644
--- a/third_party/blink/renderer/modules/permissions/permissions.cc
+++ b/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -8,9 +8,9 @@
 #include <utility>
 
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_clipboard_permission_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_midi_permission_descriptor.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_permission_descriptor.h"
@@ -47,7 +47,7 @@
 // current context. The caller should make sure that no assumption is made
 // after this has been called.
 PermissionDescriptorPtr ParsePermission(ScriptState* script_state,
-                                        const Dictionary raw_permission,
+                                        const ScriptValue raw_permission,
                                         ExceptionState& exception_state) {
   PermissionDescriptor permission =
       NativeValueTraits<PermissionDescriptor>::NativeValue(
@@ -144,7 +144,7 @@
 }  // anonymous namespace
 
 ScriptPromise Permissions::query(ScriptState* script_state,
-                                 const Dictionary& raw_permission,
+                                 const ScriptValue& raw_permission,
                                  ExceptionState& exception_state) {
   PermissionDescriptorPtr descriptor =
       ParsePermission(script_state, raw_permission, exception_state);
@@ -168,7 +168,7 @@
 }
 
 ScriptPromise Permissions::request(ScriptState* script_state,
-                                   const Dictionary& raw_permission,
+                                   const ScriptValue& raw_permission,
                                    ExceptionState& exception_state) {
   PermissionDescriptorPtr descriptor =
       ParsePermission(script_state, raw_permission, exception_state);
@@ -195,7 +195,7 @@
 }
 
 ScriptPromise Permissions::revoke(ScriptState* script_state,
-                                  const Dictionary& raw_permission,
+                                  const ScriptValue& raw_permission,
                                   ExceptionState& exception_state) {
   PermissionDescriptorPtr descriptor =
       ParsePermission(script_state, raw_permission, exception_state);
@@ -215,14 +215,15 @@
   return promise;
 }
 
-ScriptPromise Permissions::requestAll(ScriptState* script_state,
-                                      const Vector<Dictionary>& raw_permissions,
-                                      ExceptionState& exception_state) {
+ScriptPromise Permissions::requestAll(
+    ScriptState* script_state,
+    const Vector<ScriptValue>& raw_permissions,
+    ExceptionState& exception_state) {
   Vector<PermissionDescriptorPtr> internal_permissions;
   Vector<int> caller_index_to_internal_index;
   caller_index_to_internal_index.resize(raw_permissions.size());
   for (size_t i = 0; i < raw_permissions.size(); ++i) {
-    const Dictionary& raw_permission = raw_permissions[i];
+    const ScriptValue& raw_permission = raw_permissions[i];
 
     auto descriptor =
         ParsePermission(script_state, raw_permission, exception_state);
diff --git a/third_party/blink/renderer/modules/permissions/permissions.h b/third_party/blink/renderer/modules/permissions/permissions.h
index b753e856..cfe417b 100644
--- a/third_party/blink/renderer/modules/permissions/permissions.h
+++ b/third_party/blink/renderer/modules/permissions/permissions.h
@@ -12,20 +12,20 @@
 
 namespace blink {
 
-class Dictionary;
 class ExecutionContext;
 class ScriptPromiseResolver;
 class ScriptState;
+class ScriptValue;
 
 class Permissions final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  ScriptPromise query(ScriptState*, const Dictionary&, ExceptionState&);
-  ScriptPromise request(ScriptState*, const Dictionary&, ExceptionState&);
-  ScriptPromise revoke(ScriptState*, const Dictionary&, ExceptionState&);
+  ScriptPromise query(ScriptState*, const ScriptValue&, ExceptionState&);
+  ScriptPromise request(ScriptState*, const ScriptValue&, ExceptionState&);
+  ScriptPromise revoke(ScriptState*, const ScriptValue&, ExceptionState&);
   ScriptPromise requestAll(ScriptState*,
-                           const Vector<Dictionary>&,
+                           const Vector<ScriptValue>&,
                            ExceptionState&);
 
  private:
diff --git a/third_party/blink/renderer/modules/permissions/permissions.idl b/third_party/blink/renderer/modules/permissions/permissions.idl
index 3c43fccb..c66fe36 100644
--- a/third_party/blink/renderer/modules/permissions/permissions.idl
+++ b/third_party/blink/renderer/modules/permissions/permissions.idl
@@ -9,8 +9,10 @@
     Exposed=(Window,Worker),
     RuntimeEnabled=Permissions
 ] interface Permissions {
-    [CallWith=ScriptState, RaisesException, Measure] Promise<PermissionStatus> query(Dictionary permission);
-    [RuntimeEnabled=PermissionsRequestRevoke, CallWith=ScriptState, RaisesException, Measure] Promise<PermissionStatus> request(Dictionary permissions);
-    [RuntimeEnabled=PermissionsRequestRevoke, CallWith=ScriptState, RaisesException, Measure] Promise<PermissionStatus> revoke(Dictionary permission);
-    [RuntimeEnabled=PermissionsRequestRevoke, CallWith=ScriptState, RaisesException, Measure] Promise<sequence<PermissionStatus>> requestAll(sequence<Dictionary> permissions);
+    [CallWith=ScriptState, RaisesException, Measure] Promise<PermissionStatus> query(object permission);
+
+    // Non standard APIs
+    [RuntimeEnabled=PermissionsRequestRevoke, CallWith=ScriptState, RaisesException, Measure] Promise<PermissionStatus> request(object permissions);
+    [RuntimeEnabled=PermissionsRequestRevoke, CallWith=ScriptState, RaisesException, Measure] Promise<PermissionStatus> revoke(object permission);
+    [RuntimeEnabled=PermissionsRequestRevoke, CallWith=ScriptState, RaisesException, Measure] Promise<sequence<PermissionStatus>> requestAll(sequence<object> permissions);
 };
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
index a7d40cb..34ee29bc 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
+++ b/third_party/blink/renderer/modules/picture_in_picture/html_video_element_picture_in_picture.idl
@@ -15,5 +15,4 @@
     [RuntimeEnabled=PictureInPictureControl] attribute EventHandler onpictureinpicturecontrolclick;
 
     [CEReactions, Measure, Reflect] attribute boolean disablePictureInPicture;
-
 };
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index 3abee02..75819a5 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -162,21 +162,19 @@
     resolver->Resolve();
 }
 
-void PictureInPictureControllerImpl::OnPictureInPictureControlClicked() {
+void PictureInPictureControllerImpl::OnPictureInPictureControlClicked(
+    const WebString& control_id) {
   DCHECK(GetSupplementable());
 
   // Bail out if document is not active.
   if (!GetSupplementable()->IsActive())
     return;
 
-  // TODO(crbug/856251): Allow for different strings to be passed in here.
-  // Current string is a placeholder.
   if (RuntimeEnabledFeatures::PictureInPictureControlEnabled() &&
       picture_in_picture_element_) {
     picture_in_picture_element_->DispatchEvent(
         PictureInPictureControlEvent::Create(
-            EventTypeNames::pictureinpicturecontrolclick,
-            "placeholder_event_name"));
+            EventTypeNames::pictureinpicturecontrolclick, control_id));
   }
 }
 
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
index ca01ebf..45b0e6a 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
@@ -59,7 +59,7 @@
                              ScriptPromiseResolver*) override;
   void ExitPictureInPicture(HTMLVideoElement*, ScriptPromiseResolver*) override;
   void OnExitedPictureInPicture(ScriptPromiseResolver*) override;
-  void OnPictureInPictureControlClicked() override;
+  void OnPictureInPictureControlClicked(const WebString& control_id) override;
   Status IsElementAllowed(const HTMLVideoElement&) const override;
   bool IsPictureInPictureElement(const Element*) const override;
 
diff --git a/third_party/blink/renderer/modules/webusb/usb_alternate_interface.idl b/third_party/blink/renderer/modules/webusb/usb_alternate_interface.idl
index b7796e1..20cfe45 100644
--- a/third_party/blink/renderer/modules/webusb/usb_alternate_interface.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_alternate_interface.idl
@@ -7,7 +7,8 @@
 [
     Constructor(USBInterface deviceInterface, octet alternateSetting),
     Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
-    RaisesException=Constructor
+    RaisesException=Constructor,
+    SecureContext
 ] interface USBAlternateInterface {
     readonly attribute octet alternateSetting;
     readonly attribute octet interfaceClass;
diff --git a/third_party/blink/renderer/modules/webusb/usb_configuration.idl b/third_party/blink/renderer/modules/webusb/usb_configuration.idl
index 42272e0..a4ebe75 100644
--- a/third_party/blink/renderer/modules/webusb/usb_configuration.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_configuration.idl
@@ -7,7 +7,8 @@
 [
     Constructor(USBDevice device, octet configurationValue),
     Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
-    RaisesException=Constructor
+    RaisesException=Constructor,
+    SecureContext
 ] interface USBConfiguration {
     readonly attribute octet configurationValue;
     readonly attribute DOMString? configurationName;
diff --git a/third_party/blink/renderer/modules/webusb/usb_connection_event.idl b/third_party/blink/renderer/modules/webusb/usb_connection_event.idl
index a2b6778..ed62a8e 100644
--- a/third_party/blink/renderer/modules/webusb/usb_connection_event.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_connection_event.idl
@@ -6,7 +6,8 @@
 
 [
     Constructor(DOMString type, USBConnectionEventInit eventInitDict),
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB)
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
+    SecureContext
 ] interface USBConnectionEvent : Event {
     [SameObject] readonly attribute USBDevice device;
 };
diff --git a/third_party/blink/renderer/modules/webusb/usb_device.idl b/third_party/blink/renderer/modules/webusb/usb_device.idl
index e9f797c0..bff5d2ed 100644
--- a/third_party/blink/renderer/modules/webusb/usb_device.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_device.idl
@@ -13,7 +13,8 @@
 // https://wicg.github.io/webusb/#device-usage
 
 [
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB)
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
+    SecureContext
 ] interface USBDevice {
     readonly attribute octet usbVersionMajor;
     readonly attribute octet usbVersionMinor;
diff --git a/third_party/blink/renderer/modules/webusb/usb_endpoint.idl b/third_party/blink/renderer/modules/webusb/usb_endpoint.idl
index 1b8b735..80d5298 100644
--- a/third_party/blink/renderer/modules/webusb/usb_endpoint.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_endpoint.idl
@@ -18,7 +18,8 @@
 [
     Constructor(USBAlternateInterface alternate, octet endpointNumber, USBDirection direction),
     Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
-    RaisesException=Constructor
+    RaisesException=Constructor,
+    SecureContext
 ] interface USBEndpoint {
     readonly attribute octet endpointNumber;
     readonly attribute USBDirection direction;
diff --git a/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.idl b/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.idl
index 87926664..3efc62c 100644
--- a/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_in_transfer_result.idl
@@ -6,7 +6,8 @@
 
 [
     Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
-    Constructor(USBTransferStatus status, optional DataView? data)
+    Constructor(USBTransferStatus status, optional DataView? data),
+    SecureContext
 ] interface USBInTransferResult {
     readonly attribute DataView? data;
     readonly attribute USBTransferStatus status;
diff --git a/third_party/blink/renderer/modules/webusb/usb_interface.idl b/third_party/blink/renderer/modules/webusb/usb_interface.idl
index 3eba4678..a25d466 100644
--- a/third_party/blink/renderer/modules/webusb/usb_interface.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_interface.idl
@@ -7,7 +7,8 @@
 [
     Constructor(USBConfiguration configuration, octet interfaceNumber),
     Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
-    RaisesException=Constructor
+    RaisesException=Constructor,
+    SecureContext
 ] interface USBInterface {
     readonly attribute octet interfaceNumber;
     readonly attribute USBAlternateInterface? alternate;
diff --git a/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.idl b/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.idl
index d32e452..313adbb9 100644
--- a/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_packet.idl
@@ -6,7 +6,8 @@
 
 [
     Constructor(USBTransferStatus status, optional DataView? data),
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB)
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
+    SecureContext
 ] interface USBIsochronousInTransferPacket {
     readonly attribute USBTransferStatus status;
     readonly attribute DataView? data;
diff --git a/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.idl b/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.idl
index 9fdde34..0d6b8187 100644
--- a/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_isochronous_in_transfer_result.idl
@@ -6,7 +6,8 @@
 
 [
     Constructor(sequence<USBIsochronousInTransferPacket> packets, optional DataView? data),
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB)
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
+    SecureContext
 ] interface USBIsochronousInTransferResult {
     readonly attribute DataView? data;
     readonly attribute FrozenArray<USBIsochronousInTransferPacket> packets;
diff --git a/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_packet.idl b/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_packet.idl
index b011f3fc..f080b0e4 100644
--- a/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_packet.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_packet.idl
@@ -6,7 +6,8 @@
 
 [
     Constructor(USBTransferStatus status, optional unsigned long bytesWritten = 0),
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB)
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
+    SecureContext
 ] interface USBIsochronousOutTransferPacket {
     readonly attribute unsigned long bytesWritten;
     readonly attribute USBTransferStatus status;
diff --git a/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_result.idl b/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_result.idl
index ba9f266..01e6940 100644
--- a/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_result.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_isochronous_out_transfer_result.idl
@@ -6,7 +6,8 @@
 
 [
     Constructor(sequence<USBIsochronousOutTransferPacket> packets),
-    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB)
+    Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
+    SecureContext
 ] interface USBIsochronousOutTransferResult {
     readonly attribute FrozenArray<USBIsochronousOutTransferPacket> packets;
 };
diff --git a/third_party/blink/renderer/modules/webusb/usb_out_transfer_result.idl b/third_party/blink/renderer/modules/webusb/usb_out_transfer_result.idl
index b67e1f36..b68561e1 100644
--- a/third_party/blink/renderer/modules/webusb/usb_out_transfer_result.idl
+++ b/third_party/blink/renderer/modules/webusb/usb_out_transfer_result.idl
@@ -6,7 +6,8 @@
 
 [
     Exposed(DedicatedWorker WebUSBOnDedicatedWorkers, SharedWorker WebUSBOnSharedWorkers, Window WebUSB),
-    Constructor(USBTransferStatus status, optional unsigned long bytesWritten = 0)
+    Constructor(USBTransferStatus status, optional unsigned long bytesWritten = 0),
+    SecureContext
 ] interface USBOutTransferResult {
     readonly attribute unsigned long bytesWritten;
     readonly attribute USBTransferStatus status;
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index 906e20e..5bc6c3d9 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -71,6 +71,8 @@
     compositor_frame_sink_->SetNeedsBeginFrame(is_rendering_ && should_submit_);
     if (should_submit_)
       SubmitSingleFrame();
+    else if (!frame_size_.IsEmpty())
+      SubmitEmptyFrame();
   }
 }
 
@@ -194,11 +196,15 @@
   if (!compositor_frame_sink_ || !should_submit_)
     return;
 
+  // TODO(mlamouri): the `frame_size_` is expected to be consistent but seems to
+  // change in some cases. Ideally, it should be set when empty and a DCHECK
+  // should make sure it stays consistent.
+  frame_size_ = gfx::Rect(video_frame->coded_size());
+
   viz::CompositorFrame compositor_frame;
   std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
 
-  render_pass->SetNew(1, gfx::Rect(video_frame->coded_size()),
-                      gfx::Rect(video_frame->coded_size()), gfx::Transform());
+  render_pass->SetNew(1, frame_size_, frame_size_, gfx::Transform());
   render_pass->filters = cc::FilterOperations();
   resource_provider_->AppendQuads(render_pass.get(), video_frame, rotation_);
   compositor_frame.metadata.begin_frame_ack = begin_frame_ack;
@@ -225,6 +231,28 @@
   waiting_for_compositor_ack_ = true;
 }
 
+void VideoFrameSubmitter::SubmitEmptyFrame() {
+  TRACE_EVENT0("media", "VideoFrameSubmitter::SubmitEmptyFrame");
+  DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
+  DCHECK(compositor_frame_sink_ && !should_submit_);
+  DCHECK(!frame_size_.IsEmpty());
+
+  viz::CompositorFrame compositor_frame;
+
+  compositor_frame.metadata.begin_frame_ack =
+      viz::BeginFrameAck::CreateManualAckWithDamage();
+  compositor_frame.metadata.device_scale_factor = 1;
+  compositor_frame.metadata.may_contain_video = true;
+
+  std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
+  render_pass->SetNew(1, frame_size_, frame_size_, gfx::Transform());
+  compositor_frame.render_pass_list.push_back(std::move(render_pass));
+
+  compositor_frame_sink_->SubmitCompositorFrame(
+      surface_id_.local_surface_id(), std::move(compositor_frame), nullptr, 0);
+  waiting_for_compositor_ack_ = true;
+}
+
 void VideoFrameSubmitter::OnBeginFrame(const viz::BeginFrameArgs& args) {
   TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame");
   DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
@@ -273,10 +301,11 @@
   }
   waiting_for_compositor_ack_ = false;
 
+  resource_provider_->OnContextLost();
+
   // |compositor_frame_sink_| should be reset last.
   compositor_frame_sink_.reset();
 
-  resource_provider_->OnContextLost();
   context_provider_callback_.Run(
       base::BindOnce(&VideoFrameSubmitter::OnReceivedContextProvider,
                      weak_ptr_factory_.GetWeakPtr()));
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
index aa95cf0..06325b3 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.h
@@ -92,6 +92,7 @@
   void StartSubmitting();
   void UpdateSubmissionStateInternal();
   void SubmitFrame(const viz::BeginFrameAck&, scoped_refptr<media::VideoFrame>);
+  void SubmitEmptyFrame();
 
   // Pulls frame and submits it to compositor.
   // Used in cases like PaintSingleFrame, which occurs before video rendering
@@ -114,6 +115,11 @@
   bool should_submit_ = false;
   media::VideoRotation rotation_;
 
+  // Size of the video frame being submitted. It is set the first time a frame
+  // is submitted and is expected to never change aftewards. Used to send an
+  // empty frame when the video is out of view.
+  gfx::Rect frame_size_;
+
   THREAD_CHECKER(media_thread_checker_);
 
   base::WeakPtrFactory<VideoFrameSubmitter> weak_ptr_factory_;
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
index 4512c5f..3b805de 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter_test.cc
@@ -287,7 +287,7 @@
       .WillOnce(Return(media::VideoFrame::CreateFrame(
           media::PIXEL_FORMAT_YV12, gfx::Size(8, 8), gfx::Rect(gfx::Size(8, 8)),
           gfx::Size(8, 8), base::TimeDelta())));
-  EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _));
+  EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
   EXPECT_CALL(*provider_, PutCurrentFrame());
   EXPECT_CALL(*resource_provider_, AppendQuads(_, _, _));
   EXPECT_CALL(*resource_provider_, PrepareSendToParent(_, _));
@@ -296,6 +296,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   EXPECT_CALL(*sink_, SetNeedsBeginFrame(false));
+  EXPECT_CALL(*sink_, DoSubmitCompositorFrame(_, _)).Times(1);
+  EXPECT_CALL(*provider_, GetCurrentFrame()).Times(0);
   submitter_->UpdateSubmissionState(false);
   scoped_task_environment_.RunUntilIdle();
 
diff --git a/third_party/closure_compiler/compile_js2.gypi b/third_party/closure_compiler/compile_js2.gypi
deleted file mode 100644
index 2c583ef..0000000
--- a/third_party/closure_compiler/compile_js2.gypi
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
-  'type': 'none',
-
-  'variables': {
-    'CLOSURE_DIR': '<(DEPTH)/third_party/closure_compiler',
-    'EXTERNS_GYP': '<(CLOSURE_DIR)/externs/compiled_resources2.gyp',
-    'INTERFACES_GYP': '<(CLOSURE_DIR)/interfaces/compiled_resources2.gyp',
-
-    'default_source_file': '<(_target_name).js',
-    'source_files%': ['<(default_source_file)'],
-    'extra_inputs%': [],
-
-    'includes': ['closure_args.gypi'],
-  },
-
-  'sources': ['<@(source_files)'],
-
-  'all_dependent_settings': {
-    'sources': ['<@(source_files)'],
-  },
-
-  'actions': [
-    {
-      'action_name': 'compile_js',
-
-      # This action optionally takes these arguments:
-      # - sources: a list of all of the source files to be compiled.
-      #            If sources is undefined, a default of ['<(_target_name).js']
-      #            is created (this probably suffices for many targets).
-      # - out_file: a file where the compiled output is written to. The default
-      #             is gen/closure/<path to |target_name|>/|target_name|.js.
-      # - script_args: additional arguments to pass to compile2.py.
-      # - closure_args: additional arguments to pass to the Closure compiler.
-      # - disabled_closure_args: additional arguments dealing with the
-      #                          strictness of compilation; Non-strict
-      #                          defaults are provided that can be overriden.
-      'variables': {
-        'target_path': '<!(python <(CLOSURE_DIR)/build/outputs.py <(default_source_file))',
-        'out_file%': '<(SHARED_INTERMEDIATE_DIR)/closure/<(target_path)',
-        # TODO(dbeam): remove when no longer used from remoting/.
-        'script_args%': [],
-        'closure_args%': '<(default_closure_args)',
-        'disabled_closure_args%': '<(default_disabled_closure_args)',
-      },
-
-      'inputs': [
-        '<(CLOSURE_DIR)/build/outputs.py',
-        '<(CLOSURE_DIR)/closure_args.gypi',
-        '<(CLOSURE_DIR)/compile2.py',
-        '<(CLOSURE_DIR)/compile_js2.gypi',
-        '<(CLOSURE_DIR)/compiler/compiler.jar',
-        '<(CLOSURE_DIR)/include_js.gypi',
-        '<(CLOSURE_DIR)/processor.py',
-        '>@(_sources)',
-        # When converting to GN, write the paths to additional inputs in a GN
-        # depfile file instead.
-        '<@(extra_inputs)',
-      ],
-
-      'outputs': ['<(out_file)'],
-
-      'action': [
-        'python',
-        '<(CLOSURE_DIR)/compile2.py',
-        '<@(script_args)',
-        '>@(_sources)',
-        '--out_file', '<(out_file)',
-        '--closure_args', '<@(closure_args)', '<@(disabled_closure_args)',
-        # '--verbose' # for make glorious log spam of Closure compiler.
-      ],
-
-      'message': 'Compiling <(target_path)',
-    },
-  ],
-}
diff --git a/third_party/closure_compiler/compiled_resources2.gyp b/third_party/closure_compiler/compiled_resources2.gyp
deleted file mode 100644
index 1ab2cdf..0000000
--- a/third_party/closure_compiler/compiled_resources2.gyp
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-#
-# Add your directory-specific .gyp file to this list for it to be continuously
-# typechecked on the builder:
-# http://build.chromium.org/p/chromium.fyi/builders/Closure%20Compilation%20Linux
-#
-# Also, see our guide to Closure compilation in chrome:
-# https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md
-{
-  'targets': [
-    {
-      'target_name': 'compiled_resources2',
-      'type': 'none',
-      'dependencies': [
-      ],
-    },
-  ]
-}
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js
index bb81dcd..23db62b 100644
--- a/third_party/closure_compiler/externs/file_manager_private.js
+++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -215,6 +215,13 @@
   NATIVE_OR_DRIVE_SOURCE: 'native_or_drive_source',
 };
 
+/** @enum {string} */
+chrome.fileManagerPrivate.InstallLinuxPackageResponse = {
+  STARTED: 'started',
+  FAILED: 'failed',
+  INSTALL_ALREADY_ACTIVE: 'install_already_active',
+};
+
 /**
  * @typedef {{
  *   taskId: string,
@@ -941,6 +948,15 @@
  */
 chrome.fileManagerPrivate.mountCrostiniContainer = function(callback) {};
 
+/**
+ * Begin installation of a Linux package.
+ * @param {!Entry} entry
+ * @param {function(!chrome.fileManagerPrivate.InstallLinuxPackageResponse,
+ *    string)} callback
+ *    Called when the installation is either started or fails to start.
+ */
+chrome.fileManagerPrivate.installLinuxPackage = function(entry, callback) {};
+
 /** @type {!ChromeEvent} */
 chrome.fileManagerPrivate.onMountCompleted;
 
diff --git a/third_party/closure_compiler/include_js.gypi b/third_party/closure_compiler/include_js.gypi
deleted file mode 100644
index 32fbc3f..0000000
--- a/third_party/closure_compiler/include_js.gypi
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
-  'type': 'none',
-  'all_dependent_settings': {
-    'sources': ['<(_target_name).js'],
-  },
-}
diff --git a/third_party/closure_compiler/run_compiler b/third_party/closure_compiler/run_compiler
deleted file mode 100755
index 10f5609f..0000000
--- a/third_party/closure_compiler/run_compiler
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-readonly SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
-cd "$SCRIPT_DIR/../.."  # src/.
-
-export GYP_GENERATORS="ninja"
-
-tools/gyp/gyp --no-circular-check third_party/closure_compiler/compiled_resources2.gyp
-
-os_name=`uname -s`
-cores_count=1
-case "$os_name" in
-  "Darwin") cores_count=`sysctl -n hw.ncpu` ;;
-  "Linux") cores_count=`nproc` ;;
-esac
-
-ninja -C out/Default -j $cores_count $@
diff --git a/third_party/closure_compiler/tools/create_include_gyp.py b/third_party/closure_compiler/tools/create_include_gyp.py
deleted file mode 100755
index cef8aaf..0000000
--- a/third_party/closure_compiler/tools/create_include_gyp.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python
-# 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.
-#
-# Usage:
-#
-#   cd third_party/closure_compiler
-#   tools/create_include_gyp.py externs > externs/compiled_resources2.gyp
-#   tools/create_include_gyp.py interfaces > interfaces/compiled_resources2.gyp
-
-from datetime import date
-import os
-import sys
-
-
-_INCLUDE_GYPI = os.path.join(os.path.dirname(__file__), '..', 'include_js.gypi')
-
-
-_INCLUDE_TEMPLATE = """
-# Copyright %d 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.
-
-########################################################
-#    NOTE: THIS FILE IS GENERATED. DO NOT EDIT IT!     #
-# Instead, run create_include_gyp.py to regenerate it. #
-########################################################
-{
-  'targets': [
-    %s,
-  ],
-}""".lstrip()
-
-
-_TARGET_TEMPLATE_NO_CHROME_DEPENDENCY = """
-    {
-      'target_name': '%s',
-      'includes': ['%s'],
-    }"""
-
-_TARGET_TEMPLATE = """
-    {
-      'target_name': '%s',
-      'dependencies': ['chrome'],
-      'includes': ['%s'],
-    }"""
-
-# Add externs files that do not depend on chrome.* namespace here. Everything
-# else will have chrome.js as a dependency.
-NO_CHROME_DEPENDENCY = set([
-  'chrome.js',
-  'mojo.js',
-  'pending.js',
-  'polymer-1.0.js',
-  'web_animations.js',
-])
-
-def CreateIncludeGyp(directory):
-  include_path = os.path.normpath(os.path.relpath(_INCLUDE_GYPI, directory))
-  js_files = [f for f in os.listdir(directory) if f.endswith('.js')]
-  js_files.sort()
-
-  targets = []
-  for f in js_files:
-    template = (_TARGET_TEMPLATE_NO_CHROME_DEPENDENCY if f in
-                NO_CHROME_DEPENDENCY else _TARGET_TEMPLATE)
-    targets.append(template % (f[:-3], include_path))
-  return _INCLUDE_TEMPLATE % (date.today().year, ",".join(targets).strip())
-
-
-def ShowUsageAndDie():
-  print "usage: tools/create_include_gyp.py externs/ > externs/compiled_resources2.gyp"
-  sys.exit(1)
-
-
-if __name__ == "__main__":
-  if len(sys.argv) != 2:
-    ShowUsageAndDie()
-
-  print CreateIncludeGyp(sys.argv[1])
diff --git a/third_party/fuchsia-sdk/BUILD.gn b/third_party/fuchsia-sdk/BUILD.gn
index 727ae8b..2446fa4 100644
--- a/third_party/fuchsia-sdk/BUILD.gn
+++ b/third_party/fuchsia-sdk/BUILD.gn
@@ -172,6 +172,7 @@
   ]
   deps = [
     ":images",
+    ":vectorial",
   ]
 }
 
@@ -301,6 +302,15 @@
   ]
 }
 
+fuchsia_sdk_fidl_pkg("vectorial") {
+  namespace = "fuchsia.ui"
+  namespace_path = "fuchsia/ui"
+  sources = [
+    "commands.fidl",
+    "events.fidl",
+  ]
+}
+
 fuchsia_sdk_fidl_pkg("views") {
   namespace = "fuchsia.ui"
   namespace_path = "fuchsia/ui"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 471f4103..88e9494 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -16078,6 +16078,7 @@
   <int value="1260" label="SYSTEM_POWER_SOURCE_REQUESTSTATUSUPDATE"/>
   <int value="1261" label="INPUTMETHODPRIVATE_GETSURROUNDINGTEXT"/>
   <int value="1262" label="USERSPRIVATE_GETLOGINSTATUS"/>
+  <int value="1263" label="FILEMANAGERPRIVATEINTERNAL_INSTALLLINUXPACKAGE"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -25387,6 +25388,7 @@
   <int value="36" label="SERVER_FORBIDDEN"/>
   <int value="37" label="SERVER_UNREACHABLE"/>
   <int value="38" label="SERVER_CONTENT_LENGTH_MISMATCH"/>
+  <int value="39" label="SERVER_CROSS_ORIGIN_REDIRECT"/>
   <int value="40" label="USER_CANCELED"/>
   <int value="41" label="USER_SHUTDOWN"/>
   <int value="50" label="CRASH"/>
@@ -35187,6 +35189,12 @@
   <int value="4" label="auto, enabled in trial"/>
 </enum>
 
+<enum name="OmniboxDocumentSuggestRequests">
+  <int value="1" label="requests sent"/>
+  <int value="2" label="requests invalidated"/>
+  <int value="3" label="(non-invalidated) replies received"/>
+</enum>
+
 <enum name="OmniboxEnteredKeywordMode">
   <int value="0" label="via tab"/>
   <int value="1" label="via space at end"/>
@@ -35271,6 +35279,7 @@
   <int value="1219" label="APP from on-device service"/>
   <int value="1220" label="LEGACY_ON_DEVICE from on-device service"/>
   <int value="1424" label="CLIPBOARD from Clipboard provider"/>
+  <int value="1627" label="DOCUMENT via DocumentProvider"/>
 </enum>
 
 <enum name="OmniboxProviderType">
@@ -35288,6 +35297,8 @@
   <int value="12" label="on device (only used by Android GSA)"/>
   <int value="13" label="on device chrome (chrome content provider)"/>
   <int value="14" label="clipboard provider"/>
+  <int value="15" label="deprecated: Physical Web"/>
+  <int value="16" label="DocumentProvider"/>
 </enum>
 
 <enum name="OmniboxSearchEngine">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 5a66d927..a877f51 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -64594,6 +64594,24 @@
   </summary>
 </histogram>
 
+<histogram name="Omnibox.DocumentSuggest.Requests"
+    enum="OmniboxDocumentSuggestRequests">
+  <owner>skare@chromium.org</owner>
+  <summary>
+    Counts the number of document suggest requests the omnibox sent, were
+    invalidated, and were completed successfully.
+  </summary>
+</histogram>
+
+<histogram name="Omnibox.DocumentSuggest.ResultCount" units="count"
+    expires_after="M72">
+  <owner>skare@chromium.org</owner>
+  <summary>
+    Number of results returned in each document suggestion reply. Logged for
+    successful requests where the provider returned a parseable result set.
+  </summary>
+</histogram>
+
 <histogram name="Omnibox.EnteredKeywordMode" enum="OmniboxEnteredKeywordMode">
   <owner>mpearson@chromium.org</owner>
   <summary>
@@ -70134,6 +70152,16 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordProtection.ReferrerChainSize" units="referrers"
+    expires_after="M71">
+  <owner>drubery@chromium.org</owner>
+  <owner>jialiul@chromium.org</owner>
+  <summary>
+    The referrer chain size of a password protection request. This is recorded
+    when Chrome receives a verdict for this request.
+  </summary>
+</histogram>
+
 <histogram name="PasswordProtection.RequestNetworkDuration" units="ms">
   <owner>jialiul@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
@@ -123266,6 +123294,15 @@
   <affected-histogram name="PasswordProtection.Verdict"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PasswordProtectionVerdict" separator=".">
+  <suffix name="LowReputation"
+      label="Password protection reponse with low reputation verdict"/>
+  <suffix name="Phishing"
+      label="Password protection response with phishing verdict"/>
+  <suffix name="Safe" label="Password protection response with safe verdict"/>
+  <affected-histogram name="PasswordProtection.ReferrerChainSize"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PasswordReuseSourceRealm" separator=".">
   <suffix name="FromHttpRealm"
       label="The account in question was saved on an HTTP site."/>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 7676a79..729deda7 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -56,8 +56,8 @@
 start_with_url.cold.startup_pages,"pasko@chromium.org, chrome-android-perf-status@chromium.org",,
 start_with_url.warm.startup_pages,"pasko@chromium.org, chrome-android-perf-status@chromium.org",,
 supersize_archive,agrieve@chromium.org,,
-system_health.common_desktop,"charliea@chromium.org, sullivan@chromium.org, tdresser@chromium.org",,https://bit.ly/system-health-benchmarks
-system_health.common_mobile,"charliea@chromium.org, sullivan@chromium.org, tdresser@chromium.org, perezju@chromium.org",,https://bit.ly/system-health-benchmarks
+system_health.common_desktop,"charliea@chromium.org, sullivan@chromium.org, tdresser@chromium.org, chrome-speed-metrics-dev@chromium.org",Speed>Metrics>SystemHealthRegressions,https://bit.ly/system-health-benchmarks
+system_health.common_mobile,"charliea@chromium.org, sullivan@chromium.org, tdresser@chromium.org, perezju@chromium.org, chrome-speed-metrics-dev@chromium.org",Speed>Metrics>SystemHealthRegressions,https://bit.ly/system-health-benchmarks
 system_health.memory_desktop,perezju@chromium.org,,https://bit.ly/system-health-benchmarks
 system_health.memory_mobile,perezju@chromium.org,,https://bit.ly/system-health-benchmarks
 system_health.webview_startup,"perezju@chromium.org, torne@chromium.org, changwan@chromium.org",Mobile>WebView>Perf,
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index b9cd5854..36f404b 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -59,7 +59,9 @@
 
 
 @benchmark.Info(emails=['charliea@chromium.org', 'sullivan@chromium.org',
-                        'tdresser@chromium.org'],
+                        'tdresser@chromium.org',
+                        'chrome-speed-metrics-dev@chromium.org'],
+                component='Speed>Metrics>SystemHealthRegressions',
                 documentation_url='https://bit.ly/system-health-benchmarks')
 class DesktopCommonSystemHealth(_CommonSystemHealthBenchmark):
   """Desktop Chrome Energy System Health Benchmark."""
@@ -72,8 +74,9 @@
 
 
 @benchmark.Info(emails=['charliea@chromium.org', 'sullivan@chromium.org',
-                        'tdresser@chromium.org', 'perezju@chromium.org'],
-
+                        'tdresser@chromium.org', 'perezju@chromium.org',
+                        'chrome-speed-metrics-dev@chromium.org'],
+                component='Speed>Metrics>SystemHealthRegressions',
                 documentation_url='https://bit.ly/system-health-benchmarks')
 class MobileCommonSystemHealth(_CommonSystemHealthBenchmark):
   """Mobile Chrome Energy System Health Benchmark."""
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index 52c9377..f70f46f 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -172,6 +172,7 @@
   URL = 'http://www.nytimes.com'
   ITEM_SELECTOR = '.story-heading > a'
   SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY
+  COMPLETE_STATE_WAIT_TIMEOUT = 150  # crbug.com/865247
 
 
 # Desktop qq.com opens a news item in a separate tab, for which the back button
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 354acae..9deb5281 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -155,6 +155,7 @@
  <item id="oauth2_mint_token_flow" hash_code="1112842" type="1" second_id="29188932" content_hash_code="91581432" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="google_apis/gaia/oauth2_mint_token_flow.cc"/>
  <item id="ocsp_start_url_request" hash_code="60921996" type="0" content_hash_code="24127780" os_list="linux" file_path="net/cert_net/nss_ocsp.cc"/>
  <item id="offline_prefetch" hash_code="19185953" type="0" content_hash_code="57248156" os_list="linux,windows" file_path="components/offline_pages/core/prefetch/prefetch_request_fetcher.cc"/>
+ <item id="omnibox_documentsuggest" hash_code="6055066" type="0" content_hash_code="126973249" os_list="linux,windows" file_path="components/omnibox/browser/document_suggestions_service.cc"/>
  <item id="omnibox_navigation_observer" hash_code="61684939" type="0" content_hash_code="70941231" os_list="linux,windows" file_path="chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.cc"/>
  <item id="omnibox_prefetch_image" hash_code="109200878" type="0" content_hash_code="107906693" os_list="linux,windows" file_path="chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc"/>
  <item id="omnibox_result_change" hash_code="73107389" type="0" content_hash_code="24802647" os_list="linux,windows" file_path="chrome/browser/ui/omnibox/chrome_omnibox_client.cc"/>
diff --git a/ui/file_manager/PRESUBMIT.py b/ui/file_manager/PRESUBMIT.py
index 5cb5c24..e08888c 100644
--- a/ui/file_manager/PRESUBMIT.py
+++ b/ui/file_manager/PRESUBMIT.py
@@ -2,15 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-def PostUploadHook(cl, change, output_api):
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:closure_compilation',
-    ],
-    'Automatically added optional Closure bots to run on CQ.')
-
-
 def CheckChangeOnUpload(input_api, output_api):
   return _CommonChecks(input_api, output_api)
 
diff --git a/ui/file_manager/compile_js2.gypi b/ui/file_manager/compile_js2.gypi
deleted file mode 100644
index 0ddfd05..0000000
--- a/ui/file_manager/compile_js2.gypi
+++ /dev/null
@@ -1,15 +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.
-{
- 'variables': {
-    'closure_args': [
-      '<@(default_closure_args)',
-      'warning_level=VERBOSE',
-    ],
-  },
-  'dependencies': [
-    '<(EXTERNS_GYP):file_manager_private'
-  ],
-  'includes': ['../../third_party/closure_compiler/compile_js2.gypi'],
-}
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 221f7ee..efda42a 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1887,6 +1887,15 @@
   width: auto;
 }
 
+#install-linux-package-dialog {
+  min-width: 300px;
+  width: 40%;
+}
+
+#install-linux-package-dialog .cr-dialog-text {
+  min-height: 30px;
+}
+
 .drive-welcome-wrapper {
   /* drive_welcome.css will override it once loaded. */
   display: none;
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index cf4f7de52..391a53a 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -186,6 +186,24 @@
         return;
       }
 
+      // Linux package installation is currently only supported for a single
+      // file already inside the Linux container.
+      // TODO(timloh): Instead of filtering these out, we probably should show
+      // a dialog with an error message, similar to when attempting to run
+      // Crostini tasks with non-Crostini entries.
+      if (entries.length !== 1 ||
+          !FileTasks.isCrostiniEntry_(entries[0], volumeManager)) {
+        taskItems = taskItems.filter(function(item) {
+          var taskParts = item.taskId.split('|');
+          var appId = taskParts[0];
+          var taskType = taskParts[1];
+          var actionId = taskParts[2];
+          return !(
+              appId === chrome.runtime.id && taskType === 'file' &&
+              actionId === 'install-linux-package');
+        });
+      }
+
       // Filters out Pack with Zip Archiver task because it will be accessible
       // via 'Zip selection' context menu button
       taskItems = taskItems.filter(function(item) {
@@ -407,9 +425,9 @@
   var appId = taskParts[0];
   var taskType = taskParts[1];
   var actionId = taskParts[2];
-  return (appId === chrome.runtime.id &&
-          taskType === 'file' &&
-          actionId === 'mount-archive');
+  return (
+      appId === chrome.runtime.id && taskType === 'file' &&
+      (actionId === 'mount-archive' || actionId === 'install-linux-package'));
 };
 
 /**
@@ -435,13 +453,23 @@
 };
 
 /**
+ * @param {!Entry} entry
+ * @param {!VolumeManagerWrapper} volumeManager
+ * @return {boolean} True if the entry is from crostini.
+ * @private
+ */
+FileTasks.isCrostiniEntry_ = function(entry, volumeManager) {
+  return volumeManager.getLocationInfo(entry).rootType ===
+      VolumeManagerCommon.RootType.CROSTINI;
+};
+
+/**
  * @return {boolean} True if all entries are crostini.
  * @private
  */
 FileTasks.prototype.allCrostiniEntries_ = function() {
   return this.entries_.every(
-      entry => this.volumeManager_.getLocationInfo(entry).rootType ===
-          VolumeManagerCommon.RootType.CROSTINI);
+      entry => FileTasks.isCrostiniEntry_(entry, this.volumeManager_));
 };
 
 /**
@@ -491,6 +519,9 @@
       } else if (taskParts[2] === 'open-hosted-gslides') {
         task.iconType = 'gslides';
         task.title = loadTimeData.getString('TASK_OPEN_GSLIDES');
+      } else if (taskParts[2] === 'install-linux-package') {
+        task.iconType = 'crostini';
+        task.title = loadTimeData.getString('TASK_INSTALL_LINUX_PACKAGE');
       } else if (taskParts[2] === 'view-swf') {
         // Do not render this task if disabled.
         if (!loadTimeData.getBoolean('SWF_VIEW_ENABLED'))
@@ -833,11 +864,25 @@
     this.mountArchivesInternal_();
     return;
   }
+  if (taskParts[2] === 'install-linux-package') {
+    this.installLinuxPackageInternal_();
+    return;
+  }
 
   console.error('The specified task is not a valid internal task: ' + taskId);
 };
 
 /**
+ * Install a Linux Package in the Linux container.
+ * @private
+ */
+FileTasks.prototype.installLinuxPackageInternal_ = function() {
+  assert(this.entries_.length === 1);
+  this.ui_.installLinuxPackageDialog.showInstallLinuxPackageDialog(
+      this.entries_[0]);
+};
+
+/**
  * The core implementation of mounts archives.
  * @private
  */
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index ab3e1aad..ad867774d 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -56,19 +56,21 @@
 function getMockFileManager() {
   return {
     volumeManager: {
+      getLocationInfo: function(entry) {
+        return VolumeManagerCommon.RootType.DRIVE;
+      },
       getDriveConnectionState: function() {
         return VolumeManagerCommon.DriveConnectionType.ONLINE;
       },
-      getVolumeInfo: function() {
+      getVolumeInfo: function(entry) {
         return {
           volumeType: VolumeManagerCommon.VolumeType.DRIVE
         };
       }
     },
     ui: {
-      alertDialog: {
-        showHtml: function(title, text, onOk, onCancel, onShow) {}
-      }
+      alertDialog:
+          {showHtml: function(title, text, onOk, onCancel, onShow) {}}
     },
     metadataModel: {},
     directoryModel: {
@@ -204,15 +206,12 @@
   var showByExtensionAndMimeIsCalled = new Promise(function(resolve, reject) {
     var fileSystem = new MockFileSystem('volumeId');
     var entry = new MockFileEntry(fileSystem, '/test.rtf');
+    var fileManager = getMockFileManager();
 
     FileTasks
         .create(
-            {
-              getDriveConnectionState: function() {
-                return VolumeManagerCommon.DriveConnectionType.ONLINE;
-              }
-            },
-            {}, {}, {
+            fileManager.volumeManager, fileManager.metadataModel,
+            fileManager.directoryModel, {
               taskMenuButton: document.createElement('button'),
               fileContextMenu:
                   {defaultActionMenuItem: document.createElement('div')},
@@ -244,20 +243,13 @@
   var onFailureIsCalled = new Promise(function(resolve, reject) {
     var fileSystem = new MockFileSystem('volumeId');
     var entry = new MockFileEntry(fileSystem, '/test');
+    var fileManager = getMockFileManager();
 
     FileTasks
         .create(
-            {
-              getDriveConnectionState: function() {
-                return VolumeManagerCommon.DriveConnectionType.ONLINE;
-              }
-            },
-            {}, {}, {
-              taskMenuButton: document.createElement('button'),
-              fileContextMenu:
-                  {defaultActionMenuItem: document.createElement('div')}
-            },
-            [entry], [null], mockTaskHistory)
+            fileManager.volumeManager, fileManager.metadataModel,
+            fileManager.directoryModel, fileManager.ui, [entry], [null],
+            mockTaskHistory)
         .then(function(tasks) {
           tasks.openSuggestAppsDialog(function() {}, function() {}, resolve);
         });
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index 6b99219..087ddd9 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -175,6 +175,7 @@
 // <include src="ui/files_confirm_dialog.js">
 // <include src="ui/files_menu.js">
 // <include src="ui/gear_menu.js">
+// <include src="ui/install_linux_package_dialog.js">
 // <include src="ui/list_container.js">
 // <include src="ui/location_line.js">
 // <include src="ui/multi_profile_share_dialog.js">
diff --git a/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js b/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js
index 1ad02c311..2906f6b 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata_box_controller.js
@@ -139,7 +139,7 @@
     this.setDirectorySize_(
         /** @type {!DirectoryEntry} */ (entry), isSameEntry);
   }
-  if (item.modificationTime) {
+  if (item.modificationTime && !util.isTeamDriveRoot(entry)) {
     this.metadataBox_.modificationTime =
         this.fileMetadataFormatter_.formatModDate(item.modificationTime);
   }
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index 07931b0..7593c84 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -428,6 +428,10 @@
     this.linuxFilesItem_ = item;
     this.reorderNavigationItems_();
   },
+  /** @type {boolean} */
+  get disableMyFilesNavigation() {
+    return this.disableMyFilesNavigation_;
+  }
 };
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
index 939ab9a..14b1d7fc 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
@@ -57,6 +57,9 @@
       new MockFileEntry(fileSystem, '/test.png', {});
   var controller = new TaskController(
       DialogType.FULL_PAGE, {
+        getLocationInfo: function(entry) {
+          return VolumeManagerCommon.RootType.DRIVE;
+        },
         getDriveConnectionState: function() {
           return VolumeManagerCommon.DriveConnectionType.ONLINE;
         },
@@ -76,7 +79,8 @@
         getCurrentRootType: function() {
           return null;
         }
-      }, new cr.EventTarget(), null);
+      },
+      new cr.EventTarget(), null);
 
   controller.executeEntryTask(fileSystem.entries['/test.png']);
   reportPromise(new Promise(function(fulfill) {
@@ -129,7 +133,12 @@
 
 function createTaskController(selectionHandler) {
   return new TaskController(
-      DialogType.FULL_PAGE, {}, {
+      DialogType.FULL_PAGE, {
+        getLocationInfo: function(entry) {
+          return VolumeManagerCommon.RootType.DRIVE;
+        }
+      },
+      {
         taskMenuButton: document.createElement('button'),
         shareMenuButton: {menu: document.createElement('div')},
         fileContextMenu:
@@ -139,7 +148,8 @@
         getCurrentRootType: function() {
           return null;
         }
-      }, selectionHandler, null);
+      },
+      selectionHandler, null);
 }
 
 // TaskController.getFileTasks should not call fileManagerPrivate.getFileTasks
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index 058fa4b..2be8a02 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -29,6 +29,7 @@
     ":files_confirm_dialog",
     ":files_menu",
     ":gear_menu",
+    ":install_linux_package_dialog",
     ":list_container",
     ":location_line",
     ":multi_profile_share_dialog",
@@ -207,6 +208,7 @@
     ":files_alert_dialog",
     ":files_confirm_dialog",
     ":gear_menu",
+    ":install_linux_package_dialog",
     ":list_container",
     ":location_line",
     ":multi_profile_share_dialog",
@@ -285,6 +287,12 @@
   ]
 }
 
+js_library("install_linux_package_dialog") {
+  deps = [
+    ":file_manager_dialog_base",
+  ]
+}
+
 js_library("gear_menu") {
   deps = [
     "../../../common/js:util",
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 8f53a11..1c1752bb 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -1049,6 +1049,10 @@
     this.add(item);
     item.updateSubDirectories(false);
   }
+  // When My files is disabled Drive should be expanded by default.
+  // TODO(crbug.com/850348): Remove this once flag is removed.
+  if (this.parentTree_.dataModel.disableMyFilesNavigation)
+    this.expanded = true;
 };
 
 /**
@@ -1628,8 +1632,8 @@
       if (recursive && currentItem instanceof VolumeItem)
         currentItem.updateSubDirectories(true);
       // EntryListItem can contain volumes that might have been updated: ask
-      // them to re-draw. It only needs to update the first level of children,
-      // so it doesn't need to be recursive.
+      // them to re-draw. Updates recursively so any created or removed children
+      // folder can be reflected on directory tree.
       if (currentItem instanceof EntryListItem)
         currentItem.updateSubDirectories(true);
     } else {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index abd6cd53..1b203fc 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -119,6 +119,14 @@
       providersModel, this.element, launchParam.suggestAppsDialogState);
 
   /**
+   * Dialog for installing .deb files
+   * @type {!cr.filebrowser.InstallLinuxPackageDialog}
+   * @const
+   */
+  this.installLinuxPackageDialog =
+      new cr.filebrowser.InstallLinuxPackageDialog(this.element);
+
+  /**
    * The container element of the dialog.
    * @type {!HTMLElement}
    */
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index bd026d9e..5be3aaa 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -899,6 +899,13 @@
  * @private
  */
 FileTable.prototype.updateDate_ = function(div, entry) {
+  // For now, Team Drive roots have the incorrect modified date value. Hide it
+  // until we get the proper one (see https://crbug.com/861622).
+  if (util.isTeamDriveRoot(entry)) {
+    div.textContent = '--';
+    return;
+  }
+
   var item = this.metadataModel_.getCache(
       [entry], ['modificationTime', 'modificationByMeTime'])[0];
   var modTime = this.useModificationByMeTime_ ?
diff --git a/ui/file_manager/file_manager/foreground/js/ui/install_linux_package_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/install_linux_package_dialog.js
new file mode 100644
index 0000000..138e87aa
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/ui/install_linux_package_dialog.js
@@ -0,0 +1,103 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * InstallLinuxPackageDialog is used as the handler for .deb files.
+ * TODO(timloh): Retrieve package info and display it in the dialog.
+ */
+cr.define('cr.filebrowser', function() {
+  /**
+   * Creates dialog in DOM tree.
+   *
+   * @param {HTMLElement} parentNode Node to be parent for this dialog.
+   * @constructor
+   * @extends {FileManagerDialogBase}
+   */
+  function InstallLinuxPackageDialog(parentNode) {
+    FileManagerDialogBase.call(this, parentNode);
+
+    this.frame_.id = 'install-linux-package-dialog';
+
+    // TODO(timloh): Add a penguin icon
+
+    // The OK button normally dismisses the dialog, so add a button we can
+    // customize.
+    this.installButton_ = this.okButton_.cloneNode();
+    this.installButton_.textContent =
+        str('INSTALL_LINUX_PACKAGE_INSTALL_BUTTON');
+    this.installButton_.addEventListener(
+        'click', this.onInstallClick_.bind(this));
+    this.buttons.insertBefore(this.installButton_, this.okButton_);
+    this.initialFocusElement_ = this.installButton_;
+  }
+
+  InstallLinuxPackageDialog.prototype = {
+    __proto__: FileManagerDialogBase.prototype,
+  };
+
+  /**
+   * Shows the dialog.
+   *
+   * @param {!Entry} entry
+   */
+  InstallLinuxPackageDialog.prototype.showInstallLinuxPackageDialog = function(
+      entry) {
+    // We re-use the same object, so reset any visual state that may be changed.
+    this.installButton_.hidden = false;
+    this.okButton_.hidden = true;
+    this.cancelButton_.hidden = false;
+
+    this.entry_ = entry;
+
+    var title = str('INSTALL_LINUX_PACKAGE_TITLE');
+    var message = str('INSTALL_LINUX_PACKAGE_DESCRIPTION');
+    var show = FileManagerDialogBase.prototype.showOkCancelDialog.call(
+        this, title, message, null, null);
+
+    if (!show) {
+      console.error('InstallLinuxPackageDialog can\'t be shown.');
+      return;
+    }
+  };
+
+  /**
+   * Starts installing the Linux package.
+   */
+  InstallLinuxPackageDialog.prototype.onInstallClick_ = function() {
+    // Add the event listener first to avoid potential races.
+    chrome.fileManagerPrivate.installLinuxPackage(
+        this.entry_, this.onInstallLinuxPackage_.bind(this));
+
+    this.installButton_.hidden = true;
+    this.cancelButton_.hidden = true;
+
+    this.okButton_.hidden = false;
+    this.okButton_.focus();
+  };
+
+  /**
+   * The callback for installLinuxPackage(). Progress updates and completion
+   * for succesfully started installations will be displayed in a notification,
+   * rather than the file manager.
+   * @param {!chrome.fileManagerPrivate.InstallLinuxPackageResponse} response
+   *     Whether the install successfully started or not.
+   * @param {string} failure_reason A textual reason for the 'failed' case.
+   */
+  InstallLinuxPackageDialog.prototype.onInstallLinuxPackage_ = function(
+      response, failure_reason) {
+    if (response == 'started') {
+      this.text_.textContent =
+          str('INSTALL_LINUX_PACKAGE_INSTALLATION_STARTED');
+      return;
+    }
+
+    // Currently we always display a generic error message. Eventually we'll
+    // want a different message for the 'install_already_active' case, and to
+    // surface the provided failure reason if one is provided.
+    this.title_.textContent = str('INSTALL_LINUX_PACKAGE_ERROR_TITLE');
+    this.text_.textContent = str('INSTALL_LINUX_PACKAGE_ERROR_DESCRIPTION');
+  };
+
+  return {InstallLinuxPackageDialog: InstallLinuxPackageDialog};
+});
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index f49c373..68bd831 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -138,6 +138,14 @@
         "filesystem:*.gslides"
       ]
     },
+    {
+      "id": "install-linux-package",
+      "default_title": "__MSG_INSTALL_LINUX_PACKAGE__",
+      "default_icon": "common/images/file_types/200/generic.png",
+      "file_filters": [
+        "filesystem:*.deb"
+      ]
+    },
     // The following handlers are used only internally, therefore they do not
     // have any file filter.
     // Selects the passed file after launching the Files app.
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index faef2c2..2213931 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -415,7 +415,7 @@
       ChangeState(KeyboardControllerState::HIDDEN);
 
       for (KeyboardControllerObserver& observer : observer_list_)
-        observer.OnKeyboardHidden();
+        observer.OnKeyboardHidden(reason == HIDE_REASON_SYSTEM_TEMPORARY);
       ui_->EnsureCaretInWorkArea(gfx::Rect());
 
       break;
diff --git a/ui/keyboard/keyboard_controller_observer.h b/ui/keyboard/keyboard_controller_observer.h
index 5339b1cb..e9b839a9 100644
--- a/ui/keyboard/keyboard_controller_observer.h
+++ b/ui/keyboard/keyboard_controller_observer.h
@@ -59,7 +59,9 @@
 
   // Called when the keyboard has been hidden and the hiding animation finished
   // successfully. This is same as |state| == HIDDEN on OnStateChanged.
-  virtual void OnKeyboardHidden() {}
+  // When |is_temporary_hide| is true, this hide is immediately followed by a
+  // show (e.g. when changing to floating keyboard)
+  virtual void OnKeyboardHidden(bool is_temporary_hide) {}
 
   // Called when the state changed.
   virtual void OnStateChanged(KeyboardControllerState state) {}
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index b479be6..eba8ef2 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -72,12 +72,8 @@
       ozone_platform = "windows"
       ozone_platform_windows = true
     } else if (is_fuchsia) {
-      # TODO(crbug.com/829980): Uncomment this line to set scenic as default
-      # on fuchsia. Currently this breaks content_unittests on test bots.
-      #
-      # ozone_platform = "scenic"
+      ozone_platform = "scenic"
       ozone_platform_scenic = true
-
       ozone_platform_magma = true
     }
   }
diff --git a/ui/views/bubble/tooltip_icon.cc b/ui/views/bubble/tooltip_icon.cc
index 05e3354..2b88baf 100644
--- a/ui/views/bubble/tooltip_icon.cc
+++ b/ui/views/bubble/tooltip_icon.cc
@@ -14,8 +14,9 @@
 
 namespace views {
 
-TooltipIcon::TooltipIcon(const base::string16& tooltip)
+TooltipIcon::TooltipIcon(const base::string16& tooltip, int tooltip_icon_size)
     : tooltip_(tooltip),
+      tooltip_icon_size_(tooltip_icon_size),
       mouse_inside_(false),
       bubble_(nullptr),
       preferred_width_(0),
@@ -69,9 +70,8 @@
 }
 
 void TooltipIcon::SetDrawAsHovered(bool hovered) {
-  constexpr int kTooltipIconSize = 16;
   SetImage(
-      gfx::CreateVectorIcon(vector_icons::kInfoOutlineIcon, kTooltipIconSize,
+      gfx::CreateVectorIcon(vector_icons::kInfoOutlineIcon, tooltip_icon_size_,
                             hovered ? SkColorSetARGB(0xBD, 0, 0, 0)
                                     : SkColorSetARGB(0xBD, 0x44, 0x44, 0x44)));
 }
@@ -84,7 +84,7 @@
 
   bubble_ = new InfoBubble(this, tooltip_);
   bubble_->set_preferred_width(preferred_width_);
-  bubble_->set_arrow(BubbleBorder::TOP_RIGHT);
+  bubble_->set_arrow(anchor_point_arrow_);
   // When shown due to a gesture event, close on deactivate (i.e. don't use
   // "focusless").
   bubble_->set_can_activate(!mouse_inside_);
diff --git a/ui/views/bubble/tooltip_icon.h b/ui/views/bubble/tooltip_icon.h
index 327bdd5..97dbe04 100644
--- a/ui/views/bubble/tooltip_icon.h
+++ b/ui/views/bubble/tooltip_icon.h
@@ -11,6 +11,7 @@
 #include "base/scoped_observer.h"
 #include "base/strings/string16.h"
 #include "base/timer/timer.h"
+#include "ui/views/bubble/bubble_border.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/mouse_watcher.h"
 #include "ui/views/widget/widget_observer.h"
@@ -24,7 +25,8 @@
                                  public MouseWatcherListener,
                                  public WidgetObserver {
  public:
-  explicit TooltipIcon(const base::string16& tooltip);
+  explicit TooltipIcon(const base::string16& tooltip,
+                       int tooltip_icon_size = 16);
   ~TooltipIcon() override;
 
   // ImageView:
@@ -45,6 +47,10 @@
     preferred_width_ = preferred_width;
   }
 
+  void set_anchor_point_arrow(BubbleBorder::Arrow arrow) {
+    anchor_point_arrow_ = arrow;
+  }
+
  private:
   // Changes the color to reflect the hover node_data.
   void SetDrawAsHovered(bool hovered);
@@ -59,6 +65,14 @@
   // The text to show in a bubble when hovered.
   base::string16 tooltip_;
 
+  // The size of the tooltip icon, in dip.
+  // Must be set in the constructor, otherwise the pre-hovered icon will show
+  // the default size.
+  int tooltip_icon_size_;
+
+  // The point at which to anchor the tooltip.
+  BubbleBorder::Arrow anchor_point_arrow_ = BubbleBorder::TOP_RIGHT;
+
   // Whether the mouse is inside this tooltip.
   bool mouse_inside_;
 
diff --git a/ui/views/controls/webview/webview.cc b/ui/views/controls/webview/webview.cc
index 4971127..74ddbc9 100644
--- a/ui/views/controls/webview/webview.cc
+++ b/ui/views/controls/webview/webview.cc
@@ -91,6 +91,8 @@
   }
   AttachWebContents();
   NotifyAccessibilityWebContentsChanged();
+
+  MaybeEnableAutoResize();
 }
 
 void WebView::SetEmbedFullscreenWidgetMode(bool enable) {
@@ -109,6 +111,14 @@
   holder_->set_fast_resize(fast_resize);
 }
 
+void WebView::EnableSizingFromWebContents(const gfx::Size& min_size,
+                                          const gfx::Size& max_size) {
+  DCHECK(!max_size.IsEmpty());
+  min_size_ = min_size;
+  max_size_ = max_size;
+  MaybeEnableAutoResize();
+}
+
 void WebView::SetResizeBackgroundColor(SkColor resize_background_color) {
   holder_->set_resize_background_color(resize_background_color);
 }
@@ -271,6 +281,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // WebView, content::WebContentsObserver implementation:
 
+void WebView::RenderViewCreated(content::RenderViewHost* render_view_host) {
+  MaybeEnableAutoResize();
+}
+
 void WebView::RenderViewReady() {
   UpdateCrashedOverlayView();
   NotifyAccessibilityWebContentsChanged();
@@ -283,6 +297,8 @@
 
 void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
                                     content::RenderViewHost* new_host) {
+  MaybeEnableAutoResize();
+
   if (HasFocus())
     OnFocus();
   NotifyAccessibilityWebContentsChanged();
@@ -326,6 +342,14 @@
   NotifyAccessibilityWebContentsChanged();
 }
 
+void WebView::ResizeDueToAutoResize(content::WebContents* source,
+                                    const gfx::Size& new_size) {
+  if (source != web_contents())
+    return;
+
+  SetPreferredSize(new_size);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WebView, private:
 
@@ -411,4 +435,15 @@
   return contents;
 }
 
+void WebView::MaybeEnableAutoResize() {
+  if (max_size_.IsEmpty() || !web_contents() ||
+      !web_contents()->GetRenderWidgetHostView()) {
+    return;
+  }
+
+  content::RenderWidgetHostView* render_widget_host_view =
+      web_contents()->GetRenderWidgetHostView();
+  render_widget_host_view->EnableAutoResize(min_size_, max_size_);
+}
+
 }  // namespace views
diff --git a/ui/views/controls/webview/webview.h b/ui/views/controls/webview/webview.h
index 87d9a1e7..994520b 100644
--- a/ui/views/controls/webview/webview.h
+++ b/ui/views/controls/webview/webview.h
@@ -76,6 +76,11 @@
   //         resizing performance during interactive resizes and animations.
   void SetFastResize(bool fast_resize);
 
+  // If enabled, this will make the WebView's preferred size dependent on the
+  // WebContents' size.
+  void EnableSizingFromWebContents(const gfx::Size& min_size,
+                                   const gfx::Size& max_size);
+
   // Set the background color to use while resizing with a clip. This is white
   // by default.
   void SetResizeBackgroundColor(SkColor resize_background_color);
@@ -94,6 +99,10 @@
   // Overridden from View:
   const char* GetClassName() const override;
 
+  // Overridden from content::WebContentsDelegate:
+  void ResizeDueToAutoResize(content::WebContents* source,
+                             const gfx::Size& new_size) override;
+
   NativeViewHost* holder() { return holder_; }
   using WebContentsCreator =
       base::RepeatingCallback<std::unique_ptr<content::WebContents>(
@@ -123,6 +132,9 @@
   virtual void OnLetterboxingChanged() {}
   bool is_letterboxing() const { return is_letterboxing_; }
 
+  const gfx::Size& min_size() const { return min_size_; }
+  const gfx::Size& max_size() const { return max_size_; }
+
   // Overridden from View:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   void ViewHierarchyChanged(
@@ -138,6 +150,7 @@
   bool EmbedsFullscreenWidget() const override;
 
   // Overridden from content::WebContentsObserver:
+  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
   void RenderViewReady() override;
   void RenderViewDeleted(content::RenderViewHost* render_view_host) override;
   void RenderViewHostChanged(content::RenderViewHost* old_host,
@@ -167,6 +180,11 @@
   void UpdateCrashedOverlayView();
   void NotifyAccessibilityWebContentsChanged();
 
+  // Registers for ResizeDueToAutoResize() notifications from the
+  // RenderWidgetHostView whenever it is created or changes, if
+  // EnableSizingFromWebContents() has been called.
+  void MaybeEnableAutoResize();
+
   // Create a regular or test web contents (based on whether we're running
   // in a unit test or not).
   std::unique_ptr<content::WebContents> CreateWebContents(
@@ -188,6 +206,11 @@
   bool allow_accelerators_;
   View* crashed_overlay_view_ = nullptr;
 
+  // Minimum and maximum sizes to determine WebView bounds for auto-resizing.
+  // Empty if auto resize is not enabled.
+  gfx::Size min_size_;
+  gfx::Size max_size_;
+
   DISALLOW_COPY_AND_ASSIGN(WebView);
 };
 
diff --git a/ui/webui/resources/PRESUBMIT.py b/ui/webui/resources/PRESUBMIT.py
index 4db5f28e..d1933521 100644
--- a/ui/webui/resources/PRESUBMIT.py
+++ b/ui/webui/resources/PRESUBMIT.py
@@ -4,15 +4,6 @@
 
 import os
 
-def PostUploadHook(cl, change, output_api):
-  return output_api.EnsureCQIncludeTrybotsAreAdded(
-    cl,
-    [
-      'luci.chromium.try:closure_compilation',
-    ],
-    'Automatically added optional Closure bots to run on CQ.')
-
-
 def CheckChangeOnUpload(input_api, output_api):
   return _CommonChecks(input_api, output_api)
 
@@ -20,30 +11,6 @@
 def CheckChangeOnCommit(input_api, output_api):
   return _CommonChecks(input_api, output_api)
 
-# For every modified gyp file, warn if the corresponding GN file is not updated.
-def _CheckForGNUpdate(input_api, output_api):
-  gyp_folders = set()
-  for f in input_api.AffectedFiles():
-    local_path = f.LocalPath()
-    if local_path.endswith('compiled_resources2.gyp'):
-      gyp_folders.add(os.path.dirname(local_path))
-
-  for f in input_api.AffectedFiles():
-    local_path = f.LocalPath()
-    dir_name = os.path.dirname(local_path)
-    if local_path.endswith('BUILD.gn') and dir_name in gyp_folders:
-      gyp_folders.remove(dir_name)
-
-  if not gyp_folders:
-    return []
-
-  return [output_api.PresubmitPromptWarning("""
-You may have forgotten to update the BUILD.gn Closure Compilation for the
-following folders:
-""" + "\n".join(["- " + x for x in gyp_folders]) + """
-
-Ping calamity@ or check go/closure-compile-gn for more details.
-""")]
 
 def _CheckForTranslations(input_api, output_api):
   shared_keywords = ['i18n(']
@@ -86,7 +53,6 @@
 def _CommonChecks(input_api, output_api):
   results = []
   results += _CheckForTranslations(input_api, output_api)
-  results += _CheckForGNUpdate(input_api, output_api)
   results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api,
                                                          check_js=True)
   try: