diff --git a/DEPS b/DEPS
index 3024089..df90ad5 100644
--- a/DEPS
+++ b/DEPS
@@ -96,11 +96,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'ab7181daad5dae205b8dbd9de318aa3438a1cabf',
+  'skia_revision': '6bbd386a0e4bf13cd7abb887900018a56e24091b',
   # 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': 'd527ddce3d5f3c0266e56c2b7568c1b837dff0d8',
+  'v8_revision': '558cf7d7ae9f4dda0bb1cad06be5275b891c9bb7',
   # 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.
@@ -108,7 +108,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '5730c0bf431e2decbddfdb7a3a2ec8338e56be2d',
+  'angle_revision': 'a00ef3144f7039b54ea7dbfe255b85b6f4d11224',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -120,7 +120,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': '08d96f1cadb14d91b051e7568de0c43804ba7340',
+  'pdfium_revision': '473b4ae489e8c6d63b087693589eda03399f60f6',
   # 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.
@@ -156,7 +156,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'dd13313c34d34127722d3bab7c2b4f372329c544',
+  'catapult_revision': '075ca3000abfdd522bd4faf668cae4b7c820dd64',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -498,7 +498,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7e9e7b065a98c94ba1435726e1904869724979d5',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'c8e4e795ed7527807910153dea581ee6ad9a2698',
       'condition': 'checkout_linux',
   },
 
@@ -1002,7 +1002,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@eb85cead4784fe9d080343a1332a8e7361235366',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3136ebfa0a629e2906f6f2455f40490e95436baf',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc
index f87010a..3128db3c 100644
--- a/ash/system/ime_menu/ime_menu_tray_unittest.cc
+++ b/ash/system/ime_menu/ime_menu_tray_unittest.cc
@@ -106,7 +106,8 @@
   void FocusInInputContext(ui::TextInputType input_type) {
     ui::IMEEngineHandlerInterface::InputContext input_context(
         input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
-        ui::TextInputClient::FOCUS_REASON_OTHER);
+        ui::TextInputClient::FOCUS_REASON_OTHER,
+        false /* should_do_learning */);
     ui::IMEBridge::Get()->SetCurrentInputContext(input_context);
   }
 
diff --git a/cc/trees/render_frame_metadata.cc b/cc/trees/render_frame_metadata.cc
index 2559925..b8a0500b 100644
--- a/cc/trees/render_frame_metadata.cc
+++ b/cc/trees/render_frame_metadata.cc
@@ -34,7 +34,7 @@
 RenderFrameMetadata& RenderFrameMetadata::operator=(
     RenderFrameMetadata&& other) = default;
 
-bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) {
+bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const {
   return root_scroll_offset == other.root_scroll_offset &&
          root_background_color == other.root_background_color &&
          is_scroll_offset_at_top == other.is_scroll_offset_at_top &&
@@ -45,7 +45,7 @@
          local_surface_id == other.local_surface_id;
 }
 
-bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) {
+bool RenderFrameMetadata::operator!=(const RenderFrameMetadata& other) const {
   return !operator==(other);
 }
 
diff --git a/cc/trees/render_frame_metadata.h b/cc/trees/render_frame_metadata.h
index c76d498..94f768c 100644
--- a/cc/trees/render_frame_metadata.h
+++ b/cc/trees/render_frame_metadata.h
@@ -31,8 +31,8 @@
 
   RenderFrameMetadata& operator=(const RenderFrameMetadata&);
   RenderFrameMetadata& operator=(RenderFrameMetadata&& other);
-  bool operator==(const RenderFrameMetadata& other);
-  bool operator!=(const RenderFrameMetadata& other);
+  bool operator==(const RenderFrameMetadata& other) const;
+  bool operator!=(const RenderFrameMetadata& other) const;
 
   // Indicates whether the scroll offset of the root layer is at top, i.e.,
   // whether scroll_offset.y() == 0.
diff --git a/chrome/VERSION b/chrome/VERSION
index fa590464..a2ee50e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=68
 MINOR=0
-BUILD=3431
+BUILD=3432
 PATCH=0
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index fb24a54..aac3d0f 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-68.0.3430.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-68.0.3431.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
index 6481b92..3dc8080b 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -245,23 +245,8 @@
 
       // This bridge must receive OnNotificationStateChanged call for the
       // notification_key before this receives an accessibility event for it.
-      // TODO(yawano): change this to DCHECK once we remove backward
-      //               compatibility logic.
-      if (notification_keys_.find(notification_key) !=
-          notification_keys_.end()) {
-        tree_source = GetFromNotificationKey(notification_key);
-        DCHECK(tree_source);
-      } else {
-        // Backward compatibility logic.
-        // TODO(yawano): remove this once this becomes unnecessary.
-        if (event_data->event_type ==
-            arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED) {
-          tree_source = CreateFromNotificationKey(notification_key);
-          backward_compat_notification_keys_[notification_key]++;
-        } else {
-          tree_source = GetFromNotificationKey(notification_key);
-        }
-      }
+      tree_source = GetFromNotificationKey(notification_key);
+      DCHECK(tree_source);
     } else {
       if (event_data->task_id == kNoTaskId)
         return;
@@ -283,40 +268,21 @@
 
     tree_source->NotifyAccessibilityEvent(event_data.get());
 
-    if (is_notification_event) {
-      switch (event_data->event_type) {
-        case arc::mojom::AccessibilityEventType::VIEW_TEXT_SELECTION_CHANGED: {
-          // If text selection changed event is dispatched from Android, it
-          // means that user is trying to type a text in Android notification.
-          // Dispatch text selection changed event to notification content view
-          // as the view can take necessary actions, e.g. activate itself, etc.
-          auto* surface_manager = ArcNotificationSurfaceManager::Get();
-          if (!surface_manager)
-            break;
-
-          ArcNotificationSurface* surface = surface_manager->GetArcSurface(
-              event_data->notification_key.value());
-          if (!surface)
-            break;
-
+    if (is_notification_event &&
+        event_data->event_type ==
+            arc::mojom::AccessibilityEventType::VIEW_TEXT_SELECTION_CHANGED) {
+      // If text selection changed event is dispatched from Android, it
+      // means that user is trying to type a text in Android notification.
+      // Dispatch text selection changed event to notification content view
+      // as the view can take necessary actions, e.g. activate itself, etc.
+      auto* surface_manager = ArcNotificationSurfaceManager::Get();
+      if (surface_manager) {
+        ArcNotificationSurface* surface = surface_manager->GetArcSurface(
+            event_data->notification_key.value());
+        if (surface) {
           surface->GetAttachedHost()->NotifyAccessibilityEvent(
               ax::mojom::Event::kTextSelectionChanged, true);
-          break;
         }
-        case arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED: {
-          // TODO(yawano): Move this to OnNotificationStateChanged. This can be
-          // moved there if we don't need to care about backward compat.
-          ui::AXTreeData tree_data;
-          if (!tree_source->GetTreeData(&tree_data))
-            break;
-
-          DCHECK(event_data->notification_key.has_value());
-          UpdateTreeIdOfNotificationSurface(
-              event_data->notification_key.value(), tree_data.tree_id);
-          break;
-        }
-        default:
-          break;
       }
     }
 
@@ -335,12 +301,19 @@
     const std::string& notification_key,
     arc::mojom::AccessibilityNotificationStateType state) {
   switch (state) {
-    case arc::mojom::AccessibilityNotificationStateType::SURFACE_CREATED:
-      CreateFromNotificationKey(notification_key);
-      notification_keys_.insert(notification_key);
+    case arc::mojom::AccessibilityNotificationStateType::SURFACE_CREATED: {
+      AXTreeSourceArc* tree_source =
+          CreateFromNotificationKey(notification_key);
+
+      ui::AXTreeData tree_data;
+      if (!tree_source->GetTreeData(&tree_data)) {
+        NOTREACHED();
+        return;
+      }
+      UpdateTreeIdOfNotificationSurface(notification_key, tree_data.tree_id);
       break;
+    }
     case arc::mojom::AccessibilityNotificationStateType::SURFACE_REMOVED:
-      notification_keys_.erase(notification_key);
       notification_key_to_tree_.erase(notification_key);
       UpdateTreeIdOfNotificationSurface(notification_key, kInvalidTreeId);
       break;
@@ -599,22 +572,4 @@
   }
 }
 
-void ArcAccessibilityHelperBridge::OnNotificationSurfaceRemoved(
-    ArcNotificationSurface* surface) {
-  const std::string& notification_key = surface->GetNotificationKey();
-
-  auto it = backward_compat_notification_keys_.find(notification_key);
-  if (it == backward_compat_notification_keys_.end())
-    return;
-
-  it->second--;
-
-  DCHECK(it->second >= 0);
-
-  if (it->second == 0) {
-    notification_key_to_tree_.erase(notification_key);
-    backward_compat_notification_keys_.erase(notification_key);
-  }
-}
-
 }  // namespace arc
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
index 3de2223..27d4e70 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
@@ -83,7 +83,7 @@
 
   // ArcNotificationSurfaceManager::Observer overrides.
   void OnNotificationSurfaceAdded(ArcNotificationSurface* surface) override;
-  void OnNotificationSurfaceRemoved(ArcNotificationSurface* surface) override;
+  void OnNotificationSurfaceRemoved(ArcNotificationSurface* surface) override{};
 
   const std::map<int32_t, std::unique_ptr<AXTreeSourceArc>>&
   task_id_to_tree_for_test() const {
@@ -128,16 +128,6 @@
   std::unique_ptr<chromeos::AccessibilityStatusSubscription>
       accessibility_status_subscription_;
 
-  // Map for managing notifications in backward compatible way, creating
-  // notification with WINDOW_STATE_CHANGED event.
-  // Key: notification key
-  // Value: retain counter
-  // TODO(yawano): Remove this after this becomes unnecessary.
-  std::map<std::string, int32_t> backward_compat_notification_keys_;
-
-  // TODO(yawano): Remove this after this becomes unnecessary.
-  std::set<std::string> notification_keys_;
-
   DISALLOW_COPY_AND_ASSIGN(ArcAccessibilityHelperBridge);
 };
 
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
index 0c75b4a..e40d179 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -404,107 +404,6 @@
   arc_notification_surface_manager_->RemoveSurface(&test_surface_2);
 }
 
-// This is the case for testing backward compatibility with creating
-// notification by WINDOW_STATE_CHANGED event.
-//
-// mojo: notification 1 created
-// wayland: surface 1 created
-// mojo: notification 2 created
-// wayland: surface 1 removed
-// wayland: surface 2 created
-// wayland: surface 2 removed
-//
-// wayland: surface 3 created
-// mojo: notification 3 created
-// wayland: surface 3 removed
-TEST_F(ArcAccessibilityHelperBridgeTest, NotificationBackwardCompat) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      chromeos::switches::kEnableChromeVoxArcSupport);
-
-  TestArcAccessibilityHelperBridge* helper_bridge =
-      accessibility_helper_bridge();
-  arc_notification_surface_manager_->AddObserver(helper_bridge);
-
-  const auto& notification_key_to_tree_ =
-      helper_bridge->notification_key_to_tree_for_test();
-  ASSERT_EQ(0U, notification_key_to_tree_.size());
-
-  // mojo: notification 1 created
-  auto event1 = arc::mojom::AccessibilityEventData::New();
-  event1->event_type = arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED;
-  event1->notification_key = base::make_optional<std::string>(kNotificationKey);
-  event1->node_data.push_back(arc::mojom::AccessibilityNodeInfoData::New());
-  helper_bridge->OnAccessibilityEvent(event1.Clone());
-
-  EXPECT_EQ(1U, notification_key_to_tree_.size());
-
-  // wayland: surface 1 added
-  FakeArcNotificationSurface test_surface1(kNotificationKey);
-  arc_notification_surface_manager_->AddSurface(&test_surface1);
-
-  auto it = notification_key_to_tree_.find(kNotificationKey);
-  EXPECT_NE(notification_key_to_tree_.end(), it);
-  AXTreeSourceArc* tree = it->second.get();
-  ui::AXTreeData tree_data;
-  tree->GetTreeData(&tree_data);
-  EXPECT_EQ(tree_data.tree_id, test_surface1.GetAXTreeId());
-
-  // mojo: notification 2 created
-  auto event2 = arc::mojom::AccessibilityEventData::New();
-  event2->event_type = arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED;
-  event2->notification_key = base::make_optional<std::string>(kNotificationKey);
-  event2->node_data.push_back(arc::mojom::AccessibilityNodeInfoData::New());
-  helper_bridge->OnAccessibilityEvent(event2.Clone());
-
-  auto it2 = notification_key_to_tree_.find(kNotificationKey);
-  EXPECT_NE(notification_key_to_tree_.end(), it);
-  AXTreeSourceArc* tree2 = it2->second.get();
-  ui::AXTreeData tree_data2;
-  tree2->GetTreeData(&tree_data2);
-  EXPECT_EQ(tree_data2.tree_id, test_surface1.GetAXTreeId());
-
-  // wayland: surface 1 removed
-  arc_notification_surface_manager_->RemoveSurface(&test_surface1);
-
-  EXPECT_EQ(1U, notification_key_to_tree_.size());
-
-  // wayland: surface 2 added
-  FakeArcNotificationSurface test_surface2(kNotificationKey);
-  arc_notification_surface_manager_->AddSurface(&test_surface2);
-
-  EXPECT_EQ(tree_data2.tree_id, test_surface2.GetAXTreeId());
-
-  // wayland: surface 2 removed
-  arc_notification_surface_manager_->RemoveSurface(&test_surface2);
-
-  EXPECT_EQ(0U, notification_key_to_tree_.size());
-
-  // wayland: surface 3 added
-  FakeArcNotificationSurface test_surface3(kNotificationKey);
-  arc_notification_surface_manager_->AddSurface(&test_surface3);
-
-  // mojo: notification 3 created
-  auto event3 = arc::mojom::AccessibilityEventData::New();
-  event3->event_type = arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED;
-  event3->notification_key = base::make_optional<std::string>(kNotificationKey);
-  event3->node_data.push_back(arc::mojom::AccessibilityNodeInfoData::New());
-  helper_bridge->OnAccessibilityEvent(event3.Clone());
-
-  EXPECT_EQ(1U, notification_key_to_tree_.size());
-
-  auto it3 = notification_key_to_tree_.find(kNotificationKey);
-  EXPECT_NE(notification_key_to_tree_.end(), it3);
-  AXTreeSourceArc* tree3 = it3->second.get();
-  ui::AXTreeData tree_data3;
-  tree3->GetTreeData(&tree_data3);
-  EXPECT_EQ(tree_data3.tree_id, test_surface3.GetAXTreeId());
-
-  // wayland: surface 3 removed
-  arc_notification_surface_manager_->RemoveSurface(&test_surface3);
-
-  EXPECT_EQ(0U, notification_key_to_tree_.size());
-}
-
 // This is the case where surface creation/removal arrive before mojo events.
 //
 // wayland: surface 1 added
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index ef646d96..6d82c04 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -73,9 +73,7 @@
 }
 
 bool IsCrostiniUIAllowedForProfile(Profile* profile) {
-  if (!profile || profile->IsOffTheRecord() ||
-      chromeos::ProfileHelper::IsEphemeralUserProfile(profile) ||
-      chromeos::ProfileHelper::IsLockScreenAppProfile(profile)) {
+  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
     return false;
   }
 
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc b/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
index 2a00be6..e30e41e 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
@@ -67,6 +67,14 @@
 
   void TearDownInProcessBrowserTestFixture() override { extension_ = NULL; }
 
+  ui::IMEEngineHandlerInterface::InputContext CreateInputContextWithInputType(
+      ui::TextInputType type) {
+    return ui::IMEEngineHandlerInterface::InputContext(
+        type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
+        ui::TextInputClient::FOCUS_REASON_OTHER,
+        false /* should_do_learning */);
+  }
+
  protected:
   void LoadTestInputMethod() {
     // This will load "chrome/test/data/extensions/input_ime"
@@ -179,11 +187,10 @@
   ASSERT_TRUE(activated_listener.was_satisfied());
 
   // onFocus event should be fired if FocusIn function is called.
-  ExtensionTestMessageListener focus_listener("onFocus:text:true:true:true",
-                                              false);
-  ui::IMEEngineHandlerInterface::InputContext context(
-      ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
-      ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+  ExtensionTestMessageListener focus_listener(
+      "onFocus:text:true:true:true:false", false);
+  const auto context =
+      CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TEXT);
   engine_handler->FocusIn(context);
   ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
   ASSERT_TRUE(focus_listener.was_satisfied());
@@ -262,9 +269,8 @@
   ASSERT_TRUE(host);
 
   engine_handler->Enable("APIArgumentIME");
-  ui::IMEEngineHandlerInterface::InputContext context(
-      ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
-      ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+  const auto context =
+      CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TEXT);
   engine_handler->FocusIn(context);
 
   {
@@ -937,61 +943,55 @@
     mock_candidate_window->Reset();
 
     {
-      ExtensionTestMessageListener focus_listener("onFocus:text:true:true:true",
-                                                  false);
-      ui::IMEEngineHandlerInterface::InputContext context(
-          ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
-          ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+      ExtensionTestMessageListener focus_listener(
+          "onFocus:text:true:true:true:false", false);
+      const auto context =
+          CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TEXT);
       engine_handler->FocusIn(context);
       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
       ASSERT_TRUE(focus_listener.was_satisfied());
     }
     {
       ExtensionTestMessageListener focus_listener(
-          "onFocus:search:true:true:true", false);
-      ui::IMEEngineHandlerInterface::InputContext context(
-          ui::TEXT_INPUT_TYPE_SEARCH, ui::TEXT_INPUT_MODE_DEFAULT,
-          ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
-      engine_handler->FocusIn(context);
-      ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
-      ASSERT_TRUE(focus_listener.was_satisfied());
-    }
-    {
-      ExtensionTestMessageListener focus_listener("onFocus:tel:true:true:true",
-                                                  false);
-      ui::IMEEngineHandlerInterface::InputContext context(
-          ui::TEXT_INPUT_TYPE_TELEPHONE, ui::TEXT_INPUT_MODE_DEFAULT,
-          ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
-      engine_handler->FocusIn(context);
-      ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
-      ASSERT_TRUE(focus_listener.was_satisfied());
-    }
-    {
-      ExtensionTestMessageListener focus_listener("onFocus:url:true:true:true",
-                                                  false);
-      ui::IMEEngineHandlerInterface::InputContext context(
-          ui::TEXT_INPUT_TYPE_URL, ui::TEXT_INPUT_MODE_DEFAULT,
-          ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+          "onFocus:search:true:true:true:false", false);
+      const auto context =
+          CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_SEARCH);
       engine_handler->FocusIn(context);
       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
       ASSERT_TRUE(focus_listener.was_satisfied());
     }
     {
       ExtensionTestMessageListener focus_listener(
-          "onFocus:email:true:true:true", false);
-      ui::IMEEngineHandlerInterface::InputContext context(
-          ui::TEXT_INPUT_TYPE_EMAIL, ui::TEXT_INPUT_MODE_DEFAULT,
-          ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+          "onFocus:tel:true:true:true:false", false);
+      const auto context =
+          CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TELEPHONE);
       engine_handler->FocusIn(context);
       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
       ASSERT_TRUE(focus_listener.was_satisfied());
     }
     {
       ExtensionTestMessageListener focus_listener(
-          "onFocus:number:true:true:true", false);
-      ui::IMEEngineHandlerInterface::InputContext context(
-          ui::TEXT_INPUT_TYPE_NUMBER, ui::TEXT_INPUT_MODE_DEFAULT,
-          ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+          "onFocus:url:true:true:true:false", false);
+      const auto context =
+          CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_URL);
+      engine_handler->FocusIn(context);
+      ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
+      ASSERT_TRUE(focus_listener.was_satisfied());
+    }
+    {
+      ExtensionTestMessageListener focus_listener(
+          "onFocus:email:true:true:true:false", false);
+      const auto context =
+          CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_EMAIL);
+      engine_handler->FocusIn(context);
+      ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
+      ASSERT_TRUE(focus_listener.was_satisfied());
+    }
+    {
+      ExtensionTestMessageListener focus_listener(
+          "onFocus:number:true:true:true:false", false);
+      const auto context =
+          CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_NUMBER);
       engine_handler->FocusIn(context);
       ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
       ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1090,10 +1090,9 @@
     SCOPED_TRACE("Text");
 
     ExtensionTestMessageListener focus_listener(
-        "onFocus:text:false:false:false", false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+        "onFocus:text:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TEXT);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1102,10 +1101,9 @@
     SCOPED_TRACE("Password");
 
     ExtensionTestMessageListener focus_listener(
-        "onFocus:password:false:false:false", false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_PASSWORD, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+        "onFocus:password:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1113,11 +1111,10 @@
   {
     SCOPED_TRACE("URL");
 
-    ExtensionTestMessageListener focus_listener("onFocus:url:false:false:false",
-                                                false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_URL, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+    ExtensionTestMessageListener focus_listener(
+        "onFocus:url:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_URL);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1126,10 +1123,9 @@
     SCOPED_TRACE("Search");
 
     ExtensionTestMessageListener focus_listener(
-        "onFocus:search:false:false:false", false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_SEARCH, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+        "onFocus:search:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_SEARCH);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1138,10 +1134,9 @@
     SCOPED_TRACE("Email");
 
     ExtensionTestMessageListener focus_listener(
-        "onFocus:email:false:false:false", false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_EMAIL, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+        "onFocus:email:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_EMAIL);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1150,10 +1145,9 @@
     SCOPED_TRACE("Number");
 
     ExtensionTestMessageListener focus_listener(
-        "onFocus:number:false:false:false", false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_NUMBER, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+        "onFocus:number:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_NUMBER);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
@@ -1161,17 +1155,45 @@
   {
     SCOPED_TRACE("Telephone");
 
-    ExtensionTestMessageListener focus_listener("onFocus:tel:false:false:false",
-                                                false);
-    ui::IMEEngineHandlerInterface::InputContext context(
-        ui::TEXT_INPUT_TYPE_TELEPHONE, ui::TEXT_INPUT_MODE_DEFAULT,
-        ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_OTHER);
+    ExtensionTestMessageListener focus_listener(
+        "onFocus:tel:false:false:false:false", false);
+    const auto context =
+        CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TELEPHONE);
     engine_handler->FocusIn(context);
     ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
     ASSERT_TRUE(focus_listener.was_satisfied());
   }
 }
 
+IN_PROC_BROWSER_TEST_P(InputMethodEngineBrowserTest, ShouldDoLearning) {
+  LoadTestInputMethod();
+
+  InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
+      kIdentityIMEID, false /* show_message */);
+
+  std::unique_ptr<ui::MockIMEInputContextHandler> mock_input_context(
+      new ui::MockIMEInputContextHandler());
+  std::unique_ptr<MockIMECandidateWindowHandler> mock_candidate_window(
+      new MockIMECandidateWindowHandler());
+
+  ui::IMEBridge::Get()->SetInputContextHandler(mock_input_context.get());
+  ui::IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
+
+  ui::IMEEngineHandlerInterface* engine_handler =
+      ui::IMEBridge::Get()->GetCurrentEngineHandler();
+  ASSERT_TRUE(engine_handler);
+  engine_handler->Enable("IdentityIME");
+
+  // onFocus event should be fired if FocusIn function is called.
+  ExtensionTestMessageListener focus_listener(
+      "onFocus:text:true:true:true:true", false);
+  auto context = CreateInputContextWithInputType(ui::TEXT_INPUT_TYPE_TEXT);
+  context.should_do_learning = true;
+  engine_handler->FocusIn(context);
+  ASSERT_TRUE(focus_listener.WaitUntilSatisfied());
+  ASSERT_TRUE(focus_listener.was_satisfied());
+}
+
 }  // namespace
 }  // namespace input_method
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
index bfed21db..f3352ee6 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
@@ -167,7 +167,8 @@
   void FocusIn(ui::TextInputType input_type) {
     ui::IMEEngineHandlerInterface::InputContext input_context(
         input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
-        ui::TextInputClient::FOCUS_REASON_OTHER);
+        ui::TextInputClient::FOCUS_REASON_OTHER,
+        false /* should_do_learning */);
     engine_->FocusIn(input_context);
     ui::IMEBridge::Get()->SetCurrentInputContext(input_context);
   }
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index fdf6dab..34b2a98 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -59,6 +59,7 @@
   context_value.auto_correct = ConvertInputContextAutoCorrect(context);
   context_value.auto_complete = ConvertInputContextAutoComplete(context);
   context_value.spell_check = ConvertInputContextSpellCheck(context);
+  context_value.should_do_learning = context.should_do_learning;
 
   std::unique_ptr<base::ListValue> args(
       input_ime::OnFocus::Create(context_value));
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index b7dc8c6..85611ab 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -207,6 +207,7 @@
       input_context.auto_correct = ConvertInputContextAutoCorrect(context);
       input_context.auto_complete = ConvertInputContextAutoComplete(context);
       input_context.spell_check = ConvertInputContextSpellCheck(context);
+      input_context.should_do_learning = context.should_do_learning;
       input_context.focus_reason = input_method_private::ParseFocusReason(
           ConvertInputContextFocusReason(context));
 
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index 2e4a39a..2f248f45 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -188,10 +188,9 @@
   if (generated_icon_color == SK_ColorTRANSPARENT)
     generated_icon_color = SK_ColorDKGRAY;
 
-  for (std::set<int>::const_iterator it = generate_sizes.begin();
-       it != generate_sizes.end(); ++it) {
+  for (int size : generate_sizes) {
     extensions::BookmarkAppHelper::GenerateIcon(
-        bitmap_map, *it, generated_icon_color, icon_letter);
+        bitmap_map, size, generated_icon_color, icon_letter);
   }
 }
 
@@ -385,10 +384,10 @@
     const std::set<int>& sizes) {
   std::map<int, BitmapAndSource> output_bitmaps;
   std::map<int, BitmapAndSource> ordered_bitmaps;
-  for (std::vector<BitmapAndSource>::const_iterator it = bitmaps.begin();
-       it != bitmaps.end(); ++it) {
-    DCHECK(it->bitmap.width() == it->bitmap.height());
-    ordered_bitmaps[it->bitmap.width()] = *it;
+  for (const BitmapAndSource& bitmap_and_source : bitmaps) {
+    const SkBitmap& bitmap = bitmap_and_source.bitmap;
+    DCHECK(bitmap.width() == bitmap.height());
+    ordered_bitmaps[bitmap.width()] = bitmap_and_source;
   }
 
   if (ordered_bitmaps.size() > 0) {
@@ -442,14 +441,12 @@
 
   // Iterate through the extensions and extract the LaunchWebUrl (bookmark apps)
   // or check the web extent (hosted apps).
-  for (extensions::ExtensionSet::const_iterator iter = extensions.begin();
-       iter != extensions.end(); ++iter) {
-    const Extension* extension = iter->get();
+  for (const scoped_refptr<const Extension>& extension : extensions) {
     if (!extension->is_hosted_app())
       continue;
 
     if (extension->web_extent().MatchesURL(url) ||
-        AppLaunchInfo::GetLaunchWebURL(extension) == url) {
+        AppLaunchInfo::GetLaunchWebURL(extension.get()) == url) {
       return true;
     }
   }
@@ -673,28 +670,20 @@
   }
 
   std::vector<BitmapAndSource> downloaded_icons;
-  for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin();
-       map_it != bitmaps.end();
-       ++map_it) {
-    for (std::vector<SkBitmap>::const_iterator bitmap_it =
-             map_it->second.begin();
-         bitmap_it != map_it->second.end();
-         ++bitmap_it) {
-      if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height())
+  for (const std::pair<GURL, std::vector<SkBitmap>>& url_bitmap : bitmaps) {
+    for (const SkBitmap& bitmap : url_bitmap.second) {
+      if (bitmap.empty() || bitmap.width() != bitmap.height())
         continue;
 
-      downloaded_icons.push_back(BitmapAndSource(map_it->first, *bitmap_it));
+      downloaded_icons.push_back(BitmapAndSource(url_bitmap.first, bitmap));
     }
   }
 
   // Add all existing icons from WebApplicationInfo.
-  for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it =
-           web_app_info_.icons.begin();
-       it != web_app_info_.icons.end();
-       ++it) {
-    const SkBitmap& icon = it->data;
+  for (const WebApplicationInfo::IconInfo& icon_info : web_app_info_.icons) {
+    const SkBitmap& icon = icon_info.data;
     if (!icon.drawsNothing() && icon.width() == icon.height()) {
-      downloaded_icons.push_back(BitmapAndSource(it->url, icon));
+      downloaded_icons.push_back(BitmapAndSource(icon_info.url, icon));
     }
   }
 
diff --git a/chrome/browser/media/router/mojo/media_router_desktop.cc b/chrome/browser/media/router/mojo/media_router_desktop.cc
index dca903dc..02f46c8 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/media/router/mojo/media_route_controller.h"
 #include "chrome/browser/media/router/mojo/media_router_mojo_metrics.h"
 #include "chrome/browser/media/router/providers/cast/cast_media_route_provider.h"
+#include "chrome/browser/media/router/providers/cast/chrome_cast_message_handler.h"
 #include "chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
@@ -243,7 +244,9 @@
           new CastMediaRouteProvider(
               mojo::MakeRequest(&cast_provider_ptr),
               media_router_ptr.PassInterface(),
-              media_sink_service_->cast_app_discovery_service(), task_runner),
+              media_sink_service_->GetCastMediaSinkServiceImpl(),
+              media_sink_service_->cast_app_discovery_service(),
+              GetCastMessageHandler(), task_runner),
           base::OnTaskRunnerDeleter(task_runner));
   RegisterMediaRouteProvider(MediaRouteProviderId::CAST,
                              std::move(cast_provider_ptr), base::DoNothing());
diff --git a/chrome/browser/media/router/providers/cast/cast_app_discovery_service.cc b/chrome/browser/media/router/providers/cast/cast_app_discovery_service.cc
index 291ef691..adad5fa 100644
--- a/chrome/browser/media/router/providers/cast/cast_app_discovery_service.cc
+++ b/chrome/browser/media/router/providers/cast/cast_app_discovery_service.cc
@@ -37,7 +37,7 @@
 
 }  // namespace
 
-CastAppDiscoveryService::CastAppDiscoveryService(
+CastAppDiscoveryServiceImpl::CastAppDiscoveryServiceImpl(
     cast_channel::CastMessageHandler* message_handler,
     cast_channel::CastSocketService* socket_service,
     MediaSinkServiceBase* media_sink_service,
@@ -52,17 +52,17 @@
   DCHECK(socket_service_);
   DCHECK(clock_);
   socket_service_->task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&CastAppDiscoveryService::Init, base::Unretained(this)));
+      FROM_HERE, base::BindOnce(&CastAppDiscoveryServiceImpl::Init,
+                                base::Unretained(this)));
 }
 
-CastAppDiscoveryService::~CastAppDiscoveryService() {
+CastAppDiscoveryServiceImpl::~CastAppDiscoveryServiceImpl() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   media_sink_service_->RemoveObserver(this);
 }
 
 CastAppDiscoveryService::Subscription
-CastAppDiscoveryService::StartObservingMediaSinks(
+CastAppDiscoveryServiceImpl::StartObservingMediaSinks(
     const CastMediaSource& source,
     const SinkQueryCallback& callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -77,9 +77,9 @@
   auto& callback_list = sink_queries_[source_id];
   if (!callback_list) {
     callback_list = std::make_unique<SinkQueryCallbackList>();
-    callback_list->set_removal_callback(
-        base::BindRepeating(&CastAppDiscoveryService::MaybeRemoveSinkQueryEntry,
-                            base::Unretained(this), source));
+    callback_list->set_removal_callback(base::BindRepeating(
+        &CastAppDiscoveryServiceImpl::MaybeRemoveSinkQueryEntry,
+        base::Unretained(this), source));
 
     // Note: even though we retain availability results for an app unregistered
     // from the tracker, we will send app availability requests again when it
@@ -108,7 +108,7 @@
   return callback_list->Add(callback);
 }
 
-void CastAppDiscoveryService::Refresh() {
+void CastAppDiscoveryServiceImpl::Refresh() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const auto app_ids = availability_tracker_.GetRegisteredApps();
   base::TimeTicks now = clock_->NowTicks();
@@ -133,7 +133,7 @@
   }
 }
 
-void CastAppDiscoveryService::MaybeRemoveSinkQueryEntry(
+void CastAppDiscoveryServiceImpl::MaybeRemoveSinkQueryEntry(
     const CastMediaSource& source) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto it = sink_queries_.find(source.source_id());
@@ -145,12 +145,12 @@
   }
 }
 
-void CastAppDiscoveryService::Init() {
+void CastAppDiscoveryServiceImpl::Init() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   media_sink_service_->AddObserver(this);
 }
 
-void CastAppDiscoveryService::OnSinkAddedOrUpdated(
+void CastAppDiscoveryServiceImpl::OnSinkAddedOrUpdated(
     const MediaSinkInternal& sink) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -169,24 +169,24 @@
   }
 }
 
-void CastAppDiscoveryService::OnSinkRemoved(const MediaSinkInternal& sink) {
+void CastAppDiscoveryServiceImpl::OnSinkRemoved(const MediaSinkInternal& sink) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const MediaSink::Id& sink_id = sink.sink().id();
   UpdateSinkQueries(availability_tracker_.RemoveResultsForSink(sink_id));
 }
 
-void CastAppDiscoveryService::RequestAppAvailability(
+void CastAppDiscoveryServiceImpl::RequestAppAvailability(
     cast_channel::CastSocket* socket,
     const std::string& app_id,
     const MediaSink::Id& sink_id) {
   message_handler_->RequestAppAvailability(
       socket, app_id,
-      base::BindOnce(&CastAppDiscoveryService::UpdateAppAvailability,
+      base::BindOnce(&CastAppDiscoveryServiceImpl::UpdateAppAvailability,
                      weak_ptr_factory_.GetWeakPtr(), clock_->NowTicks(),
                      sink_id));
 }
 
-void CastAppDiscoveryService::UpdateAppAvailability(
+void CastAppDiscoveryServiceImpl::UpdateAppAvailability(
     base::TimeTicks start_time,
     const MediaSink::Id& sink_id,
     const std::string& app_id,
@@ -203,7 +203,7 @@
       sink_id, app_id, {availability, clock_->NowTicks()}));
 }
 
-void CastAppDiscoveryService::UpdateSinkQueries(
+void CastAppDiscoveryServiceImpl::UpdateSinkQueries(
     const std::vector<CastMediaSource>& sources) {
   for (const auto& source : sources) {
     const MediaSource::Id& source_id = source.source_id();
@@ -216,7 +216,7 @@
   }
 }
 
-std::vector<MediaSinkInternal> CastAppDiscoveryService::GetSinksByIds(
+std::vector<MediaSinkInternal> CastAppDiscoveryServiceImpl::GetSinksByIds(
     const base::flat_set<MediaSink::Id>& sink_ids) const {
   std::vector<MediaSinkInternal> sinks;
   for (const auto& sink_id : sink_ids) {
diff --git a/chrome/browser/media/router/providers/cast/cast_app_discovery_service.h b/chrome/browser/media/router/providers/cast/cast_app_discovery_service.h
index 4748f6b..def76dc 100644
--- a/chrome/browser/media/router/providers/cast/cast_app_discovery_service.h
+++ b/chrome/browser/media/router/providers/cast/cast_app_discovery_service.h
@@ -35,11 +35,8 @@
 
 namespace media_router {
 
-// Keeps track of sink queries and listens to CastMediaSinkServiceImpl for sink
-// updates, and issues app availability requests based on these signals. This
-// class may be created on any sequence. All other methods must be called on the
-// CastSocketService sequence.
-class CastAppDiscoveryService : public MediaSinkServiceBase::Observer {
+// Interface for app discovery for Cast MediaSinks.
+class CastAppDiscoveryService {
  public:
   using SinkQueryFunc = void(const MediaSource::Id& source_id,
                              const std::vector<MediaSinkInternal>& sinks);
@@ -47,27 +44,46 @@
   using SinkQueryCallbackList = base::CallbackList<SinkQueryFunc>;
   using Subscription = std::unique_ptr<SinkQueryCallbackList::Subscription>;
 
-  CastAppDiscoveryService(cast_channel::CastMessageHandler* message_handler,
-                          cast_channel::CastSocketService* socket_service,
-                          MediaSinkServiceBase* media_sink_service,
-                          const base::TickClock* clock);
-  ~CastAppDiscoveryService() override;
+  virtual ~CastAppDiscoveryService() = default;
 
   // Adds a sink query for |source|. Results will be continuously returned via
   // |callback| until the returned Subscription is destroyed by the caller.
   // If there are cached results available, |callback| will be invoked before
   // this method returns.
-  Subscription StartObservingMediaSinks(const CastMediaSource& source,
-                                        const SinkQueryCallback& callback);
+  virtual Subscription StartObservingMediaSinks(
+      const CastMediaSource& source,
+      const SinkQueryCallback& callback) = 0;
 
-  // Reissues app availability requests for currently registered (sink, app_id)
-  // pairs whose status is kUnavailable or kUnknown. It is suitable to call
+  // Refreshes the state of app discovery in the service. It is suitable to call
   // this method when the user initiates a user gesture (such as opening the
   // Media Router dialog).
-  void Refresh();
+  virtual void Refresh() = 0;
+};
+
+// Keeps track of sink queries and listens to CastMediaSinkServiceImpl for sink
+// updates, and issues app availability requests based on these signals. This
+// class may be created on any sequence. All other methods must be called on the
+// CastSocketService sequence.
+class CastAppDiscoveryServiceImpl : public CastAppDiscoveryService,
+                                    public MediaSinkServiceBase::Observer {
+ public:
+  CastAppDiscoveryServiceImpl(cast_channel::CastMessageHandler* message_handler,
+                              cast_channel::CastSocketService* socket_service,
+                              MediaSinkServiceBase* media_sink_service,
+                              const base::TickClock* clock);
+  ~CastAppDiscoveryServiceImpl() override;
+
+  // CastAppDiscoveryService implementation.
+  Subscription StartObservingMediaSinks(
+      const CastMediaSource& source,
+      const SinkQueryCallback& callback) override;
+
+  // Reissues app availability requests for currently registered (sink, app_id)
+  // pairs whose status is kUnavailable or kUnknown.
+  void Refresh() override;
 
  private:
-  friend class CastAppDiscoveryServiceTest;
+  friend class CastAppDiscoveryServiceImplTest;
 
   // Called on construction. Registers an observer with |media_sink_service_|.
   void Init();
@@ -115,8 +131,8 @@
   const base::TickClock* const clock_;
 
   SEQUENCE_CHECKER(sequence_checker_);
-  base::WeakPtrFactory<CastAppDiscoveryService> weak_ptr_factory_;
-  DISALLOW_COPY_AND_ASSIGN(CastAppDiscoveryService);
+  base::WeakPtrFactory<CastAppDiscoveryServiceImpl> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(CastAppDiscoveryServiceImpl);
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/cast_app_discovery_service_unittest.cc b/chrome/browser/media/router/providers/cast/cast_app_discovery_service_unittest.cc
index 32e2f18..de86665 100644
--- a/chrome/browser/media/router/providers/cast/cast_app_discovery_service_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/cast_app_discovery_service_unittest.cc
@@ -28,10 +28,10 @@
         socket_service_(task_runner_),
         message_handler_(&socket_service_),
         app_discovery_service_(
-            std::make_unique<CastAppDiscoveryService>(&message_handler_,
-                                                      &socket_service_,
-                                                      &media_sink_service_,
-                                                      &clock_)),
+            std::make_unique<CastAppDiscoveryServiceImpl>(&message_handler_,
+                                                          &socket_service_,
+                                                          &media_sink_service_,
+                                                          &clock_)),
         source_a_1_(*CastMediaSource::From("cast:AAAAAAAA?clientId=1")),
         source_a_2_(*CastMediaSource::From("cast:AAAAAAAA?clientId=2")),
         source_b_1_(*CastMediaSource::From("cast:BBBBBBBB?clientId=1")) {
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
index 26c400d..3cdfa5c 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.cc
@@ -6,6 +6,7 @@
 
 #include "base/stl_util.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
+#include "components/cast_channel/cast_message_handler.h"
 #include "url/origin.h"
 
 namespace media_router {
@@ -34,11 +35,18 @@
 CastMediaRouteProvider::CastMediaRouteProvider(
     mojom::MediaRouteProviderRequest request,
     mojom::MediaRouterPtrInfo media_router,
+    MediaSinkServiceBase* media_sink_service,
     CastAppDiscoveryService* app_discovery_service,
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
-    : binding_(this), app_discovery_service_(app_discovery_service) {
+    cast_channel::CastMessageHandler* message_handler,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    : binding_(this),
+      media_sink_service_(media_sink_service),
+      app_discovery_service_(app_discovery_service),
+      message_handler_(message_handler) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
+  DCHECK(media_sink_service_);
   DCHECK(app_discovery_service_);
+  DCHECK(message_handler_);
 
   task_runner->PostTask(
       FROM_HERE,
@@ -145,8 +153,9 @@
   // A broadcast request is not an actual sink query; it is used to send a
   // app precache message to receivers.
   if (cast_source->broadcast_request()) {
-    // TODO(crbug.com/809249): Implement broadcast, or figure out a re-design
-    // that does not use sink queries.
+    // TODO(imcheng): Add metric to record broadcast usage.
+    BroadcastMessageToSinks(cast_source->GetAppIds(),
+                            *cast_source->broadcast_request());
     return;
   }
 
@@ -227,4 +236,14 @@
                                  GetOrigins(source_id));
 }
 
+void CastMediaRouteProvider::BroadcastMessageToSinks(
+    const std::vector<std::string>& app_ids,
+    const cast_channel::BroadcastRequest& request) {
+  for (const auto& id_and_sink : media_sink_service_->GetSinks()) {
+    const MediaSinkInternal& sink = id_and_sink.second;
+    message_handler_->SendBroadcastMessage(sink.cast_data().cast_channel_id,
+                                           app_ids, request);
+  }
+}
+
 }  // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
index 5dd7b23..b23da2d 100644
--- a/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider.h
@@ -12,6 +12,10 @@
 #include "chrome/common/media_router/mojo/media_router.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+namespace cast_channel {
+class CastMessageHandler;
+}
+
 namespace url {
 class Origin;
 }
@@ -26,8 +30,10 @@
   CastMediaRouteProvider(
       mojom::MediaRouteProviderRequest request,
       mojom::MediaRouterPtrInfo media_router,
+      MediaSinkServiceBase* media_sink_service,
       CastAppDiscoveryService* app_discovery_service,
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+      cast_channel::CastMessageHandler* message_handler,
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
   ~CastMediaRouteProvider() override;
 
   // mojom::MediaRouteProvider:
@@ -92,15 +98,25 @@
   void OnSinkQueryUpdated(const MediaSource::Id& source_id,
                           const std::vector<MediaSinkInternal>& sinks);
 
+  // Broadcasts a message with |app_ids| and |requests| to all sinks.
+  void BroadcastMessageToSinks(const std::vector<std::string>& app_ids,
+                               const cast_channel::BroadcastRequest& request);
+
   // Binds |this| to the Mojo request passed into the ctor.
   mojo::Binding<mojom::MediaRouteProvider> binding_;
 
   // Mojo pointer to the Media Router.
   mojom::MediaRouterPtr media_router_;
 
+  // Non-owned pointer to the Cast MediaSinkServiceBase.
+  MediaSinkServiceBase* const media_sink_service_;
+
   // Non-owned pointer to the CastAppDiscoveryService instance.
   CastAppDiscoveryService* const app_discovery_service_;
 
+  // Non-owned pointer to the CastMessageHandler instance.
+  cast_channel::CastMessageHandler* const message_handler_;
+
   // Registered sink queries.
   base::flat_map<MediaSource::Id, CastAppDiscoveryService::Subscription>
       sink_queries_;
diff --git a/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
new file mode 100644
index 0000000..b32a575
--- /dev/null
+++ b/chrome/browser/media/router/providers/cast/cast_media_route_provider_unittest.cc
@@ -0,0 +1,93 @@
+// 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/media/router/providers/cast/cast_media_route_provider.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/browser/media/router/test/mock_mojo_media_router.h"
+#include "chrome/browser/media/router/test/test_helper.h"
+#include "chrome/common/media_router/test/test_helper.h"
+#include "components/cast_channel/cast_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace media_router {
+
+class CastMediaRouteProviderTest : public testing::Test {
+ public:
+  CastMediaRouteProviderTest()
+      : socket_service_(new base::TestSimpleTaskRunner()),
+        message_handler_(&socket_service_) {}
+  ~CastMediaRouteProviderTest() override = default;
+
+  void SetUp() override {
+    mojom::MediaRouterPtr router_ptr;
+    router_binding_ = std::make_unique<mojo::Binding<mojom::MediaRouter>>(
+        &mock_router_, mojo::MakeRequest(&router_ptr));
+
+    EXPECT_CALL(mock_router_, OnSinkAvailabilityUpdated(_, _));
+    provider_ = std::make_unique<CastMediaRouteProvider>(
+        mojo::MakeRequest(&provider_ptr_), router_ptr.PassInterface(),
+        &media_sink_service_, &app_discovery_service_, &message_handler_,
+        base::SequencedTaskRunnerHandle::Get());
+
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void TearDown() override { provider_.reset(); }
+
+ protected:
+  base::test::ScopedTaskEnvironment environment_;
+  mojom::MediaRouteProviderPtr provider_ptr_;
+  MockMojoMediaRouter mock_router_;
+  std::unique_ptr<mojo::Binding<mojom::MediaRouter>> router_binding_;
+
+  cast_channel::MockCastSocketService socket_service_;
+  cast_channel::MockCastMessageHandler message_handler_;
+
+  TestMediaSinkService media_sink_service_;
+  MockCastAppDiscoveryService app_discovery_service_;
+  std::unique_ptr<CastMediaRouteProvider> provider_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CastMediaRouteProviderTest);
+};
+
+TEST_F(CastMediaRouteProviderTest, StartObservingMediaSinks) {
+  MediaSource::Id non_cast_source("not-a-cast-source:foo");
+  EXPECT_CALL(app_discovery_service_, DoStartObservingMediaSinks(_)).Times(0);
+  provider_->StartObservingMediaSinks(non_cast_source);
+
+  MediaSource::Id cast_source("cast:ABCDEFGH");
+  EXPECT_CALL(app_discovery_service_, DoStartObservingMediaSinks(_));
+  provider_->StartObservingMediaSinks(cast_source);
+  EXPECT_FALSE(app_discovery_service_.callbacks().empty());
+
+  provider_->StopObservingMediaSinks(cast_source);
+  EXPECT_TRUE(app_discovery_service_.callbacks().empty());
+}
+
+TEST_F(CastMediaRouteProviderTest, BroadcastRequest) {
+  media_sink_service_.AddOrUpdateSink(CreateCastSink(1));
+  media_sink_service_.AddOrUpdateSink(CreateCastSink(2));
+  MediaSource::Id source_id(
+      "cast:ABCDEFAB?capabilities=video_out,audio_out"
+      "&broadcastNamespace=namespace"
+      "&broadcastMessage=message");
+
+  std::vector<std::string> app_ids = {"ABCDEFAB"};
+  cast_channel::BroadcastRequest request("namespace", "message");
+  EXPECT_CALL(message_handler_, SendBroadcastMessage(1, app_ids, request));
+  EXPECT_CALL(message_handler_, SendBroadcastMessage(2, app_ids, request));
+  EXPECT_CALL(app_discovery_service_, DoStartObservingMediaSinks(_)).Times(0);
+  provider_->StartObservingMediaSinks(source_id);
+  EXPECT_TRUE(app_discovery_service_.callbacks().empty());
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc b/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
index 706f3994..c558ef7 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
@@ -38,6 +38,10 @@
   return dial_media_sink_service_->impl();
 }
 
+MediaSinkServiceBase* DualMediaSinkService::GetCastMediaSinkServiceImpl() {
+  return cast_media_sink_service_->impl();
+}
+
 DualMediaSinkService::Subscription
 DualMediaSinkService::AddSinksDiscoveredCallback(
     const OnSinksDiscoveredProviderCallback& callback) {
@@ -75,10 +79,11 @@
     if (CastMediaRouteProviderEnabled()) {
       cast_channel::CastSocketService* cast_socket_service =
           cast_channel::CastSocketService::GetInstance();
-      cast_app_discovery_service_ = std::make_unique<CastAppDiscoveryService>(
-          GetCastMessageHandler(), cast_socket_service,
-          cast_media_sink_service_->impl(),
-          base::DefaultTickClock::GetInstance());
+      cast_app_discovery_service_ =
+          std::make_unique<CastAppDiscoveryServiceImpl>(
+              GetCastMessageHandler(), cast_socket_service,
+              cast_media_sink_service_->impl(),
+              base::DefaultTickClock::GetInstance());
     }
   }
 }
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service.h b/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
index 21a801d..b5ea6ca 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
@@ -59,6 +59,9 @@
   // Used by DialMediaRouteProvider only.
   DialMediaSinkServiceImpl* GetDialMediaSinkServiceImpl();
 
+  // Used by CastMediaRouteProvider only.
+  MediaSinkServiceBase* GetCastMediaSinkServiceImpl();
+
   CastAppDiscoveryService* cast_app_discovery_service() {
     return cast_app_discovery_service_.get();
   }
diff --git a/chrome/browser/media/router/test/test_helper.cc b/chrome/browser/media/router/test/test_helper.cc
index 7556e85..609ef90 100644
--- a/chrome/browser/media/router/test/test_helper.cc
+++ b/chrome/browser/media/router/test/test_helper.cc
@@ -61,6 +61,17 @@
 MockCastMediaSinkService::MockCastMediaSinkService() : CastMediaSinkService() {}
 MockCastMediaSinkService::~MockCastMediaSinkService() = default;
 
+MockCastAppDiscoveryService::MockCastAppDiscoveryService() {}
+MockCastAppDiscoveryService::~MockCastAppDiscoveryService() = default;
+
+CastAppDiscoveryService::Subscription
+MockCastAppDiscoveryService::StartObservingMediaSinks(
+    const CastMediaSource& source,
+    const CastAppDiscoveryService::SinkQueryCallback& callback) {
+  DoStartObservingMediaSinks(source);
+  return callbacks_.Add(callback);
+}
+
 MockDialAppDiscoveryService::MockDialAppDiscoveryService()
     : DialAppDiscoveryService(/*connector=*/nullptr) {}
 MockDialAppDiscoveryService::~MockDialAppDiscoveryService() = default;
diff --git a/chrome/browser/media/router/test/test_helper.h b/chrome/browser/media/router/test/test_helper.h
index bf6b9315..30b37ee 100644
--- a/chrome/browser/media/router/test/test_helper.h
+++ b/chrome/browser/media/router/test/test_helper.h
@@ -26,6 +26,7 @@
 #include "chrome/browser/media/router/discovery/dial/dial_url_fetcher.h"
 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h"
 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h"
+#include "chrome/browser/media/router/providers/cast/cast_app_discovery_service.h"
 #include "chrome/browser/media/router/providers/dial/dial_activity_manager.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "net/base/ip_endpoint.h"
@@ -138,6 +139,23 @@
   MOCK_METHOD0(StartMdnsDiscovery, void());
 };
 
+class MockCastAppDiscoveryService : public CastAppDiscoveryService {
+ public:
+  MockCastAppDiscoveryService();
+  ~MockCastAppDiscoveryService() override;
+
+  Subscription StartObservingMediaSinks(
+      const CastMediaSource& source,
+      const SinkQueryCallback& callback) override;
+  MOCK_METHOD1(DoStartObservingMediaSinks, void(const CastMediaSource&));
+  MOCK_METHOD0(Refresh, void());
+
+  SinkQueryCallbackList& callbacks() { return callbacks_; }
+
+ private:
+  SinkQueryCallbackList callbacks_;
+};
+
 class MockDialAppDiscoveryService : public DialAppDiscoveryService {
  public:
   MockDialAppDiscoveryService();
diff --git a/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html b/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
index 32ef3ea..b2daa381 100644
--- a/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
+++ b/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
@@ -1,9 +1,9 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
 <link rel="import" href="about_page_browser_proxy.html">
 <link rel="import" href="../settings_shared_css.html">
@@ -21,17 +21,17 @@
         <!-- TODO(dbeam): this can be policy-controlled. Show this in the UI.
              https://www.chromium.org/administrators/policy-list-3#ChromeOsReleaseChannel
         -->
-        <paper-radio-group
+        <paper-radio-group selectable="cr-radio-button"
             on-paper-radio-group-changed="onChannelSelectionChanged_">
-          <paper-radio-button name="[[browserChannelEnum_.STABLE]]">
+          <cr-radio-button name="[[browserChannelEnum_.STABLE]]">
             $i18n{aboutChannelDialogStable}
-          </paper-radio-button>
-          <paper-radio-button name="[[browserChannelEnum_.BETA]]">
+          </cr-radio-button>
+          <cr-radio-button name="[[browserChannelEnum_.BETA]]">
             $i18n{aboutChannelDialogBeta}
-          </paper-radio-button>
-          <paper-radio-button name="[[browserChannelEnum_.DEV]]">
+          </cr-radio-button>
+          <cr-radio-button name="[[browserChannelEnum_.DEV]]">
             $i18n{aboutChannelDialogDev}
-          </paper-radio-button>
+          </cr-radio-button>
         </paper-radio-group>
         <iron-selector id="warningSelector">
           <div>
diff --git a/chrome/browser/resources/settings/controls/BUILD.gn b/chrome/browser/resources/settings/controls/BUILD.gn
index c624702..21618639 100644
--- a/chrome/browser/resources/settings/controls/BUILD.gn
+++ b/chrome/browser/resources/settings/controls/BUILD.gn
@@ -33,6 +33,7 @@
     ":pref_control_behavior",
     "../prefs:pref_util",
     "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
+    "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button_behavior",
     "//ui/webui/resources/js:assert",
   ]
   externs_list = [ "$externs_path/settings_private.js" ]
diff --git a/chrome/browser/resources/settings/controls/controlled_radio_button.html b/chrome/browser/resources/settings/controls/controlled_radio_button.html
index 018f8dd..a8260c2 100644
--- a/chrome/browser/resources/settings/controls/controlled_radio_button.html
+++ b/chrome/browser/resources/settings/controls/controlled_radio_button.html
@@ -1,5 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
 <link rel="import" href="pref_control_behavior.html">
@@ -8,109 +10,15 @@
 
 <dom-module id="controlled-radio-button">
   <template>
-    <style include="settings-shared">
-      :host {
-        --ink-to-circle: calc((var(--paper-radio-button-ink-size) -
-                               var(--paper-radio-button-size)) / 2);
-        @apply --settings-actionable;
-        align-items: center;
-        display: flex;
-        outline: none;
-      }
-
-      #labelWrapper {
-        -webkit-margin-start: var(--paper-radio-button-label-spacing, 10px);
-        flex: 1;
-      }
-
-      #label {
-        color: var(--paper-radio-button-label-color, var(--primary-text-color));
-      }
-
-      .circle,
-      .disc,
-      .disc-wrapper,
-      paper-ripple {
-        border-radius: 50%;
-      }
-
-      .disc-wrapper {
-        height: var(--paper-radio-button-ink-size);
-        margin: 0 calc(-1 * var(--ink-to-circle));
-        position: relative;
-        width: var(--paper-radio-button-ink-size);
-      }
-
-      .circle,
-      .disc {
-        box-sizing: border-box;
-        height: var(--paper-radio-button-size);
-        left: var(--ink-to-circle);
-        position: absolute;
-        top: var(--ink-to-circle);
-        width: var(--paper-radio-button-size);
-      }
-
-      .circle {
-        border: 2px solid var(--paper-radio-button-unchecked-color,
-                              var(--primary-text-color));
-      }
-
-      :host([checked]) .circle {
-        border-color: var(--paper-radio-button-checked-color,
-                          var(--primary-color));
-      }
-
-      .disc {
-        background-color: var(--paper-radio-button-unchecked-background-color,
-                              transparent);
-        transform: scale(0);
-        transition: border-color 200ms, transform 200ms;
-      }
-
-      :host([checked]) .disc {
-        background-color: var(--paper-radio-button-checked-color,
-                              var(--primary-color));
-        transform: scale(0.5);
-      }
-
-      paper-ripple {
-        color: var(--paper-radio-button-unchecked-ink-color,
-                   var(--primary-text-color));
-        opacity: .6;
-      }
-
-      :host([checked]) paper-ripple {
-        color: var(--paper-radio-button-checked-ink-color,
-                   var(--primary-text-color));
-      }
-
-      :host(:not([disabled])) {
-        @apply --settings-actionable;
-      }
-
+    <style include="settings-shared cr-radio-button-style">
       :host([disabled]) {
-        /* Disable pointer events for this whole element, as outer on-tap gets
-         * triggered when clicking/tapping anywhere in :host. */
-        pointer-events: none;
+        opacity: 1;
       }
 
-      :host([disabled]) :-webkit-any(.circle, .disc) {
-        opacity: .5;
-      }
-
-      :host([disabled]) .circle {
-        border-color: var(--paper-radio-button-unchecked-color,
-                          var(--primary-text-color));
-      }
-
-      :host([disabled][checked]) .disc {
-        background-color: var(--paper-radio-button-unchecked-color,
-                              var(--primary-text-color));
-      }
-
+      /* Disc and label should be transluscent, but not the policy indicator. */
+      :host([disabled]) .disc-wrapper,
       :host([disabled]) #labelWrapper {
-        opacity: .65;
+        opacity: var(--cr-disabled-opacity);
       }
 
       cr-policy-pref-indicator {
@@ -122,9 +30,8 @@
     </style>
 
     <div class="disc-wrapper">
-      <div class="circle"></div>
+      <div class="disc-border"></div>
       <div class="disc"></div>
-      <paper-ripple center hold-down="[[pressed_]]"></paper-ripple>
     </div>
 
     <div id="labelWrapper">
diff --git a/chrome/browser/resources/settings/controls/controlled_radio_button.js b/chrome/browser/resources/settings/controls/controlled_radio_button.js
index 66af565..19bbcef 100644
--- a/chrome/browser/resources/settings/controls/controlled_radio_button.js
+++ b/chrome/browser/resources/settings/controls/controlled_radio_button.js
@@ -7,17 +7,10 @@
 
   behaviors: [
     PrefControlBehavior,
-    Polymer.IronA11yKeysBehavior,
+    CrRadioButtonBehavior,
   ],
 
   properties: {
-    checked: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: 'checkedChanged_',
-    },
-
     disabled: {
       type: Boolean,
       computed: 'computeDisabled_(pref.*)',
@@ -25,44 +18,10 @@
       observer: 'disabledChanged_',
     },
 
-    label: {
-      type: String,
-      value: '',  // Allows the hidden$= binding to run without being set.
-    },
-
     name: {
       type: String,
       notify: true,
     },
-
-    /** @private */
-    pressed_: Boolean,
-  },
-
-  hostAttributes: {
-    'aria-disabled': 'false',
-    'aria-checked': 'false',
-    role: 'radio',
-    tabindex: 0,
-  },
-
-  listeners: {
-    'blur': 'updatePressed_',
-    'down': 'updatePressed_',
-    'focus': 'updatePressed_',
-    'up': 'updatePressed_',
-  },
-
-  keyBindings: {
-    // This is mainly for screenreaders, which can perform actions on things
-    // that aren't focused (only focused things get synthetic click/tap events).
-    'enter:keyup': 'click',
-    'space:keyup': 'click',
-  },
-
-  /** @private */
-  checkedChanged_: function() {
-    this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
   },
 
   /**
@@ -104,15 +63,4 @@
     e.preventDefault();
     e.stopPropagation();
   },
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  updatePressed_: function(e) {
-    if (this.disabled)
-      return;
-
-    this.pressed_ = ['down', 'focus'].includes(e.type);
-  },
 });
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.html b/chrome/browser/resources/settings/controls/settings_radio_group.html
index 19c4b1bb..8bc90c2 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.html
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.html
@@ -1,7 +1,7 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="pref_control_behavior.html">
 <link rel="import" href="../prefs/pref_util.html">
 <link rel="import" href="../settings_shared_css.html">
@@ -11,7 +11,7 @@
     <style include="settings-shared"></style>
     <div>[[label]]</div>
     <paper-radio-group selected="{{selected}}"
-        selectable="paper-radio-button, controlled-radio-button">
+        selectable="cr-radio-button, controlled-radio-button">
       <slot></slot>
     </paper-radio-group>
   </template>
diff --git a/chrome/browser/resources/settings/device_page/pointers.html b/chrome/browser/resources/settings/device_page/pointers.html
index 0fb133e..221a442 100644
--- a/chrome/browser/resources/settings/device_page/pointers.html
+++ b/chrome/browser/resources/settings/device_page/pointers.html
@@ -1,11 +1,11 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
 <link rel="import" href="../controls/settings_radio_group.html">
 <link rel="import" href="../controls/settings_slider.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
-<link rel="import" href="device_page_browser_proxy.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="device_page_browser_proxy.html">
 
 <dom-module id="settings-pointers">
   <template>
@@ -79,17 +79,17 @@
         <div class="list-frame">
           <settings-radio-group
               pref="{{prefs.settings.touchpad.natural_scroll}}">
-            <paper-radio-button name="false">
+            <cr-radio-button name="false">
               $i18n{traditionalScrollLabel}
-            </paper-radio-button>
-            <paper-radio-button name="true">
+            </cr-radio-button>
+            <cr-radio-button name="true">
               $i18n{naturalScrollLabel}
               <a href="$i18n{naturalScrollLearnMoreLink}" target="_blank"
                   on-click="onLearnMoreLinkActivated_"
                   on-keydown="onLearnMoreLinkActivated_">
                 $i18n{naturalScrollLearnMore}
               </a>
-            </paper-radio-button>
+            </cr-radio-button>
           </settings-radio-group>
         </div>
       </div>
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index a68afd0..590edea 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
@@ -43,8 +44,8 @@
         display: block;
       }
 
-      paper-radio-button {
-        --paper-radio-button-label: {
+      cr-radio-button {
+        --cr-radio-button-label: {
           display: flex;
           line-height: 154%;  /* Apply 20px line-height to paper radio button
                                  text to match rest of settings line-heights. */
@@ -94,14 +95,13 @@
           <div class="list-frame" >
             <paper-radio-group id="unlockType"
                 disabled$="[[quickUnlockDisabledByPolicy_]]"
-                selected="{{selectedUnlockType}}">
-              <paper-radio-button name="password" class="list-item underbar">
+                selected="{{selectedUnlockType}}" selectable="cr-radio-button">
+              <cr-radio-button name="password" class="list-item underbar">
                 <div class="start">
                   $i18n{lockScreenPasswordOnly}
                 </div>
-              </paper-radio-button>
-              <paper-radio-button name="pin+password"
-                  class="list-item">
+              </cr-radio-button>
+              <cr-radio-button name="pin+password" class="list-item">
                 <div id="pinPasswordDiv" class="start">
                   $i18n{lockScreenPinOrPassword}
                 </div>
@@ -116,7 +116,7 @@
                     </paper-button>
                   </div>
                 </template>
-              </paper-radio-button>
+              </cr-radio-button>
             </paper-radio-group>
           </div>
         </div>
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index e3a196f..f1dd27a3 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -5,12 +5,12 @@
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
 <link rel="import" href="sync_browser_proxy.html">
 <link rel="import" href="../privacy_page/personalization_options.html">
@@ -373,13 +373,14 @@
             <paper-radio-group disabled$="[[syncPrefs.encryptAllData]]"
                 selected="[[selectedEncryptionRadio_(
                     syncPrefs.passphraseTypeIsCustom)]]"
+                selectable="cr-radio-button"
                 on-paper-radio-group-changed=
                     "onEncryptionRadioSelectionChanged_">
-              <paper-radio-button name="encrypt-with-google"
+              <cr-radio-button name="encrypt-with-google"
                   class="list-item" disabled="[[syncPrefs.encryptAllData]]">
                 $i18n{encryptWithGoogleCredentialsLabel}
-              </paper-radio-button>
-              <paper-radio-button name="encrypt-with-passphrase"
+              </cr-radio-button>
+              <cr-radio-button name="encrypt-with-passphrase"
                   class="list-item" disabled="[[syncPrefs.encryptAllData]]">
                 <template is="dom-if" if="[[syncPrefs.fullEncryptionBody]]">
                   <span>[[syncPrefs.fullEncryptionBody]]</span>
@@ -389,7 +390,7 @@
                     $i18nRaw{encryptWithSyncPassphraseLabel}
                   </span>
                 </template>
-              </paper-radio-button>
+              </cr-radio-button>
             </paper-radio-group>
             <div id="reset-sync-message-box" class="list-item"
                 hidden="[[!syncPrefs.encryptAllData]]">
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index 06bf219..a47b3fa 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -105,24 +105,15 @@
         color: var(--google-blue-500);
       }
 
-      controlled-radio-button,
-      paper-radio-button {
-        --paper-radio-button-checked-color: var(--google-blue-500);
-        --paper-radio-button-label-spacing: 22px;
-        --paper-radio-button-radio-container: {
-          flex-shrink: 0;
-        };
-        --paper-radio-button-unchecked-color: var(--paper-grey-600);
-        -webkit-margin-start: 2px;
-        align-items: center;
-        display: flex;
-        min-height: var(--settings-row-min-height);
-      }
-
       paper-radio-group {
         width: 100%;
       }
 
+      paper-radio-group:focus {
+        background-color: var(--google-grey-300);
+        outline: none;
+      }
+
       /* See also: .no-min-width below. */
       .text-elide {
         @apply --cr-text-elide;
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html
index 5e9062e..e914c74 100644
--- a/chrome/browser/resources/settings/settings_vars_css.html
+++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -53,9 +53,6 @@
     --iron-icon-height: var(--cr-icon-size);
     --iron-icon-width: var(--cr-icon-size);
 
-    --paper-radio-button-ink-size: 40px;
-    --paper-radio-button-label-color: inherit;
-    --paper-radio-button-size: 16px;
     --paper-radio-group-item-padding: 0;
 
     --paper-tabs-selection-bar-color: var(--paper-blue-500);
diff --git a/chrome/browser/site_per_process_interactive_browsertest.cc b/chrome/browser/site_per_process_interactive_browsertest.cc
index 2e2de26a..0c3dcd5 100644
--- a/chrome/browser/site_per_process_interactive_browsertest.cc
+++ b/chrome/browser/site_per_process_interactive_browsertest.cc
@@ -224,7 +224,7 @@
   // take time to propagate to the renderer's main thread.
   content::DOMMessageQueue msg_queue;
   std::string reply;
-  SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('f'),
+  SimulateKeyPress(web_contents, ui::DomKey::FromCharacter('F'),
                    ui::DomCode::US_F, ui::VKEY_F, false, false, false, false);
   EXPECT_TRUE(msg_queue.WaitForMessage(&reply));
   EXPECT_EQ("\"F\"", reply);
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index c7df2e0..30f87332 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -103,6 +103,7 @@
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
@@ -785,36 +786,6 @@
     EXPECT_TRUE(pref_service->IsManagedPreference(pref_name));
   }
 
-  // Sets the policy identified by |policy_name| to the value specified by
-  // |list_values|, ensuring that the corresponding list pref |pref_name| is
-  // updated to match. |policy_name| must specify a policy that is a list of
-  // string values.
-  void ConfigureStringListPolicy(PrefService* pref_service,
-                                 const char* policy_name,
-                                 const char* pref_name,
-                                 const std::vector<std::string>& list_values) {
-    std::unique_ptr<base::ListValue> policy_value =
-        std::make_unique<base::ListValue>();
-    for (const auto& value : list_values) {
-      policy_value->GetList().emplace_back(value);
-    }
-    policy::PolicyMap policy_map;
-    policy_map.Set(policy_name, policy::POLICY_LEVEL_MANDATORY,
-                   policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_CLOUD,
-                   std::move(policy_value), nullptr);
-
-    EXPECT_NO_FATAL_FAILURE(UpdateChromePolicy(policy_map));
-
-    const base::ListValue* pref_value = pref_service->GetList(pref_name);
-    ASSERT_TRUE(pref_value);
-    std::vector<std::string> pref_values;
-    for (const auto& value : pref_value->GetList()) {
-      ASSERT_TRUE(value.is_string());
-      pref_values.push_back(value.GetString());
-    }
-    EXPECT_THAT(pref_values, testing::UnorderedElementsAreArray(list_values));
-  }
-
   // Checks that the SSLConfig associated with the net::URLRequestContext
   // of the |context_getter| has the SSLConfig member identified by |member|
   // set to |expected|. This is sequenced such that any changes to prefs
@@ -949,8 +920,10 @@
     policy_provider_.UpdateChromePolicy(policies);
     ASSERT_TRUE(base::MessageLoopCurrent::Get());
 
-    base::RunLoop loop;
-    loop.RunUntilIdle();
+    base::RunLoop().RunUntilIdle();
+
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+      content::FlushNetworkServiceInstanceForTesting();
   }
 
   void RunOnIOThreadBlocking(base::OnceClosure task) {
@@ -1983,38 +1956,137 @@
       CheckSSLConfig(browser()->profile()->GetRequestContext(), member, true));
 }
 
-IN_PROC_BROWSER_TEST_P(SSLUITest,
-                       CertificateTransparencyEnforcementDisabledForUrls) {
-  bool require = true;
-  net::TransportSecurityState::SetShouldRequireCTForTesting(&require);
+class CertificateTransparencySSLUITest : public CertVerifierBrowserTest {
+ public:
+  CertificateTransparencySSLUITest()
+      : CertVerifierBrowserTest(),
+        https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+  ~CertificateTransparencySSLUITest() override {}
 
-  scoped_refptr<net::X509Certificate> cert = https_server_.GetCertificate();
-  net::HashValueVector hashes;
-  hashes.push_back(GetSPKIHash(cert->cert_buffer()));
-  std::vector<std::string> disabled_urls{"www.google.com"};
+  void SetUpOnMainThread() override {
+    CertVerifierBrowserTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+    https_server_.AddDefaultHandlers(base::FilePath(kDocRoot));
+  }
 
-  // Make sure that CT is required without the policy set.
-  ASSERT_NO_FATAL_FAILURE(CheckCTStatus(
-      browser()->profile()->GetRequestContext(), disabled_urls.front(), cert,
-      true, hashes, net::ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
-      net::TransportSecurityState::CTRequirementsStatus::
-          CT_REQUIREMENTS_NOT_MET));
-  ASSERT_NO_FATAL_FAILURE(CheckCTStatus(
-      browser()->profile()->GetRequestContext(), disabled_urls.front(), cert,
-      true, hashes, net::ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
-      net::TransportSecurityState::CTRequirementsStatus::CT_REQUIREMENTS_MET));
+  void SetUp() override {
+    EXPECT_CALL(policy_provider_, IsInitializationComplete(testing::_))
+        .WillRepeatedly(testing::Return(true));
+    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
+        &policy_provider_);
 
-  // Configure the policy.
+    CertVerifierBrowserTest::SetUp();
+  }
+
+  // Sets the policy identified by |policy_name| to the value specified by
+  // |list_values|, ensuring that the corresponding list pref |pref_name| is
+  // updated to match. |policy_name| must specify a policy that is a list of
+  // string values.
+  void ConfigureStringListPolicy(PrefService* pref_service,
+                                 const char* policy_name,
+                                 const char* pref_name,
+                                 const std::vector<std::string>& list_values) {
+    std::unique_ptr<base::ListValue> policy_value =
+        std::make_unique<base::ListValue>();
+    for (const auto& value : list_values) {
+      policy_value->GetList().emplace_back(value);
+    }
+    policy::PolicyMap policy_map;
+    policy_map.Set(policy_name, policy::POLICY_LEVEL_MANDATORY,
+                   policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_CLOUD,
+                   std::move(policy_value), nullptr);
+
+    EXPECT_NO_FATAL_FAILURE(UpdateChromePolicy(policy_map));
+
+    const base::ListValue* pref_value = pref_service->GetList(pref_name);
+    ASSERT_TRUE(pref_value);
+    std::vector<std::string> pref_values;
+    for (const auto& value : pref_value->GetList()) {
+      ASSERT_TRUE(value.is_string());
+      pref_values.push_back(value.GetString());
+    }
+    EXPECT_THAT(pref_values, testing::UnorderedElementsAreArray(list_values));
+  }
+
+  net::EmbeddedTestServer* https_server() { return &https_server_; }
+
+ private:
+  void UpdateChromePolicy(const policy::PolicyMap& policies) {
+    policy_provider_.UpdateChromePolicy(policies);
+    ASSERT_TRUE(base::MessageLoopCurrent::Get());
+
+    base::RunLoop().RunUntilIdle();
+
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService))
+      content::FlushNetworkServiceInstanceForTesting();
+  }
+
+  net::EmbeddedTestServer https_server_;
+
+  policy::MockConfigurationPolicyProvider policy_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(CertificateTransparencySSLUITest);
+};
+
+// Visit an HTTPS page that has a publicly trusted certificate issued after
+// the Certificate Transparency requirement date of April 2018. The connection
+// should be blocked, as the server will not be providing CT details, and the
+// Chrome CT Policy should be being enforced.
+IN_PROC_BROWSER_TEST_F(CertificateTransparencySSLUITest,
+                       EnforcedAfterApril2018) {
+  ASSERT_TRUE(https_server()->Start());
+
+  net::CertVerifyResult verify_result;
+  verify_result.verified_cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "may_2018.pem");
+  ASSERT_TRUE(verify_result.verified_cert);
+  verify_result.is_issued_by_known_root = true;
+  verify_result.public_key_hashes.push_back(
+      GetSPKIHash(verify_result.verified_cert->cert_buffer()));
+
+  mock_cert_verifier()->AddResultForCert(https_server()->GetCertificate().get(),
+                                         verify_result, net::OK);
+
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server()->GetURL("/ssl/google.html"));
+
+  CheckSecurityState(browser()->tab_strip_model()->GetActiveWebContents(),
+                     net::CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED,
+                     security_state::DANGEROUS,
+                     AuthState::SHOWING_INTERSTITIAL);
+}
+
+// Visit an HTTPS page that has a publicly trusted certificate issued after
+// the Certificate Transparency requirement date of April 2018. The connection
+// would normally be blocked, as the server will not be providing CT details,
+// and the Chrome CT Policy should be being enforced; however, because a policy
+// configuration exists that disables CT enforcement for that cert, the
+// connection should succeed.
+IN_PROC_BROWSER_TEST_F(CertificateTransparencySSLUITest,
+                       EnforcedAfterApril2018UnlessPoliciesSet) {
+  ASSERT_TRUE(https_server()->Start());
+
+  net::CertVerifyResult verify_result;
+  verify_result.verified_cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "may_2018.pem");
+  ASSERT_TRUE(verify_result.verified_cert);
+  verify_result.is_issued_by_known_root = true;
+  verify_result.public_key_hashes.push_back(
+      GetSPKIHash(verify_result.verified_cert->cert_buffer()));
+
+  mock_cert_verifier()->AddResultForCert(https_server()->GetCertificate().get(),
+                                         verify_result, net::OK);
+
   ASSERT_NO_FATAL_FAILURE(ConfigureStringListPolicy(
       browser()->profile()->GetPrefs(),
-      policy::key::kCertificateTransparencyEnforcementDisabledForUrls,
-      certificate_transparency::prefs::kCTExcludedHosts, disabled_urls));
+      policy::key::kCertificateTransparencyEnforcementDisabledForCas,
+      certificate_transparency::prefs::kCTExcludedSPKIs,
+      {verify_result.public_key_hashes.back().ToString()}));
 
-  // Make sure CT is now explicitly disabled.
-  ASSERT_NO_FATAL_FAILURE(CheckCTStatus(
-      browser()->profile()->GetRequestContext(), disabled_urls.front(), cert,
-      true, hashes, net::ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
-      net::TransportSecurityState::CTRequirementsStatus::CT_NOT_REQUIRED));
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server()->GetURL("/ssl/google.html"));
+  CheckSecurityState(browser()->tab_strip_model()->GetActiveWebContents(),
+                     CertError::NONE, security_state::SECURE, AuthState::NONE);
 }
 
 // Visit a HTTP page which request WSS connection to a server providing invalid
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc
index ea91650..3bfaa5ad 100644
--- a/chrome/browser/sync/sync_ui_util.cc
+++ b/chrome/browser/sync/sync_ui_util.cc
@@ -120,7 +120,7 @@
   // Unrecoverable error is sometimes accompanied by actionable error.
   // If status message is set display that message, otherwise show generic
   // unrecoverable error message.
-  ProfileSyncService::Status status;
+  syncer::SyncStatus status;
   service->QueryDetailedSyncStatus(&status);
   GetStatusForActionableError(status.sync_protocol_error, status_label,
                               link_label, action_type);
@@ -238,7 +238,7 @@
       }
 
       // We don't have an auth error. Check for an actionable error.
-      ProfileSyncService::Status status;
+      syncer::SyncStatus status;
       service->QueryDetailedSyncStatus(&status);
       if (status_label && link_label) {
         GetStatusForActionableError(status.sync_protocol_error, status_label,
@@ -284,7 +284,7 @@
     // or provide a link to continue with setup.
     if (service->IsFirstSetupInProgress()) {
       result_type = PRE_SYNCED;
-      ProfileSyncService::Status status;
+      syncer::SyncStatus status;
       service->QueryDetailedSyncStatus(&status);
       AuthError auth_error =
           SigninErrorControllerFactory::GetForProfile(profile)->auth_error();
@@ -364,7 +364,7 @@
     // An unrecoverable error is sometimes accompanied by an actionable error.
     // If an actionable error is not set to be UPGRADE_CLIENT, then show a
     // generic unrecoverable error message.
-    ProfileSyncService::Status status;
+    syncer::SyncStatus status;
     service->QueryDetailedSyncStatus(&status);
     if (status.sync_protocol_error.action != syncer::UPGRADE_CLIENT) {
       // Display different messages and buttons for managed accounts.
@@ -404,7 +404,7 @@
   // Check for sync errors if the sync service is enabled.
   if (service) {
     // Check for an actionable UPGRADE_CLIENT error.
-    ProfileSyncService::Status status;
+    syncer::SyncStatus status;
     service->QueryDetailedSyncStatus(&status);
     if (status.sync_protocol_error.action == syncer::UPGRADE_CLIENT) {
       *content_string_id = IDS_SYNC_ERROR_USER_MENU_UPGRADE_MESSAGE;
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index bafe409..4260443 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -524,7 +524,7 @@
   os << profile_debug_name_ << ": " << message << ": ";
   if (service()) {
     const SyncCycleSnapshot& snap = GetLastCycleSnapshot();
-    ProfileSyncService::Status status;
+    syncer::SyncStatus status;
     service()->QueryDetailedSyncStatus(&status);
     // Capture select info from the sync session snapshot and syncer status.
     os << ", has_unsynced_items: " << snap.has_remaining_local_changes()
diff --git a/chrome/browser/sync/test/integration/sync_errors_test.cc b/chrome/browser/sync/test/integration/sync_errors_test.cc
index fa7ae5d1..fabd3d4 100644
--- a/chrome/browser/sync/test/integration/sync_errors_test.cc
+++ b/chrome/browser/sync/test/integration/sync_errors_test.cc
@@ -86,7 +86,7 @@
   // Checks if an actionable error has been hit. Called repeatedly each time PSS
   // notifies observers of a state change.
   bool IsExitConditionSatisfied() override {
-    ProfileSyncService::Status status;
+    syncer::SyncStatus status;
     service()->QueryDetailedSyncStatus(&status);
     return (status.sync_protocol_error.action != syncer::UNKNOWN_ACTION &&
             service()->HasUnrecoverableError());
@@ -137,7 +137,7 @@
   // Wait until an actionable error is encountered.
   ASSERT_TRUE(ActionableErrorChecker(GetSyncService(0)).Wait());
 
-  ProfileSyncService::Status status;
+  syncer::SyncStatus status;
   GetSyncService(0)->QueryDetailedSyncStatus(&status);
   ASSERT_EQ(status.sync_protocol_error.error_type, syncer::TRANSIENT_ERROR);
   ASSERT_EQ(status.sync_protocol_error.action, syncer::UPGRADE_CLIENT);
@@ -198,7 +198,7 @@
   const BookmarkNode* node2 = AddFolder(0, 0, "title2");
   SetTitle(0, node2, "new_title2");
   ASSERT_TRUE(SyncDisabledChecker(GetSyncService(0)).Wait());
-  ProfileSyncService::Status status;
+  syncer::SyncStatus status;
   GetSyncService(0)->QueryDetailedSyncStatus(&status);
   ASSERT_EQ(status.sync_protocol_error.error_type, syncer::NOT_MY_BIRTHDAY);
   ASSERT_EQ(status.sync_protocol_error.action, syncer::DISABLE_SYNC_ON_CLIENT);
@@ -219,7 +219,7 @@
   std::string url = "www.google.com";
 
   // Remember cache_guid before actionable error.
-  ProfileSyncService::Status status;
+  syncer::SyncStatus status;
   GetSyncService(0)->QueryDetailedSyncStatus(&status);
   std::string old_cache_guid = status.sync_id;
 
diff --git a/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc b/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
index 01d4d72..39ff5f80 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_installer_view.cc
@@ -134,94 +134,6 @@
   return gfx::Size(kDialogWidth, height);
 }
 
-// static
-CrostiniInstallerView* CrostiniInstallerView::GetActiveViewForTesting() {
-  return g_crostini_installer_view;
-}
-
-CrostiniInstallerView::CrostiniInstallerView(Profile* profile)
-    : app_name_(base::ASCIIToUTF16(kCrostiniTerminalAppName)),
-      profile_(profile),
-      weak_ptr_factory_(this) {
-
-  views::LayoutProvider* provider = views::LayoutProvider::Get();
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::kVertical,
-      provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG),
-      provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)));
-  set_margins(provider->GetDialogInsetsForContentType(
-      views::DialogContentType::TEXT, views::DialogContentType::TEXT));
-
-  // TODO(timloh): Descenders in the message appear to be clipped, re-visit once
-  // the UI has been fleshed out more.
-  const base::string16 device_type = ui::GetChromeOSDeviceName();
-  const base::string16 message = l10n_util::GetStringFUTF16(
-      IDS_CROSTINI_INSTALLER_BODY, device_type, app_name_,
-      ui::FormatBytesWithUnits(kDownloadSizeInBytes, ui::DATA_UNITS_MEBIBYTE,
-                               /*show_units=*/true));
-  message_label_ = new views::Label(message);
-  message_label_->SetMultiLine(true);
-  message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  AddChildView(message_label_);
-
-  chrome::RecordDialogCreation(chrome::DialogIdentifier::CROSTINI_INSTALLER);
-}
-
-CrostiniInstallerView::~CrostiniInstallerView() {
-  g_crostini_installer_view = nullptr;
-}
-
-void CrostiniInstallerView::StepProgress() {
-  if (State::INSTALL_START <= state_ && state_ < State::INSTALL_END) {
-    // Setting value to -1 makes the progress bar play the
-    // "indeterminate animation".
-    progress_bar_->SetValue(-1);
-  }
-  SetMessageLabel();
-  DialogModelChanged();
-  GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
-}
-
-void CrostiniInstallerView::HandleError(const base::string16& error_message,
-                                        SetupResult result) {
-  // Only ever set the error once. This check is necessary as the
-  // CrostiniManager can give multiple error callbacks. Only the first should be
-  // shown to the user.
-  if (state_ == State::ERROR)
-    return;
-
-  RecordSetupResultHistogram(result);
-  state_ = State::ERROR;
-  message_label_->SetVisible(true);
-  message_label_->SetText(error_message);
-  progress_bar_->SetVisible(false);
-  GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
-  GetWidget()->UpdateWindowTitle();
-}
-
-void CrostiniInstallerView::SetMessageLabel() {
-  int message_id = 0;
-  // The States below refer to stages that have completed.
-  // The messages selected refer to the next stage, now underway.
-  if (state_ == State::INSTALL_START) {
-    message_id = IDS_CROSTINI_INSTALLER_LOAD_TERMINA_MESSAGE;
-  } else if (state_ == State::INSTALL_IMAGE_LOADER) {
-    message_id = IDS_CROSTINI_INSTALLER_START_CONCIERGE_MESSAGE;
-  } else if (state_ == State::START_CONCIERGE) {
-    message_id = IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_MESSAGE;
-  } else if (state_ == State::CREATE_DISK_IMAGE) {
-    message_id = IDS_CROSTINI_INSTALLER_START_TERMINA_VM_MESSAGE;
-  } else if (state_ == State::START_TERMINA_VM) {
-    message_id = IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE;
-  }
-  if (message_id != 0) {
-    message_label_->SetText(l10n_util::GetStringUTF16(message_id));
-    message_label_->SetVisible(true);
-  } else {
-    message_label_->SetVisible(false);
-  }
-}
-
 void CrostiniInstallerView::OnComponentLoaded(ConciergeClientResult result) {
   DCHECK_EQ(state_, State::INSTALL_START);
   state_ = State::INSTALL_IMAGE_LOADER;
@@ -281,6 +193,59 @@
   StepProgress();
 }
 
+// static
+CrostiniInstallerView* CrostiniInstallerView::GetActiveViewForTesting() {
+  return g_crostini_installer_view;
+}
+
+CrostiniInstallerView::CrostiniInstallerView(Profile* profile)
+    : app_name_(base::ASCIIToUTF16(kCrostiniTerminalAppName)),
+      profile_(profile),
+      weak_ptr_factory_(this) {
+  views::LayoutProvider* provider = views::LayoutProvider::Get();
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::kVertical,
+      provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG),
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)));
+  set_margins(provider->GetDialogInsetsForContentType(
+      views::DialogContentType::TEXT, views::DialogContentType::TEXT));
+
+  // TODO(timloh): Descenders in the message appear to be clipped, re-visit once
+  // the UI has been fleshed out more.
+  const base::string16 device_type = ui::GetChromeOSDeviceName();
+  const base::string16 message = l10n_util::GetStringFUTF16(
+      IDS_CROSTINI_INSTALLER_BODY, device_type, app_name_,
+      ui::FormatBytesWithUnits(kDownloadSizeInBytes, ui::DATA_UNITS_MEBIBYTE,
+                               /*show_units=*/true));
+  message_label_ = new views::Label(message);
+  message_label_->SetMultiLine(true);
+  message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  AddChildView(message_label_);
+
+  chrome::RecordDialogCreation(chrome::DialogIdentifier::CROSTINI_INSTALLER);
+}
+
+CrostiniInstallerView::~CrostiniInstallerView() {
+  g_crostini_installer_view = nullptr;
+}
+
+void CrostiniInstallerView::HandleError(const base::string16& error_message,
+                                        SetupResult result) {
+  // Only ever set the error once. This check is necessary as the
+  // CrostiniManager can give multiple error callbacks. Only the first should be
+  // shown to the user.
+  if (state_ == State::ERROR)
+    return;
+
+  RecordSetupResultHistogram(result);
+  state_ = State::ERROR;
+  message_label_->SetVisible(true);
+  message_label_->SetText(error_message);
+  progress_bar_->SetVisible(false);
+  GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
+  GetWidget()->UpdateWindowTitle();
+}
+
 void CrostiniInstallerView::StartContainerFinished(
     ConciergeClientResult result) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -309,6 +274,40 @@
   GetWidget()->Close();
 }
 
+void CrostiniInstallerView::StepProgress() {
+  if (State::INSTALL_START <= state_ && state_ < State::INSTALL_END) {
+    // Setting value to -1 makes the progress bar play the
+    // "indeterminate animation".
+    progress_bar_->SetValue(-1);
+  }
+  SetMessageLabel();
+  DialogModelChanged();
+  GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
+}
+
+void CrostiniInstallerView::SetMessageLabel() {
+  int message_id = 0;
+  // The States below refer to stages that have completed.
+  // The messages selected refer to the next stage, now underway.
+  if (state_ == State::INSTALL_START) {
+    message_id = IDS_CROSTINI_INSTALLER_LOAD_TERMINA_MESSAGE;
+  } else if (state_ == State::INSTALL_IMAGE_LOADER) {
+    message_id = IDS_CROSTINI_INSTALLER_START_CONCIERGE_MESSAGE;
+  } else if (state_ == State::START_CONCIERGE) {
+    message_id = IDS_CROSTINI_INSTALLER_CREATE_DISK_IMAGE_MESSAGE;
+  } else if (state_ == State::CREATE_DISK_IMAGE) {
+    message_id = IDS_CROSTINI_INSTALLER_START_TERMINA_VM_MESSAGE;
+  } else if (state_ == State::START_TERMINA_VM) {
+    message_id = IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE;
+  }
+  if (message_id != 0) {
+    message_label_->SetText(l10n_util::GetStringUTF16(message_id));
+    message_label_->SetVisible(true);
+  } else {
+    message_label_->SetVisible(false);
+  }
+}
+
 void CrostiniInstallerView::RecordSetupResultHistogram(SetupResult result) {
   // Prevent multiple results being logged for a given setup flow. This can
   // happen due to multiple error callbacks happening in some cases, as well as
diff --git a/chrome/browser/ui/avatar_button_error_controller.cc b/chrome/browser/ui/avatar_button_error_controller.cc
index 59697f91..ae7d034a 100644
--- a/chrome/browser/ui/avatar_button_error_controller.cc
+++ b/chrome/browser/ui/avatar_button_error_controller.cc
@@ -90,7 +90,7 @@
   if (sync_service) {
     SyncErrorController* sync_error_controller =
         sync_service->sync_error_controller();
-    browser_sync::ProfileSyncService::Status status;
+    syncer::SyncStatus status;
     sync_service->QueryDetailedSyncStatus(&status);
     return sync_service->HasUnrecoverableError() ||
            status.sync_protocol_error.action == syncer::UPGRADE_CLIENT ||
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.cc b/chrome/browser/ui/input_method/input_method_engine_base.cc
index abd3f75a..91de5a4 100644
--- a/chrome/browser/ui/input_method/input_method_engine_base.cc
+++ b/chrome/browser/ui/input_method/input_method_engine_base.cc
@@ -308,7 +308,7 @@
 
   observer_->OnFocus(ui::IMEEngineHandlerInterface::InputContext(
       context_id_, input_context.type, input_context.mode, input_context.flags,
-      input_context.focus_reason));
+      input_context.focus_reason, input_context.should_do_learning));
 }
 
 void InputMethodEngineBase::FocusOut() {
diff --git a/chrome/browser/ui/input_method/input_method_engine_unittest.cc b/chrome/browser/ui/input_method/input_method_engine_unittest.cc
index 42d0bbe..7e37d9d 100644
--- a/chrome/browser/ui/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/ui/input_method/input_method_engine_unittest.cc
@@ -172,7 +172,8 @@
   void FocusIn(ui::TextInputType input_type) {
     ui::IMEEngineHandlerInterface::InputContext input_context(
         input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE,
-        ui::TextInputClient::FOCUS_REASON_OTHER);
+        ui::TextInputClient::FOCUS_REASON_OTHER,
+        false /* should_do_learning */);
     engine_->FocusIn(input_context);
     ui::IMEBridge::Get()->SetCurrentInputContext(input_context);
   }
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
index 1c04fa2..eaed822 100644
--- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
+++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
@@ -176,6 +176,12 @@
   return base::EmptyString();
 }
 
+bool RemoteTextInputClient::ShouldDoLearning() {
+  // TODO(https://crbug.com/311180): Implement this method.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return false;
+}
+
 ui::EventDispatchDetails RemoteTextInputClient::DispatchKeyEventPostIME(
     ui::KeyEvent* event) {
   remote_client_->DispatchKeyEventPostIME(ui::Event::Clone(*event),
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
index 63b1b9cf..704c17ee 100644
--- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
+++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
@@ -58,6 +58,7 @@
   bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
   void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override;
   const std::string& GetClientSourceInfo() const override;
+  bool ShouldDoLearning() override;
 
   // ui::internal::InputMethodDelegate:
   ui::EventDispatchDetails DispatchKeyEventPostIME(
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 52eaba4..51d2a74 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -139,16 +139,32 @@
                                      kRichImageCornerRadius, flags);
 }
 
-}  // namespace
-
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxImageView:
 
 class OmniboxImageView : public views::ImageView {
  public:
+  OmniboxImageView() = default;
+
   bool CanProcessEventsWithinSubtree() const override { return false; }
+
+ private:
+  // views::ImageView:
+  void OnPaint(gfx::Canvas* canvas) override;
+
+  DISALLOW_COPY_AND_ASSIGN(OmniboxImageView);
 };
 
+void OmniboxImageView::OnPaint(gfx::Canvas* canvas) {
+  gfx::Path mask;
+  mask.addRoundRect(gfx::RectToSkRect(GetImageBounds()), kRichImageCornerRadius,
+                    kRichImageCornerRadius);
+  canvas->ClipPath(mask, true);
+  ImageView::OnPaint(canvas);
+}
+
+}  // namespace
+
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxMatchCellView:
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 7461c8a..2f51073 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -387,6 +387,10 @@
   scoped_observer_.RemoveAll();
 }
 
+bool OmniboxViewViews::ShouldDoLearning() {
+  return location_bar_view_ && !location_bar_view_->profile()->IsOffTheRecord();
+}
+
 void OmniboxViewViews::SetTextAndSelectedRange(const base::string16& text,
                                                const gfx::Range& range) {
   SetText(text);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index ff49173..2270f53 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -107,6 +107,7 @@
   ui::TextInputType GetTextInputType() const override;
   void AddedToWidget() override;
   void RemovedFromWidget() override;
+  bool ShouldDoLearning() override;
 
  protected:
   // For testing only.
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.cc b/chrome/browser/ui/views/tabs/tab_renderer_data.cc
index a6059d2c..2f71a9b 100644
--- a/chrome/browser/ui/views/tabs/tab_renderer_data.cc
+++ b/chrome/browser/ui/views/tabs/tab_renderer_data.cc
@@ -17,7 +17,7 @@
 
 TabRendererData::~TabRendererData() = default;
 
-bool TabRendererData::operator==(const TabRendererData& other) {
+bool TabRendererData::operator==(const TabRendererData& other) const {
   return favicon.BackedBySameObjectAs(other.favicon) &&
          network_state == other.network_state && title == other.title &&
          url == other.url && crashed_status == other.crashed_status &&
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.h b/chrome/browser/ui/views/tabs/tab_renderer_data.h
index 8edd33c..605dc26 100644
--- a/chrome/browser/ui/views/tabs/tab_renderer_data.h
+++ b/chrome/browser/ui/views/tabs/tab_renderer_data.h
@@ -22,7 +22,7 @@
   TabRendererData& operator=(const TabRendererData& other);
   TabRendererData& operator=(TabRendererData&& other);
 
-  bool operator==(const TabRendererData& other);
+  bool operator==(const TabRendererData& other) const;
 
   // This interprets the crashed status to decide whether or not this
   // render data represents a tab that is "crashed" (i.e. the render
diff --git a/chrome/common/extensions/api/input_ime.json b/chrome/common/extensions/api/input_ime.json
index 5a9ced36..0aab48d 100644
--- a/chrome/common/extensions/api/input_ime.json
+++ b/chrome/common/extensions/api/input_ime.json
@@ -44,7 +44,8 @@
           "type": {"$ref": "InputContextType", "description": "Type of value this text field edits, (Text, Number, URL, etc)"},
           "autoCorrect": {"type": "boolean", "description": "Whether the text field wants auto-correct."},
           "autoComplete": {"type": "boolean", "description": "Whether the text field wants auto-complete."},
-          "spellCheck": {"type": "boolean", "description": "Whether the text field wants spell-check."}
+          "spellCheck": {"type": "boolean", "description": "Whether the text field wants spell-check."},
+          "shouldDoLearning": {"type": "boolean", "description": "Whether text entered into the text field should be used to improve typing suggestions for the user."}
         }
       },
       {
diff --git a/chrome/common/extensions/api/input_method_private.json b/chrome/common/extensions/api/input_method_private.json
index 79ce1ff..a123ab6 100644
--- a/chrome/common/extensions/api/input_method_private.json
+++ b/chrome/common/extensions/api/input_method_private.json
@@ -55,6 +55,7 @@
           "autoCorrect": {"type": "boolean", "description": "Whether the text field wants auto-correct."},
           "autoComplete": {"type": "boolean", "description": "Whether the text field wants auto-complete."},
           "spellCheck": {"type": "boolean", "description": "Whether the text field wants spell-check."},
+          "shouldDoLearning": {"type": "boolean", "description": "Whether text entered into the text field should be used to improve typing suggestions for the user."},
           "focusReason": {"$ref": "FocusReason", "description": "How the text field was focused"}
         }
       }
diff --git a/chrome/common/media_router/providers/cast/cast_media_source.cc b/chrome/common/media_router/providers/cast/cast_media_source.cc
index aeb49d5..06f0047 100644
--- a/chrome/common/media_router/providers/cast/cast_media_source.cc
+++ b/chrome/common/media_router/providers/cast/cast_media_source.cc
@@ -12,6 +12,8 @@
 #include "url/gurl.h"
 #include "url/url_util.h"
 
+using cast_channel::BroadcastRequest;
+
 namespace media_router {
 
 namespace {
@@ -76,6 +78,23 @@
 #endif
 }
 
+std::unique_ptr<CastMediaSource> CreateFromURLParams(
+    const MediaSource::Id& source_id,
+    const std::vector<CastAppInfo>& app_infos,
+    const std::string& broadcast_namespace,
+    const std::string& broadcast_message) {
+  if (app_infos.empty())
+    return nullptr;
+
+  auto cast_source = std::make_unique<CastMediaSource>(source_id, app_infos);
+  if (!broadcast_namespace.empty() && !broadcast_message.empty()) {
+    cast_source->set_broadcast_request(
+        BroadcastRequest(broadcast_namespace, broadcast_message));
+  }
+
+  return cast_source;
+}
+
 std::unique_ptr<CastMediaSource> ParseCastUrl(const MediaSource::Id& source_id,
                                               const GURL& url) {
   std::string app_id = url.path();
@@ -110,13 +129,8 @@
     }
   }
 
-  auto parsed = std::make_unique<CastMediaSource>(source_id, app_info);
-  if (!broadcast_namespace.empty() && !broadcast_message.empty()) {
-    parsed->set_broadcast_request(
-        BroadcastRequest(broadcast_namespace, broadcast_message));
-  }
-
-  return parsed;
+  return CreateFromURLParams(source_id, {app_info}, broadcast_namespace,
+                             broadcast_message);
 }
 
 std::unique_ptr<CastMediaSource> ParseLegacyCastUrl(
@@ -173,9 +187,8 @@
   if (app_infos.empty())
     return nullptr;
 
-  auto parsed =
-      std::make_unique<CastMediaSource>(source_id, std::move(app_infos));
-  return parsed;
+  return CreateFromURLParams(source_id, app_infos, broadcast_namespace,
+                             broadcast_message);
 }
 
 }  // namespace
@@ -185,11 +198,6 @@
 
 CastAppInfo::CastAppInfo(const CastAppInfo& other) = default;
 
-BroadcastRequest::BroadcastRequest(const std::string& broadcast_namespace,
-                                   const std::string& message)
-    : broadcast_namespace(broadcast_namespace), message(message) {}
-BroadcastRequest::~BroadcastRequest() = default;
-
 // static
 std::unique_ptr<CastMediaSource> CastMediaSource::From(
     const MediaSource::Id& source_id) {
@@ -240,4 +248,13 @@
       app_ids.begin(), app_ids.end(),
       [this](const std::string& app_id) { return ContainsApp(app_id); });
 }
+
+std::vector<std::string> CastMediaSource::GetAppIds() const {
+  std::vector<std::string> app_ids;
+  for (const auto& info : app_infos_)
+    app_ids.push_back(info.app_id);
+
+  return app_ids;
+}
+
 }  // namespace media_router
diff --git a/chrome/common/media_router/providers/cast/cast_media_source.h b/chrome/common/media_router/providers/cast/cast_media_source.h
index 5f52338..ae090b5e2 100644
--- a/chrome/common/media_router/providers/cast/cast_media_source.h
+++ b/chrome/common/media_router/providers/cast/cast_media_source.h
@@ -11,6 +11,7 @@
 
 #include "base/optional.h"
 #include "chrome/common/media_router/media_source.h"
+#include "components/cast_channel/cast_message_util.h"
 #include "components/cast_channel/cast_socket.h"
 
 namespace media_router {
@@ -28,17 +29,6 @@
   int required_capabilities = cast_channel::CastDeviceCapability::NONE;
 };
 
-// Represents a broadcast request. Currently it is used for precaching data
-// on a receiver.
-struct BroadcastRequest {
-  BroadcastRequest(const std::string& broadcast_namespace,
-                   const std::string& message);
-  ~BroadcastRequest();
-
-  std::string broadcast_namespace;
-  std::string message;
-};
-
 // Represents a MediaSource parsed into structured, Cast specific data. The
 // following MediaSources can be parsed into CastMediaSource:
 // - Cast Presentation URLs
@@ -60,13 +50,17 @@
   bool ContainsApp(const std::string& app_id) const;
   bool ContainsAnyAppFrom(const std::vector<std::string>& app_ids) const;
 
+  // Returns a list of App IDs in this CastMediaSource.
+  std::vector<std::string> GetAppIds() const;
+
   const MediaSource::Id& source_id() const { return source_id_; }
   const std::vector<CastAppInfo>& app_infos() const { return app_infos_; }
-  const base::Optional<BroadcastRequest>& broadcast_request() const {
+  const base::Optional<cast_channel::BroadcastRequest>& broadcast_request()
+      const {
     return broadcast_request_;
   }
 
-  void set_broadcast_request(const BroadcastRequest& request) {
+  void set_broadcast_request(const cast_channel::BroadcastRequest& request) {
     broadcast_request_ = request;
   }
 
@@ -74,7 +68,7 @@
   // TODO(imcheng): Fill in other parameters.
   MediaSource::Id source_id_;
   std::vector<CastAppInfo> app_infos_;
-  base::Optional<BroadcastRequest> broadcast_request_;
+  base::Optional<cast_channel::BroadcastRequest> broadcast_request_;
 };
 
 }  // namespace media_router
diff --git a/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc b/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
index df72aab..94a9204 100644
--- a/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
+++ b/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
@@ -10,7 +10,10 @@
 namespace media_router {
 
 TEST(CastMediaSourceTest, FromCastURL) {
-  MediaSource::Id source_id("cast:ABCDEFAB?capabilities=video_out,audio_out");
+  MediaSource::Id source_id(
+      "cast:ABCDEFAB?capabilities=video_out,audio_out"
+      "&broadcastNamespace=namespace"
+      "&broadcastMessage=message");
   std::unique_ptr<CastMediaSource> source = CastMediaSource::From(source_id);
   ASSERT_TRUE(source);
   EXPECT_EQ(source_id, source->source_id());
@@ -20,11 +23,17 @@
   EXPECT_EQ(cast_channel::CastDeviceCapability::VIDEO_OUT |
                 cast_channel::CastDeviceCapability::AUDIO_OUT,
             app_info.required_capabilities);
+  const auto& broadcast_request = source->broadcast_request();
+  ASSERT_TRUE(broadcast_request);
+  EXPECT_EQ("namespace", broadcast_request->broadcast_namespace);
+  EXPECT_EQ("message", broadcast_request->message);
 }
 
 TEST(CastMediaSourceTest, FromLegacyCastURL) {
   MediaSource::Id source_id(
-      "https://google.com/cast#__castAppId__=ABCDEFAB(video_out,audio_out)");
+      "https://google.com/cast#__castAppId__=ABCDEFAB(video_out,audio_out)"
+      "/__castBroadcastNamespace__=namespace"
+      "/__castBroadcastMessage__=message");
   std::unique_ptr<CastMediaSource> source = CastMediaSource::From(source_id);
   ASSERT_TRUE(source);
   EXPECT_EQ(source_id, source->source_id());
@@ -34,6 +43,10 @@
   EXPECT_EQ(cast_channel::CastDeviceCapability::VIDEO_OUT |
                 cast_channel::CastDeviceCapability::AUDIO_OUT,
             app_info.required_capabilities);
+  const auto& broadcast_request = source->broadcast_request();
+  ASSERT_TRUE(broadcast_request);
+  EXPECT_EQ("namespace", broadcast_request->broadcast_namespace);
+  EXPECT_EQ("message", broadcast_request->message);
 }
 
 TEST(CastMediaSourceTest, FromPresentationURL) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 38af6168..9774f08f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3118,6 +3118,7 @@
       "../browser/media/router/providers/cast/cast_app_availability_tracker_unittest.cc",
       "../browser/media/router/providers/cast/cast_app_discovery_service_unittest.cc",
       "../browser/media/router/providers/cast/cast_media_route_provider_metrics_unittest.cc",
+      "../browser/media/router/providers/cast/cast_media_route_provider_unittest.cc",
       "../browser/media/router/providers/cast/dual_media_sink_service_unittest.cc",
       "../browser/media/router/providers/dial/dial_activity_manager_unittest.cc",
       "../browser/media/router/providers/dial/dial_internal_message_util_unittest.cc",
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 30a2e9e6..cf86cf9f 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -110,34 +110,12 @@
 
 _OS_NEGATIVE_FILTER = {}
 _OS_NEGATIVE_FILTER['win'] = [
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=373
-    'RenderedWebElementTest.testHoverPersists',
-    'RenderedWebElementTest.canClickOnASuckerFishStyleMenu',
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=416
-    'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePageAfterSwitching',
-    'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePage',
 ]
 _OS_NEGATIVE_FILTER['linux'] = [
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=416
-    'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePage',
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=1148
-    'CombinedInputActionsTest.testCombiningShiftAndClickResultsInANewWindow',
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=1150
-    'BasicKeyboardInterfaceTest.testBasicKeyboardInputOnActiveElement',
 ]
 _OS_NEGATIVE_FILTER['mac'] = [
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=26
-    'AlertsTest.testAlertShouldNotAllowAdditionalCommandsIfDismissed',
-    'AlertsTest.testShouldAllowUsersToDismissAnAlertManually',
-    'FormHandlingTest.handleFormWithJavascriptAction',
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=354
-    'AlertsTest.testShouldAllowUsersToAcceptAnAlertInAFrame',
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=375
-    'PageLoadingTest.testShouldBeAbleToNavigateBackInTheBrowserHistoryInPresenceOfIframes',
     # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=416
     'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePage',
-    # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=1149
-    'ChromeDriverTests.testShouldAllowTheUserToSwitchToAnIFrameAndRemainFocusedOnIt',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1857
     'TakesScreenshotTest.testShouldCaptureScreenshot',
     'TakesScreenshotTest.testShouldCaptureScreenshotAtFramePageAfterSwitching',
diff --git a/chrome/test/data/extensions/input_ime/main.js b/chrome/test/data/extensions/input_ime/main.js
index 7162f4c..f639d5f8 100644
--- a/chrome/test/data/extensions/input_ime/main.js
+++ b/chrome/test/data/extensions/input_ime/main.js
@@ -143,7 +143,8 @@
                             context.type + ':' +
                             context.autoComplete + ':' +
                             context.autoCorrect + ':' +
-                            context.spellCheck);
+                            context.spellCheck + ':' +
+                            context.shouldDoLearning);
   },
 
   /**
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
index 9fc8334..b530845 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
@@ -350,3 +350,27 @@
 TEST_F('CrElementsCheckboxTest', 'All', function() {
   mocha.run();
 });
+
+/**
+ * @constructor
+ * @extends {CrElementsBrowserTest}
+ */
+function CrElementsRadioButtonTest() {}
+
+CrElementsRadioButtonTest.prototype = {
+  __proto__: CrElementsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload:
+      'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html',
+
+  /** @override */
+  extraLibraries: CrElementsBrowserTest.prototype.extraLibraries.concat([
+    '../settings/test_util.js',
+    'cr_radio_button_test.js',
+  ]),
+};
+
+TEST_F('CrElementsRadioButtonTest', 'All', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/cr_elements/cr_radio_button_test.js b/chrome/test/data/webui/cr_elements/cr_radio_button_test.js
new file mode 100644
index 0000000..ca1290a
--- /dev/null
+++ b/chrome/test/data/webui/cr_elements/cr_radio_button_test.js
@@ -0,0 +1,75 @@
+// 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.
+
+suite('cr-radio-button', function() {
+  let radioButton;
+
+  setup(function() {
+    PolymerTest.clearBody();
+    document.body.innerHTML = `
+      <cr-radio-button>label</cr-radio-button>
+    `;
+
+    radioButton = document.querySelector('cr-radio-button');
+  });
+
+  function assertChecked() {
+    assertTrue(radioButton.hasAttribute('checked'));
+    assertEquals('true', radioButton.getAttribute('aria-checked'));
+    assertTrue(
+        getComputedStyle(radioButton.$$('.disc')).backgroundColor !=
+        'rgba(0, 0, 0, 0)');
+  }
+
+  function assertNotChecked() {
+    assertFalse(radioButton.hasAttribute('checked'));
+    assertEquals('false', radioButton.getAttribute('aria-checked'));
+    assertEquals(
+        'rgba(0, 0, 0, 0)',
+        getComputedStyle(radioButton.$$('.disc')).backgroundColor);
+  }
+
+  function assertDisabled() {
+    assertEquals('-1', radioButton.getAttribute('tabindex'));
+    assertTrue(radioButton.hasAttribute('disabled'));
+    assertEquals('true', radioButton.getAttribute('aria-disabled'));
+    assertEquals('none', getComputedStyle(radioButton).pointerEvents);
+    assertTrue('1' != getComputedStyle(radioButton).opacity);
+  }
+
+  function assertNotDisabled() {
+    assertEquals('0', radioButton.getAttribute('tabindex'));
+    assertFalse(radioButton.hasAttribute('disabled'));
+    assertEquals('false', radioButton.getAttribute('aria-disabled'));
+    assertEquals('1', getComputedStyle(radioButton).opacity);
+  }
+
+  // Setting selection by mouse/keyboard is paper-radio-group's job, so
+  // these tests simply set states programatically and make sure the element
+  // is visually correct.
+  test('Checked', function() {
+    assertNotChecked();
+    radioButton.checked = true;
+    assertChecked();
+    radioButton.checked = false;
+    assertNotChecked();
+  });
+
+  test('Disabled', function() {
+    assertNotDisabled();
+    radioButton.disabled = true;
+    assertDisabled();
+    radioButton.disabled = false;
+    assertNotChecked();
+  });
+
+  test('Ripple', function() {
+    assertFalse(!!radioButton.$$('paper-ripple'));
+    radioButton.fire('focus');
+    assertTrue(!!radioButton.$$('paper-ripple'));
+    assertTrue(radioButton.$$('paper-ripple').holdDown);
+    radioButton.fire('pointerup');
+    assertFalse(radioButton.$$('paper-ripple').holdDown);
+  });
+});
diff --git a/chrome/test/data/webui/settings/about_page_tests.js b/chrome/test/data/webui/settings/about_page_tests.js
index 317cdfcb..c9e007d7 100644
--- a/chrome/test/data/webui/settings/about_page_tests.js
+++ b/chrome/test/data/webui/settings/about_page_tests.js
@@ -912,8 +912,7 @@
           dialog = document.createElement('settings-channel-switcher-dialog');
           document.body.appendChild(dialog);
 
-          radioButtons =
-              dialog.shadowRoot.querySelectorAll('paper-radio-button');
+          radioButtons = dialog.shadowRoot.querySelectorAll('cr-radio-button');
           assertEquals(3, radioButtons.length);
           return browserProxy.whenCalled('getChannelInfo');
         });
diff --git a/chrome/test/data/webui/settings/device_page_tests.js b/chrome/test/data/webui/settings/device_page_tests.js
index 53fbc73d..0ec0f9f 100644
--- a/chrome/test/data/webui/settings/device_page_tests.js
+++ b/chrome/test/data/webui/settings/device_page_tests.js
@@ -450,10 +450,8 @@
      * @param {boolean} expected
      */
     function expectNaturalScrollValue(pointersPage, expected) {
-      const naturalScrollOff =
-          pointersPage.$$('paper-radio-button[name="false"]');
-      const naturalScrollOn =
-          pointersPage.$$('paper-radio-button[name="true"]');
+      const naturalScrollOff = pointersPage.$$('cr-radio-button[name="false"]');
+      const naturalScrollOn = pointersPage.$$('cr-radio-button[name="true"]');
       assertTrue(!!naturalScrollOff);
       assertTrue(!!naturalScrollOn);
 
@@ -567,8 +565,7 @@
         expectNaturalScrollValue(pointersPage, false);
 
         // Tapping the link shouldn't enable the radio button.
-        const naturalScrollOn =
-            pointersPage.$$('paper-radio-button[name="true"]');
+        const naturalScrollOn = pointersPage.$$('cr-radio-button[name="true"]');
         const a = naturalScrollOn.querySelector('a');
 
         MockInteractions.tap(a);
diff --git a/chrome/test/data/webui/settings/people_page_sync_page_test.js b/chrome/test/data/webui/settings/people_page_sync_page_test.js
index 1a3f842c7..f09722a 100644
--- a/chrome/test/data/webui/settings/people_page_sync_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_sync_page_test.js
@@ -78,9 +78,9 @@
       Polymer.dom.flush();
 
       encryptWithGoogle =
-          syncPage.$$('paper-radio-button[name="encrypt-with-google"]');
+          syncPage.$$('cr-radio-button[name="encrypt-with-google"]');
       encryptWithPassphrase =
-          syncPage.$$('paper-radio-button[name="encrypt-with-passphrase"]');
+          syncPage.$$('cr-radio-button[name="encrypt-with-passphrase"]');
       assertTrue(!!encryptWithGoogle);
       assertTrue(!!encryptWithPassphrase);
     });
diff --git a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
index b35fa28..bf5a265d 100644
--- a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
@@ -177,16 +177,17 @@
       const noneRadioButton = null;
 
       /**
-       * Asserts that only the given radio button is active and all of the
-       * others are inactive.
+       * Asserts that only the given radio button is checked and all of the
+       * others are unchecked.
        * @param {Element} radioButton
        */
-      function assertRadioButtonActive(radioButton) {
+      function assertRadioButtonChecked(radioButton) {
         function doAssert(element, name) {
           if (radioButton == element)
-            assertTrue(element.active, 'Expected ' + name + ' to be active');
+            assertTrue(element.checked, 'Expected ' + name + ' to be checked');
           else
-            assertFalse(element.active, 'Expected ' + name + ' to be inactive');
+            assertFalse(
+                element.checked, 'Expected ' + name + ' to be unchecked');
         }
 
         doAssert(passwordRadioButton, 'passwordButton');
@@ -263,9 +264,9 @@
               });
 
           passwordRadioButton =
-              getFromElement('paper-radio-button[name="password"]');
+              getFromElement('cr-radio-button[name="password"]');
           pinPasswordRadioButton =
-              getFromElement('paper-radio-button[name="pin+password"]');
+              getFromElement('cr-radio-button[name="pin+password"]');
 
           done();
         });
@@ -275,7 +276,7 @@
       // quickUnlockPrivate calls.
       test('ShowingScreenDoesNotModifyPrefs', function() {
         assertTrue(getLockScreenPref());
-        assertRadioButtonActive(passwordRadioButton);
+        assertRadioButtonChecked(passwordRadioButton);
         assertDeepEquals([], quickUnlockPrivateApi.activeModes);
       });
 
@@ -301,11 +302,11 @@
       // prefs.
       test('TappingButtonsChangesUnderlyingState', function() {
         function togglePin() {
-          assertRadioButtonActive(passwordRadioButton);
+          assertRadioButtonChecked(passwordRadioButton);
 
           // Tap pin+password button.
           MockInteractions.tap(pinPasswordRadioButton);
-          assertRadioButtonActive(pinPasswordRadioButton);
+          assertRadioButtonChecked(pinPasswordRadioButton);
           assertTrue(isSetupPinButtonVisible());
           assertDeepEquals([], quickUnlockPrivateApi.activeModes);
 
@@ -314,7 +315,7 @@
 
           // Tap password button and verify quick unlock is disabled.
           MockInteractions.tap(passwordRadioButton);
-          assertRadioButtonActive(passwordRadioButton);
+          assertRadioButtonChecked(passwordRadioButton);
           assertFalse(isSetupPinButtonVisible());
           assertDeepEquals([], quickUnlockPrivateApi.activeModes);
         }
@@ -334,11 +335,11 @@
       // will update to show quick unlock is active.
       test('EnablingQuickUnlockChangesButtonState', function() {
         setActiveModes([QuickUnlockMode.PIN]);
-        assertRadioButtonActive(pinPasswordRadioButton);
+        assertRadioButtonChecked(pinPasswordRadioButton);
         assertTrue(isSetupPinButtonVisible());
 
         setActiveModes([]);
-        assertRadioButtonActive(passwordRadioButton);
+        assertRadioButtonChecked(passwordRadioButton);
         assertDeepEquals([], quickUnlockPrivateApi.activeModes);
       });
 
@@ -349,11 +350,11 @@
             0,
             fakeUma.getHistogramValue(
                 LockScreenProgress.CHOOSE_PIN_OR_PASSWORD));
-        assertRadioButtonActive(passwordRadioButton);
+        assertRadioButtonChecked(passwordRadioButton);
 
         MockInteractions.tap(pinPasswordRadioButton);
         assertTrue(isSetupPinButtonVisible());
-        assertRadioButtonActive(pinPasswordRadioButton);
+        assertRadioButtonChecked(pinPasswordRadioButton);
 
         Polymer.dom.flush();
         MockInteractions.tap(getFromElement('#setupPinButton'));
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index dcdc442..12ba117 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10677.0.0
\ No newline at end of file
+10680.0.0
\ No newline at end of file
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index b530e6ac..f6fffe7 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -518,6 +518,12 @@
   return base::EmptyString();
 }
 
+bool ArcImeService::ShouldDoLearning() {
+  // TODO(https://crbug.com/311180): Implement this method.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return true;
+}
+
 // static
 void ArcImeService::SetOverrideDefaultDeviceScaleFactorForTesting(
     base::Optional<double> scale_factor) {
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h
index feee49e..a1beae6 100644
--- a/components/arc/ime/arc_ime_service.h
+++ b/components/arc/ime/arc_ime_service.h
@@ -138,6 +138,7 @@
   void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override {
   }
   const std::string& GetClientSourceInfo() const override;
+  bool ShouldDoLearning() override;
 
   // Normally, the default device scale factor is used to convert from DPI to
   // physical pixels. This method provides a way to override it for testing.
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index c36e255..f36ce9d 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -177,7 +177,6 @@
                            public identity::IdentityManager::Observer,
                            public GaiaCookieManagerService::Observer {
  public:
-  using Status = syncer::SyncStatus;
   using PlatformSyncAllowedProvider = base::RepeatingCallback<bool()>;
   using SigninScopedDeviceIdCallback = base::RepeatingCallback<std::string()>;
 
diff --git a/components/cast_channel/cast_message_handler.cc b/components/cast_channel/cast_message_handler.cc
index b12c1b49..d9734f4 100644
--- a/components/cast_channel/cast_message_handler.cc
+++ b/components/cast_channel/cast_message_handler.cc
@@ -133,6 +133,29 @@
   SendCastMessage(socket, message);
 }
 
+void CastMessageHandler::SendBroadcastMessage(
+    int socket_id,
+    const std::vector<std::string>& app_ids,
+    const BroadcastRequest& request) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  CastSocket* socket = socket_service_->GetSocket(socket_id);
+  if (!socket) {
+    DVLOG(2) << __func__ << ": socket not found: " << socket_id;
+    return;
+  }
+
+  int request_id = NextRequestId();
+  DVLOG(2) << __func__ << ", socket_id: " << socket->id()
+           << ", request_id: " << request_id;
+
+  // Note: Even though the message is formatted like a request, we don't care
+  // about the response, as broadcasts are fire-and-forget.
+  CastMessage message =
+      CreateBroadcastRequest(sender_id_, request_id, app_ids, request);
+  SendCastMessage(socket, message);
+}
+
 void CastMessageHandler::AppAvailabilityTimedOut(int request_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(1) << __func__ << ", request_id: " << request_id;
diff --git a/components/cast_channel/cast_message_handler.h b/components/cast_channel/cast_message_handler.h
index ad775ed7..2617790c 100644
--- a/components/cast_channel/cast_message_handler.h
+++ b/components/cast_channel/cast_message_handler.h
@@ -91,6 +91,12 @@
                                       const std::string& app_id,
                                       GetAppAvailabilityCallback callback);
 
+  // Sends a broadcast message containing |app_ids| and |request| to the socket
+  // given by |socket_id|.
+  virtual void SendBroadcastMessage(int socket_id,
+                                    const std::vector<std::string>& app_ids,
+                                    const BroadcastRequest& request);
+
   const std::string& sender_id() const { return sender_id_; }
 
  private:
diff --git a/components/cast_channel/cast_message_util.cc b/components/cast_channel/cast_message_util.cc
index 0b3dc78..77a32ac6 100644
--- a/components/cast_channel/cast_message_util.cc
+++ b/components/cast_channel/cast_message_util.cc
@@ -26,6 +26,7 @@
 constexpr char kConnectionNamespace[] =
     "urn:x-cast:com.google.cast.tp.connection";
 constexpr char kReceiverNamespace[] = "urn:x-cast:com.google.cast.receiver";
+constexpr char kBroadcastNamespace[] = "urn:x-cast:com.google.cast.broadcast";
 
 // Text payload keys.
 constexpr char kTypeNodeId[] = "type";
@@ -36,6 +37,7 @@
 constexpr char kKeepAlivePongType[] = "PONG";
 constexpr char kGetAppAvailabilityRequestType[] = "GET_APP_AVAILABILITY";
 constexpr char kConnectionRequestType[] = "CONNECT";
+constexpr char kBroadcastRequestType[] = "APPLICATION_BROADCAST";
 
 // The value used for "sdkType" in a virtual connect request. Historically, this
 // value is used in the Media Router extension, but here it is reused in Chrome.
@@ -55,16 +57,20 @@
   message->set_namespace_(message_namespace);
 }
 
+void SetJSONStringPayload(CastMessage* message, const Value& payload) {
+  message->set_payload_type(
+      CastMessage::PayloadType::CastMessage_PayloadType_STRING);
+  CHECK(base::JSONWriter::Write(payload, message->mutable_payload_utf8()));
+}
+
 CastMessage CreateKeepAliveMessage(const char* keep_alive_type) {
   CastMessage output;
   FillCommonCastMessageFields(&output, kPlatformSenderId, kPlatformReceiverId,
                               kHeartbeatNamespace);
-  output.set_payload_type(
-      CastMessage::PayloadType::CastMessage_PayloadType_STRING);
 
   base::DictionaryValue type_dict;
   type_dict.SetString(kTypeNodeId, keep_alive_type);
-  CHECK(base::JSONWriter::Write(type_dict, output.mutable_payload_utf8()));
+  SetJSONStringPayload(&output, type_dict);
   return output;
 }
 
@@ -223,8 +229,6 @@
   CastMessage output;
   FillCommonCastMessageFields(&output, source_id, destination_id,
                               kConnectionNamespace);
-  output.set_payload_type(
-      CastMessage::PayloadType::CastMessage_PayloadType_STRING);
 
   // Parse system_version from user agent string. It contains platform, OS and
   // CPU info and is contained in the first set of parentheses of the user
@@ -254,7 +258,8 @@
     sender_info.SetKey("systemVersion", Value(system_version));
 
   dict.SetKey("senderInfo", std::move(sender_info));
-  CHECK(base::JSONWriter::Write(dict, output.mutable_payload_utf8()));
+
+  SetJSONStringPayload(&output, dict);
   return output;
 }
 
@@ -264,8 +269,6 @@
   CastMessage output;
   FillCommonCastMessageFields(&output, source_id, kPlatformReceiverId,
                               kReceiverNamespace);
-  output.set_payload_type(
-      CastMessage::PayloadType::CastMessage_PayloadType_STRING);
 
   Value dict(Value::Type::DICTIONARY);
   dict.SetKey(kTypeNodeId, Value(kGetAppAvailabilityRequestType));
@@ -273,7 +276,40 @@
   app_id_value.GetList().push_back(Value(app_id));
   dict.SetKey("appId", std::move(app_id_value));
   dict.SetKey(kRequestIdNodeId, Value(request_id));
-  CHECK(base::JSONWriter::Write(dict, output.mutable_payload_utf8()));
+
+  SetJSONStringPayload(&output, dict);
+  return output;
+}
+
+BroadcastRequest::BroadcastRequest(const std::string& broadcast_namespace,
+                                   const std::string& message)
+    : broadcast_namespace(broadcast_namespace), message(message) {}
+BroadcastRequest::~BroadcastRequest() = default;
+
+bool BroadcastRequest::operator==(const BroadcastRequest& other) const {
+  return broadcast_namespace == other.broadcast_namespace &&
+         message == other.message;
+}
+
+CastMessage CreateBroadcastRequest(const std::string& source_id,
+                                   int request_id,
+                                   const std::vector<std::string>& app_ids,
+                                   const BroadcastRequest& request) {
+  CastMessage output;
+  FillCommonCastMessageFields(&output, source_id, kPlatformReceiverId,
+                              kBroadcastNamespace);
+
+  Value dict(Value::Type::DICTIONARY);
+  dict.SetKey(kTypeNodeId, Value(kBroadcastRequestType));
+  std::vector<Value> app_ids_value;
+  for (const std::string& app_id : app_ids)
+    app_ids_value.push_back(Value(app_id));
+
+  dict.SetKey("appIds", Value(std::move(app_ids_value)));
+  dict.SetKey("namespace", Value(request.broadcast_namespace));
+  dict.SetKey("message", Value(request.message));
+
+  SetJSONStringPayload(&output, dict);
   return output;
 }
 
diff --git a/components/cast_channel/cast_message_util.h b/components/cast_channel/cast_message_util.h
index 4a64c59..8ec880b 100644
--- a/components/cast_channel/cast_message_util.h
+++ b/components/cast_channel/cast_message_util.h
@@ -87,6 +87,24 @@
                                             int request_id,
                                             const std::string& app_id);
 
+// Represents a broadcast request. Currently it is used for precaching data
+// on a receiver.
+struct BroadcastRequest {
+  BroadcastRequest(const std::string& broadcast_namespace,
+                   const std::string& message);
+  ~BroadcastRequest();
+  bool operator==(const BroadcastRequest& other) const;
+
+  std::string broadcast_namespace;
+  std::string message;
+};
+
+// Creates a broadcast request with the given parameters.
+CastMessage CreateBroadcastRequest(const std::string& source_id,
+                                   int request_id,
+                                   const std::vector<std::string>& app_ids,
+                                   const BroadcastRequest& request);
+
 // Possible results of a GET_APP_AVAILABILITY request.
 enum class GetAppAvailabilityResult {
   kAvailable,
diff --git a/components/cast_channel/cast_test_util.h b/components/cast_channel/cast_test_util.h
index 8781325..5448486 100644
--- a/components/cast_channel/cast_test_util.h
+++ b/components/cast_channel/cast_test_util.h
@@ -160,6 +160,11 @@
                     const std::string&,
                     GetAppAvailabilityCallback&));
 
+  MOCK_METHOD3(SendBroadcastMessage,
+               void(int,
+                    const std::vector<std::string>&,
+                    const BroadcastRequest&));
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MockCastMessageHandler);
 };
diff --git a/components/cast_channel/cast_transport.cc b/components/cast_channel/cast_transport.cc
index 8036767..4040f2f 100644
--- a/components/cast_channel/cast_transport.cc
+++ b/components/cast_channel/cast_transport.cc
@@ -88,6 +88,7 @@
     const net::CompletionCallback& callback,
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(IsCastMessageValid(message));
   std::string serialized_message;
   if (!MessageFramer::Serialize(message, &serialized_message)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/components/certificate_transparency/BUILD.gn b/components/certificate_transparency/BUILD.gn
index 1c702a0..604177a7 100644
--- a/components/certificate_transparency/BUILD.gn
+++ b/components/certificate_transparency/BUILD.gn
@@ -6,10 +6,10 @@
   sources = [
     "chrome_ct_policy_enforcer.cc",
     "chrome_ct_policy_enforcer.h",
+    "chrome_require_ct_delegate.cc",
+    "chrome_require_ct_delegate.h",
     "ct_known_logs.cc",
     "ct_known_logs.h",
-    "ct_policy_manager.cc",
-    "ct_policy_manager.h",
     "features.cc",
     "features.h",
     "log_dns_client.cc",
@@ -42,8 +42,8 @@
   testonly = true
   sources = [
     "chrome_ct_policy_enforcer_unittest.cc",
+    "chrome_require_ct_delegate_unittest.cc",
     "ct_known_logs_unittest.cc",
-    "ct_policy_manager_unittest.cc",
     "log_dns_client_unittest.cc",
     "mock_log_dns_traffic.cc",
     "mock_log_dns_traffic.h",
diff --git a/components/certificate_transparency/ct_policy_manager.cc b/components/certificate_transparency/chrome_require_ct_delegate.cc
similarity index 72%
rename from components/certificate_transparency/ct_policy_manager.cc
rename to components/certificate_transparency/chrome_require_ct_delegate.cc
index d896d33..c75aec7 100644
--- a/components/certificate_transparency/ct_policy_manager.cc
+++ b/components/certificate_transparency/chrome_require_ct_delegate.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/certificate_transparency/ct_policy_manager.h"
+#include "components/certificate_transparency/chrome_require_ct_delegate.h"
 
 #include <algorithm>
 #include <iterator>
@@ -161,111 +161,67 @@
 
 }  // namespace
 
-class CTPolicyManager::CTDelegate
-    : public net::TransportSecurityState::RequireCTDelegate {
- public:
-  explicit CTDelegate();
-  ~CTDelegate() override = default;
+ChromeRequireCTDelegate::ChromeRequireCTDelegate()
+    : url_matcher_(std::make_unique<url_matcher::URLMatcher>()), next_id_(0) {}
 
-  // Updates the CTDelegate to require CT
-  // for |required_hosts|, and exclude |excluded_hosts| from CT policies.
-  void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
-                        const std::vector<std::string>& excluded_hosts,
-                        const std::vector<std::string>& excluded_spkis,
-                        const std::vector<std::string>& excluded_legacy_spkis);
-
-  // RequireCTDelegate implementation
-  // Called on the network task runner.
-  CTRequirementLevel IsCTRequiredForHost(
-      const std::string& hostname,
-      const net::X509Certificate* chain,
-      const net::HashValueVector& hashes) override;
-
- private:
-  struct Filter {
-    bool ct_required = false;
-    bool match_subdomains = false;
-    size_t host_length = 0;
-  };
-
-  // Returns true if a policy for |hostname| is found, setting
-  // |*ct_required| to indicate whether or not Certificate Transparency is
-  // required for the host.
-  bool MatchHostname(const std::string& hostname, bool* ct_required) const;
-
-  // Returns true if a policy for |chain|, which contains the SPKI hashes
-  // |hashes|, is found, setting |*ct_required| to indicate whether or not
-  // Certificate Transparency is required for the certificate.
-  bool MatchSPKI(const net::X509Certificate* chain,
-                 const net::HashValueVector& hashes,
-                 bool* ct_required) const;
-
-  // Updates the |url_matcher_| to
-  // require CT for |required_hosts| and exclude |excluded_hosts|, both
-  // of which are Lists of Strings which are URLBlacklist filters, and
-  // updates |excluded_spkis| and |excluded_legacy_spkis| to exclude CT for
-  // those SPKIs, which are encoded as strings using net::HashValue::ToString.
-  void Update(const std::vector<std::string>& required_hosts,
-              const std::vector<std::string>& excluded_hosts,
-              const std::vector<std::string>& excluded_spkis,
-              const std::vector<std::string>& excluded_legacy_spkis);
-
-  // Parses the filters from |host_patterns|, adding them as filters to
-  // |filters_| (with |ct_required| indicating whether or not CT is required
-  // for that host), and updating |*conditions| with the corresponding
-  // URLMatcher::Conditions to match the host.
-  void AddFilters(bool ct_required,
-                  const std::vector<std::string>& host_patterns,
-                  url_matcher::URLMatcherConditionSet::Vector* conditions);
-
-  // Parses the SPKIs from |list|, setting |*hashes| to the sorted set of all
-  // valid SPKIs.
-  void ParseSpkiHashes(const std::vector<std::string> list,
-                       net::HashValueVector* hashes) const;
-
-  // Returns true if |lhs| has greater precedence than |rhs|.
-  bool FilterTakesPrecedence(const Filter& lhs, const Filter& rhs) const;
-
-  std::unique_ptr<url_matcher::URLMatcher> url_matcher_;
-  url_matcher::URLMatcherConditionSet::ID next_id_;
-  std::map<url_matcher::URLMatcherConditionSet::ID, Filter> filters_;
-
-  // Both SPKI lists are sorted.
-  net::HashValueVector spkis_;
-  net::HashValueVector legacy_spkis_;
-
-  DISALLOW_COPY_AND_ASSIGN(CTDelegate);
-};
-
-CTPolicyManager::CTDelegate::CTDelegate()
-    : url_matcher_(new url_matcher::URLMatcher), next_id_(0) {}
-
-void CTPolicyManager::CTDelegate::UpdateCTPolicies(
-    const std::vector<std::string>& required_hosts,
-    const std::vector<std::string>& excluded_hosts,
-    const std::vector<std::string>& excluded_spkis,
-    const std::vector<std::string>& excluded_legacy_spkis) {
-  Update(required_hosts, excluded_hosts, excluded_spkis, excluded_legacy_spkis);
-}
+ChromeRequireCTDelegate::~ChromeRequireCTDelegate() {}
 
 net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel
-CTPolicyManager::CTDelegate::IsCTRequiredForHost(
+ChromeRequireCTDelegate::IsCTRequiredForHost(
     const std::string& hostname,
     const net::X509Certificate* chain,
-    const net::HashValueVector& hashes) {
-
+    const net::HashValueVector& spki_hashes) {
   bool ct_required = false;
   if (MatchHostname(hostname, &ct_required) ||
-      MatchSPKI(chain, hashes, &ct_required)) {
+      MatchSPKI(chain, spki_hashes, &ct_required)) {
     return ct_required ? CTRequirementLevel::REQUIRED
                        : CTRequirementLevel::NOT_REQUIRED;
   }
 
+  // Compute >= 2018-05-01, rather than deal with possible fractional
+  // seconds.
+  const base::Time kMay_1_2018 =
+      base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1525132800);
+  if (chain->valid_start() >= kMay_1_2018)
+    return CTRequirementLevel::REQUIRED;
+
   return CTRequirementLevel::DEFAULT;
 }
 
-bool CTPolicyManager::CTDelegate::MatchHostname(const std::string& hostname,
-                                                bool* ct_required) const {
+void ChromeRequireCTDelegate::UpdateCTPolicies(
+    const std::vector<std::string>& required_hosts,
+    const std::vector<std::string>& excluded_hosts,
+    const std::vector<std::string>& excluded_spkis,
+    const std::vector<std::string>& excluded_legacy_spkis) {
+  url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
+  filters_.clear();
+  next_id_ = 0;
+
+  url_matcher::URLMatcherConditionSet::Vector all_conditions;
+  AddFilters(true, required_hosts, &all_conditions);
+  AddFilters(false, excluded_hosts, &all_conditions);
+
+  url_matcher_->AddConditionSets(all_conditions);
+
+  ParseSpkiHashes(excluded_spkis, &spkis_);
+  ParseSpkiHashes(excluded_legacy_spkis, &legacy_spkis_);
+
+  // Filter out SPKIs that aren't for legacy CAs.
+  legacy_spkis_.erase(
+      std::remove_if(legacy_spkis_.begin(), legacy_spkis_.end(),
+                     [](const net::HashValue& hash) {
+                       if (!net::IsLegacyPubliclyTrustedCA(hash)) {
+                         LOG(ERROR) << "Non-legacy SPKI configured "
+                                    << hash.ToString();
+                         return true;
+                       }
+                       return false;
+                     }),
+      legacy_spkis_.end());
+}
+
+bool ChromeRequireCTDelegate::MatchHostname(const std::string& hostname,
+                                            bool* ct_required) const {
   if (url_matcher_->IsEmpty())
     return false;
 
@@ -301,9 +257,9 @@
   return true;
 }
 
-bool CTPolicyManager::CTDelegate::MatchSPKI(const net::X509Certificate* chain,
-                                            const net::HashValueVector& hashes,
-                                            bool* ct_required) const {
+bool ChromeRequireCTDelegate::MatchSPKI(const net::X509Certificate* chain,
+                                        const net::HashValueVector& hashes,
+                                        bool* ct_required) const {
   // Try to scan legacy SPKIs first, if any, since they will only require
   // comparing hash values.
   if (!legacy_spkis_.empty()) {
@@ -379,39 +335,7 @@
   return false;
 }
 
-void CTPolicyManager::CTDelegate::Update(
-    const std::vector<std::string>& required_hosts,
-    const std::vector<std::string>& excluded_hosts,
-    const std::vector<std::string>& excluded_spkis,
-    const std::vector<std::string>& excluded_legacy_spkis) {
-  url_matcher_.reset(new url_matcher::URLMatcher);
-  filters_.clear();
-  next_id_ = 0;
-
-  url_matcher::URLMatcherConditionSet::Vector all_conditions;
-  AddFilters(true, required_hosts, &all_conditions);
-  AddFilters(false, excluded_hosts, &all_conditions);
-
-  url_matcher_->AddConditionSets(all_conditions);
-
-  ParseSpkiHashes(excluded_spkis, &spkis_);
-  ParseSpkiHashes(excluded_legacy_spkis, &legacy_spkis_);
-
-  // Filter out SPKIs that aren't for legacy CAs.
-  legacy_spkis_.erase(
-      std::remove_if(legacy_spkis_.begin(), legacy_spkis_.end(),
-                     [](const net::HashValue& hash) {
-                       if (!net::IsLegacyPubliclyTrustedCA(hash)) {
-                         LOG(ERROR) << "Non-legacy SPKI configured "
-                                    << hash.ToString();
-                         return true;
-                       }
-                       return false;
-                     }),
-      legacy_spkis_.end());
-}
-
-void CTPolicyManager::CTDelegate::AddFilters(
+void ChromeRequireCTDelegate::AddFilters(
     bool ct_required,
     const std::vector<std::string>& hosts,
     url_matcher::URLMatcherConditionSet::Vector* conditions) {
@@ -472,11 +396,11 @@
   }
 }
 
-void CTPolicyManager::CTDelegate::ParseSpkiHashes(
-    const std::vector<std::string> list,
+void ChromeRequireCTDelegate::ParseSpkiHashes(
+    const std::vector<std::string> spki_list,
     net::HashValueVector* hashes) const {
   hashes->clear();
-  for (const auto& value : list) {
+  for (const auto& value : spki_list) {
     net::HashValue hash;
     if (!hash.FromString(value)) {
       continue;
@@ -486,9 +410,8 @@
   std::sort(hashes->begin(), hashes->end());
 }
 
-bool CTPolicyManager::CTDelegate::FilterTakesPrecedence(
-    const Filter& lhs,
-    const Filter& rhs) const {
+bool ChromeRequireCTDelegate::FilterTakesPrecedence(const Filter& lhs,
+                                                    const Filter& rhs) const {
   if (lhs.match_subdomains != rhs.match_subdomains)
     return !lhs.match_subdomains;  // Prefer the more explicit policy.
 
@@ -501,21 +424,4 @@
   return false;
 }
 
-CTPolicyManager::CTPolicyManager() : delegate_(new CTDelegate()) {}
-
-CTPolicyManager::~CTPolicyManager() {}
-
-void CTPolicyManager::UpdateCTPolicies(
-    const std::vector<std::string>& required_hosts,
-    const std::vector<std::string>& excluded_hosts,
-    const std::vector<std::string>& excluded_spkis,
-    const std::vector<std::string>& excluded_legacy_spkis) {
-  delegate_->UpdateCTPolicies(required_hosts, excluded_hosts, excluded_spkis,
-                              excluded_legacy_spkis);
-}
-
-net::TransportSecurityState::RequireCTDelegate* CTPolicyManager::GetDelegate() {
-  return delegate_.get();
-}
-
 }  // namespace certificate_transparency
diff --git a/components/certificate_transparency/chrome_require_ct_delegate.h b/components/certificate_transparency/chrome_require_ct_delegate.h
new file mode 100644
index 0000000..3b947f5
--- /dev/null
+++ b/components/certificate_transparency/chrome_require_ct_delegate.h
@@ -0,0 +1,107 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_REQUIRE_CT_DELEGATE_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_REQUIRE_CT_DELEGATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/url_matcher/url_matcher.h"
+#include "net/base/hash_value.h"
+#include "net/http/transport_security_state.h"
+
+namespace net {
+class X509Certificate;
+}  // namespace net
+
+namespace certificate_transparency {
+
+// ChromeRequireCTDelegate implements the policies used by Chrome to determine
+// when to require Certificate Transparency for a host or certificate. Combined
+// with ChromeCTPolicyEnforcer, these two classes implement the
+// "Certificate Transparency in Chrome" policy from
+// https://goo.gl/chrome/ct-policy - PolicyEnforcer imposing the policies on
+// the SCTs to determine whether or not a certificate complies, and
+// RequireCTDelegate to determine whether or not compliance is required for the
+// connection to succeed.
+//
+// To support Enterprise configuration, additional requirements or exceptions
+// can be provided via |UpdateCTPolicies()|, which uses the configuration
+// syntax documented in pref_names.h for each of the options.
+class ChromeRequireCTDelegate
+    : public net::TransportSecurityState::RequireCTDelegate {
+ public:
+  explicit ChromeRequireCTDelegate();
+  ~ChromeRequireCTDelegate() override;
+
+  // RequireCTDelegate implementation
+  CTRequirementLevel IsCTRequiredForHost(
+      const std::string& hostname,
+      const net::X509Certificate* chain,
+      const net::HashValueVector& spki_hashes) override;
+
+  // Updates the CTDelegate to require CT for |required_hosts|, and exclude
+  // |excluded_hosts| from CT policies.  In addtion, this method updates
+  // |excluded_spkis| and |excluded_legacy_spkis| intended for use within an
+  // Enterprise (see https://crbug.com/824184).
+  void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
+                        const std::vector<std::string>& excluded_hosts,
+                        const std::vector<std::string>& excluded_spkis,
+                        const std::vector<std::string>& excluded_legacy_spkis);
+
+ private:
+  struct Filter {
+    bool ct_required = false;
+    bool match_subdomains = false;
+    size_t host_length = 0;
+  };
+
+  // Returns true if a policy for |hostname| is found, setting
+  // |*ct_required| to indicate whether or not Certificate Transparency is
+  // required for the host.
+  bool MatchHostname(const std::string& hostname, bool* ct_required) const;
+
+  // Returns true if a policy for |chain|, which contains the SPKI hashes
+  // |hashes|, is found, setting |*ct_required| to indicate whether or not
+  // Certificate Transparency is required for the certificate.
+  bool MatchSPKI(const net::X509Certificate* chain,
+                 const net::HashValueVector& hashes,
+                 bool* ct_required) const;
+
+  // Parses the filters from |host_patterns|, adding them as filters to
+  // |filters_| (with |ct_required| indicating whether or not CT is required
+  // for that host), and updating |*conditions| with the corresponding
+  // URLMatcher::Conditions to match the host.
+  void AddFilters(bool ct_required,
+                  const std::vector<std::string>& host_patterns,
+                  url_matcher::URLMatcherConditionSet::Vector* conditions);
+
+  // Parses the SPKIs from |spki_list|, setting |*hashes| to the sorted set of
+  // all valid SPKIs.
+  void ParseSpkiHashes(const std::vector<std::string> spki_list,
+                       net::HashValueVector* hashes) const;
+
+  // Returns true if |lhs| has greater precedence than |rhs|. Filters of
+  // higher precedence are consulted first when determining if a given filter
+  // matches.
+  bool FilterTakesPrecedence(const Filter& lhs, const Filter& rhs) const;
+
+  std::unique_ptr<url_matcher::URLMatcher> url_matcher_;
+  url_matcher::URLMatcherConditionSet::ID next_id_;
+  std::map<url_matcher::URLMatcherConditionSet::ID, Filter> filters_;
+
+  // Both SPKI lists are sorted.
+  net::HashValueVector spkis_;
+  net::HashValueVector legacy_spkis_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeRequireCTDelegate);
+};
+
+}  // namespace certificate_transparency
+
+#endif  // COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_REQUIRE_CT_DELEGATE_H_
diff --git a/components/certificate_transparency/ct_policy_manager_unittest.cc b/components/certificate_transparency/chrome_require_ct_delegate_unittest.cc
similarity index 61%
rename from components/certificate_transparency/ct_policy_manager_unittest.cc
rename to components/certificate_transparency/chrome_require_ct_delegate_unittest.cc
index 0cd328e..a9e1628 100644
--- a/components/certificate_transparency/ct_policy_manager_unittest.cc
+++ b/components/certificate_transparency/chrome_require_ct_delegate_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/certificate_transparency/ct_policy_manager.h"
+#include "components/certificate_transparency/chrome_require_ct_delegate.h"
 
 #include <iterator>
 
@@ -27,9 +27,9 @@
 
 namespace {
 
-class CTPolicyManagerTest : public ::testing::Test {
+class ChromeRequireCTDelegateTest : public ::testing::Test {
  public:
-  CTPolicyManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
+  ChromeRequireCTDelegateTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
 
   void SetUp() override {
     cert_ = net::CreateCertificateChainFromFile(
@@ -48,7 +48,7 @@
 
 // Treat the preferences as a black box as far as naming, but ensure that
 // preferences get registered.
-TEST_F(CTPolicyManagerTest, RegistersPrefs) {
+TEST_F(ChromeRequireCTDelegateTest, RegistersPrefs) {
   TestingPrefServiceSimple pref_service;
   auto registered_prefs = std::distance(pref_service.registry()->begin(),
                                         pref_service.registry()->end());
@@ -58,172 +58,144 @@
   EXPECT_NE(registered_prefs, newly_registered_prefs);
 }
 
-TEST_F(CTPolicyManagerTest, DelegateChecksRequired) {
+TEST_F(ChromeRequireCTDelegateTest, DelegateChecksRequired) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  CTPolicyManager manager;
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
+  ChromeRequireCTDelegate delegate;
 
   // No required host set yet.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
   // Add a required host
-  manager.UpdateCTPolicies(
-      std::vector<std::string>{"google.com"}, std::vector<std::string>(),
-      std::vector<std::string>(), std::vector<std::string>());
+  delegate.UpdateCTPolicies({"google.com"}, {}, {}, {});
 
   // The new setting should take effect.
   EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 }
 
-TEST_F(CTPolicyManagerTest, DelegateChecksExcluded) {
+TEST_F(ChromeRequireCTDelegateTest, DelegateChecksExcluded) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  CTPolicyManager manager;
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
+  ChromeRequireCTDelegate delegate;
 
   // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
   // Add a excluded host
-  manager.UpdateCTPolicies(
-      std::vector<std::string>(), std::vector<std::string>{"google.com"},
-      std::vector<std::string>(), std::vector<std::string>());
+  delegate.UpdateCTPolicies({}, {"google.com"}, {}, {});
 
   // The new setting should take effect.
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 }
 
-TEST_F(CTPolicyManagerTest, IgnoresInvalidEntries) {
+TEST_F(ChromeRequireCTDelegateTest, IgnoresInvalidEntries) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  CTPolicyManager manager;
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
+  ChromeRequireCTDelegate delegate;
 
   // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
   // Now setup invalid state (that is, that fail to be parsable as
   // URLs).
-  manager.UpdateCTPolicies(
-      std::vector<std::string>{
-          "file:///etc/fstab", "file://withahost/etc/fstab",
-          "file:///c|/Windows", "*", "https://*", "example.com",
-          "https://example.test:invalid_port"},
-      std::vector<std::string>(), std::vector<std::string>(),
-      std::vector<std::string>());
+  delegate.UpdateCTPolicies(
+      {"file:///etc/fstab", "file://withahost/etc/fstab", "file:///c|/Windows",
+       "*", "https://*", "example.com", "https://example.test:invalid_port"},
+      {}, {}, {});
 
   // Wildcards are ignored (both * and https://*).
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+  // File URL hosts are ignored.
   // TODO(rsleevi): https://crbug.com/841407 - Ensure that file URLs have their
   // hosts ignored for policy.
   // EXPECT_EQ(CTRequirementLevel::DEFAULT,
-  //          delegate->IsCTRequiredForHost("withahost", cert_.get(), hashes_));
+  //          delegate.IsCTRequiredForHost("withahost", cert_.get(), hashes_));
 
   // While the partially parsed hosts should take effect.
-  EXPECT_EQ(
-      CTRequirementLevel::REQUIRED,
-      delegate->IsCTRequiredForHost("example.test", cert_.get(), hashes_));
   EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("example.test", cert_.get(), hashes_));
+  EXPECT_EQ(CTRequirementLevel::REQUIRED,
+            delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
 }
 
 // Make sure the various 'undocumented' priorities apply:
 //   - non-wildcards beat wildcards
 //   - more specific hosts beat less specific hosts
 //   - requiring beats excluding
-TEST_F(CTPolicyManagerTest, AppliesPriority) {
+TEST_F(ChromeRequireCTDelegateTest, AppliesPriority) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  CTPolicyManager manager;
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
+  ChromeRequireCTDelegate delegate;
 
   // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
   EXPECT_EQ(
       CTRequirementLevel::DEFAULT,
-      delegate->IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
+      delegate.IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("accounts.example.com", cert_.get(),
-                                          hashes_));
+            delegate.IsCTRequiredForHost("accounts.example.com", cert_.get(),
+                                         hashes_));
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("login.accounts.example.com",
-                                          cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("login.accounts.example.com",
+                                         cert_.get(), hashes_));
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("sub.accounts.example.com",
-                                          cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("sub.accounts.example.com",
+                                         cert_.get(), hashes_));
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("login.sub.accounts.example.com",
-                                          cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("login.sub.accounts.example.com",
+                                         cert_.get(), hashes_));
   EXPECT_EQ(
       CTRequirementLevel::DEFAULT,
-      delegate->IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
+      delegate.IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
 
   // Set up policies that exclude it for a domain and all of its subdomains,
   // but then require it for a specific host.
-  manager.UpdateCTPolicies(
-      std::vector<std::string>{"sub.example.com", "accounts.example.com",
-                               "test.example.com"},
-      std::vector<std::string>{"example.com", ".sub.example.com",
-                               ".sub.accounts.example.com", "test.example.com"},
-      std::vector<std::string>(), std::vector<std::string>());
+  delegate.UpdateCTPolicies(
+      {"sub.example.com", "accounts.example.com", "test.example.com"},
+      {"example.com", ".sub.example.com", ".sub.accounts.example.com",
+       "test.example.com"},
+      {}, {});
 
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
-            delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
   // Non-wildcarding (.sub.example.com) beats wildcarding (sub.example.com).
   EXPECT_EQ(
       CTRequirementLevel::NOT_REQUIRED,
-      delegate->IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
+      delegate.IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
   // More specific hosts (accounts.example.com) beat less specific hosts
   // (example.com + wildcard).
   EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("accounts.example.com", cert_.get(),
-                                          hashes_));
+            delegate.IsCTRequiredForHost("accounts.example.com", cert_.get(),
+                                         hashes_));
   // More specific hosts (accounts.example.com) beat less specific hosts
   // (example.com).
   EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("login.accounts.example.com",
-                                          cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("login.accounts.example.com",
+                                         cert_.get(), hashes_));
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
-            delegate->IsCTRequiredForHost("sub.accounts.example.com",
-                                          cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("sub.accounts.example.com",
+                                         cert_.get(), hashes_));
   EXPECT_EQ(CTRequirementLevel::REQUIRED,
-            delegate->IsCTRequiredForHost("login.sub.accounts.example.com",
-                                          cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("login.sub.accounts.example.com",
+                                         cert_.get(), hashes_));
   // Requiring beats excluding.
   EXPECT_EQ(
       CTRequirementLevel::REQUIRED,
-      delegate->IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
+      delegate.IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
 }
 
-TEST_F(CTPolicyManagerTest, SupportsOrgRestrictions) {
+TEST_F(ChromeRequireCTDelegateTest, SupportsOrgRestrictions) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
 
-  CTPolicyManager manager;
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
+  ChromeRequireCTDelegate delegate;
 
   base::FilePath test_directory = net::GetTestNetDataDirectory().Append(
       FILE_PATH_LITERAL("ov_name_constraints"));
@@ -340,33 +312,24 @@
           net::x509_util::DupCryptoBuffer(leaf->cert_buffer()),
           std::move(intermediates));
     }
-    manager.UpdateCTPolicies(
-        std::vector<std::string>(), std::vector<std::string>(),
-        std::vector<std::string>(), std::vector<std::string>());
+    delegate.UpdateCTPolicies({}, {}, {}, {});
 
     // There should be no existing settings.
     EXPECT_EQ(CTRequirementLevel::DEFAULT,
-              delegate->IsCTRequiredForHost("google.com", leaf.get(), hashes));
+              delegate.IsCTRequiredForHost("google.com", leaf.get(), hashes));
 
-    manager.UpdateCTPolicies(std::vector<std::string>(),
-                             std::vector<std::string>(),
-                             std::vector<std::string>{test.spki.ToString()},
-                             std::vector<std::string>());
+    delegate.UpdateCTPolicies({}, {}, {test.spki.ToString()}, {});
 
     // The new setting should take effect.
     EXPECT_EQ(test.expected,
-              delegate->IsCTRequiredForHost("google.com", leaf.get(), hashes));
+              delegate.IsCTRequiredForHost("google.com", leaf.get(), hashes));
   }
 }
 
-TEST_F(CTPolicyManagerTest, SupportsLegacyCaRestrictions) {
+TEST_F(ChromeRequireCTDelegateTest, SupportsLegacyCaRestrictions) {
   using CTRequirementLevel =
       net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
-  CTPolicyManager manager;
-
-  net::TransportSecurityState::RequireCTDelegate* delegate =
-      manager.GetDelegate();
-  ASSERT_TRUE(delegate);
+  ChromeRequireCTDelegate delegate;
 
   // The hash of a known legacy CA. See
   // //net/cert/root_cert_list_generated.h
@@ -375,35 +338,99 @@
       0x38, 0x3E, 0x37, 0x3F, 0x0F, 0x22, 0x9E, 0x7D, 0xFE, 0x34, 0x44,
       0x81, 0x0A, 0x8D, 0x6E, 0x50, 0x90, 0x5D, 0x20, 0xD6, 0x61,
   }};
-
   hashes_.push_back(net::HashValue(legacy_spki));
 
   // No setting should yield the default results.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
   // Setting to a non-legacy CA should not work.
   std::string leaf_hash_string = hashes_.front().ToString();
-  manager.UpdateCTPolicies(
-      std::vector<std::string>(), std::vector<std::string>(),
-      std::vector<std::string>(), std::vector<std::string>{leaf_hash_string});
+  delegate.UpdateCTPolicies({}, {}, {}, {leaf_hash_string});
 
   // This setting should have no effect, because the hash for |cert_|
   // is not a legacy CA hash.
   EXPECT_EQ(CTRequirementLevel::DEFAULT,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
 
   // Now set to a truly legacy CA, and create a chain that
   // contains that legacy CA hash.
-  std::string legacy_ca_hash_string = hashes_.back().ToString();
-
-  manager.UpdateCTPolicies(std::vector<std::string>(),
-                           std::vector<std::string>(),
-                           std::vector<std::string>(),
-                           std::vector<std::string>{legacy_ca_hash_string});
-
+  delegate.UpdateCTPolicies({}, {}, {}, {hashes_.back().ToString()});
   EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
-            delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+            delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+}
+
+TEST_F(ChromeRequireCTDelegateTest, RequiresCTAfterApril2018) {
+  using CTRequirementLevel =
+      net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
+  ChromeRequireCTDelegate delegate;
+
+  EXPECT_EQ(CTRequirementLevel::DEFAULT,
+            delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+
+  scoped_refptr<net::X509Certificate> may_2018 =
+      net::CreateCertificateChainFromFile(
+          net::GetTestCertsDirectory(), "may_2018.pem",
+          net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+  ASSERT_TRUE(may_2018);
+
+  net::HashValueVector new_hashes;
+  new_hashes.push_back(net::HashValue(
+      net::X509Certificate::CalculateFingerprint256(may_2018->cert_buffer())));
+
+  EXPECT_EQ(
+      CTRequirementLevel::REQUIRED,
+      delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+}
+
+TEST_F(ChromeRequireCTDelegateTest,
+       PoliciesCheckedBeforeRequiringCTAfterApril2018) {
+  using CTRequirementLevel =
+      net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
+  ChromeRequireCTDelegate delegate;
+
+  scoped_refptr<net::X509Certificate> may_2018 =
+      net::CreateCertificateChainFromFile(
+          net::GetTestCertsDirectory(), "may_2018.pem",
+          net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+  ASSERT_TRUE(may_2018);
+
+  net::HashValueVector new_hashes;
+  net::HashValue leaf_hash;
+  ASSERT_TRUE(net::x509_util::CalculateSha256SpkiHash(may_2018->cert_buffer(),
+                                                      &leaf_hash));
+  new_hashes.push_back(std::move(leaf_hash));
+
+  EXPECT_EQ(
+      CTRequirementLevel::REQUIRED,
+      delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+
+  // Check excluding by hostname.
+  delegate.UpdateCTPolicies({}, {"example.com"}, {}, {});
+  EXPECT_EQ(
+      CTRequirementLevel::NOT_REQUIRED,
+      delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+
+  // Check excluding by leaf hash.
+  delegate.UpdateCTPolicies({}, {}, {new_hashes.front().ToString()}, {});
+  EXPECT_EQ(
+      CTRequirementLevel::NOT_REQUIRED,
+      delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+
+  // Check excluding by legacy CA hash.
+
+  // The hash of a known legacy CA. See
+  // //net/cert/root_cert_list_generated.h
+  net::SHA256HashValue legacy_spki = {{
+      0x00, 0x6C, 0xB2, 0x26, 0xA7, 0x72, 0xC7, 0x18, 0x2D, 0x77, 0x72,
+      0x38, 0x3E, 0x37, 0x3F, 0x0F, 0x22, 0x9E, 0x7D, 0xFE, 0x34, 0x44,
+      0x81, 0x0A, 0x8D, 0x6E, 0x50, 0x90, 0x5D, 0x20, 0xD6, 0x61,
+  }};
+  new_hashes.push_back(net::HashValue(legacy_spki));
+  delegate.UpdateCTPolicies({}, {}, {}, {new_hashes.back().ToString()});
+  EXPECT_EQ(
+      CTRequirementLevel::NOT_REQUIRED,
+      delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
 }
 
 }  // namespace
diff --git a/components/certificate_transparency/ct_policy_manager.h b/components/certificate_transparency/ct_policy_manager.h
deleted file mode 100644
index 88f3b97..0000000
--- a/components/certificate_transparency/ct_policy_manager.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_POLICY_MANAGER_H_
-#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_POLICY_MANAGER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "net/http/transport_security_state.h"
-
-namespace certificate_transparency {
-
-// CTPolicyManager serves as the bridge between the Certificate Transparency
-// preferences (see pref_names.h) and the actual implementation, by exposing
-// a TransportSecurityState::RequireCTDelegate that can be used to query for
-// CT-related policies.
-class CTPolicyManager {
- public:
-  // Creates a CTPolicyManager that will provide a RequireCTDelegate delegate.
-  CTPolicyManager();
-  ~CTPolicyManager();
-
-  // Returns a RequireCTDelegate that responds based on the policies set via
-  // preferences.
-  //
-  // The order of priority of the preferences is that:
-  //   - Specific hosts are preferred over those that match subdomains.
-  //   - The most specific host is preferred.
-  //   - Requiring CT is preferred over excluding CT
-  //
-  net::TransportSecurityState::RequireCTDelegate* GetDelegate();
-
-  // Updates the CTDelegate to require CT for |required_hosts|, and exclude
-  // |excluded_hosts| from CT policies.  In addtion, this method updates
-  // |excluded_spkis| and |excluded_legacy_spkis| intended for use within an
-  // Enterprise (see https://crbug.com/824184).
-  void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
-                        const std::vector<std::string>& excluded_hosts,
-                        const std::vector<std::string>& excluded_spkis,
-                        const std::vector<std::string>& excluded_legacy_spkis);
-
- private:
-  class CTDelegate;
-  std::unique_ptr<CTDelegate> delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(CTPolicyManager);
-};
-
-}  // namespace certificate_transparency
-
-#endif  // COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_POLICY_MANAGER_H_
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 560c716..abf40af 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -576,8 +576,9 @@
   if (state_.input_region) {
     hit_test_region_ = *state_.input_region;
     hit_test_region_.Intersect(surface_hierarchy_content_bounds_);
-  } else
+  } else {
     hit_test_region_ = surface_hierarchy_content_bounds_;
+  }
 
   int outset = state_.input_outset;
   if (outset > 0) {
@@ -727,7 +728,7 @@
 
 Surface::State::~State() = default;
 
-bool Surface::State::operator==(const State& other) {
+bool Surface::State::operator==(const State& other) const {
   return other.opaque_region == opaque_region &&
          other.input_region == input_region &&
          other.buffer_scale == buffer_scale &&
diff --git a/components/exo/surface.h b/components/exo/surface.h
index d0874a9..4f070a9 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -248,8 +248,8 @@
     State();
     ~State();
 
-    bool operator==(const State& other);
-    bool operator!=(const State& other) { return !(*this == other); }
+    bool operator==(const State& other) const;
+    bool operator!=(const State& other) const { return !(*this == other); }
 
     cc::Region opaque_region;
     base::Optional<cc::Region> input_region;
diff --git a/components/viz/service/display/dc_layer_overlay.cc b/components/viz/service/display/dc_layer_overlay.cc
index 592eb099..1b0bd24 100644
--- a/components/viz/service/display/dc_layer_overlay.cc
+++ b/components/viz/service/display/dc_layer_overlay.cc
@@ -21,16 +21,16 @@
 DCLayerOverlayProcessor::DCLayerResult FromYUVQuad(
     cc::DisplayResourceProvider* resource_provider,
     const YUVVideoDrawQuad* quad,
-    DCLayerOverlay* ca_layer_overlay) {
+    DCLayerOverlay* dc_layer_overlay) {
   for (const auto& resource : quad->resources) {
     if (!resource_provider->IsOverlayCandidate(resource))
       return DCLayerOverlayProcessor::DC_LAYER_FAILED_TEXTURE_NOT_CANDIDATE;
   }
-  ca_layer_overlay->resources = quad->resources;
-  ca_layer_overlay->contents_rect = quad->ya_tex_coord_rect;
-  ca_layer_overlay->filter = GL_LINEAR;
-  ca_layer_overlay->color_space = quad->video_color_space;
-  ca_layer_overlay->require_overlay = quad->require_overlay;
+  dc_layer_overlay->resources = quad->resources;
+  dc_layer_overlay->contents_rect = quad->ya_tex_coord_rect;
+  dc_layer_overlay->filter = GL_LINEAR;
+  dc_layer_overlay->color_space = quad->video_color_space;
+  dc_layer_overlay->require_overlay = quad->require_overlay;
   return DCLayerOverlayProcessor::DC_LAYER_SUCCESS;
 }
 
@@ -94,7 +94,7 @@
     const gfx::RectF& display_rect,
     QuadList::ConstIterator quad_list_begin,
     QuadList::ConstIterator quad,
-    DCLayerOverlay* ca_layer_overlay) {
+    DCLayerOverlay* dc_layer_overlay) {
   if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver)
     return DC_LAYER_FAILED_QUAD_BLEND_MODE;
 
@@ -103,7 +103,7 @@
     case DrawQuad::YUV_VIDEO_CONTENT:
       result =
           FromYUVQuad(resource_provider, YUVVideoDrawQuad::MaterialCast(*quad),
-                      ca_layer_overlay);
+                      dc_layer_overlay);
       break;
     default:
       return DC_LAYER_FAILED_UNSUPPORTED_QUAD;
@@ -123,8 +123,8 @@
   overlay_shared_state->transform =
       quad->shared_quad_state->quad_to_target_transform.matrix();
 
-  ca_layer_overlay->shared_state = overlay_shared_state;
-  ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
+  dc_layer_overlay->shared_state = overlay_shared_state;
+  dc_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
 
   return result;
 }
@@ -135,7 +135,7 @@
     RenderPassList* render_passes,
     gfx::Rect* overlay_damage_rect,
     gfx::Rect* damage_rect,
-    DCLayerOverlayList* ca_layer_overlays) {
+    DCLayerOverlayList* dc_layer_overlays) {
   DCHECK(pass_info_.empty());
   processed_overlay_in_frame_ = false;
   if (base::FeatureList::IsEnabled(
@@ -145,12 +145,12 @@
       ProcessRenderPass(resource_provider, display_rect, pass.get(), is_root,
                         overlay_damage_rect,
                         is_root ? damage_rect : &pass->damage_rect,
-                        ca_layer_overlays);
+                        dc_layer_overlays);
     }
   } else {
     ProcessRenderPass(resource_provider, display_rect,
                       render_passes->back().get(), true, overlay_damage_rect,
-                      damage_rect, ca_layer_overlays);
+                      damage_rect, dc_layer_overlays);
   }
   pass_info_.clear();
 }
@@ -224,7 +224,7 @@
     bool is_root,
     gfx::Rect* overlay_damage_rect,
     gfx::Rect* damage_rect,
-    DCLayerOverlayList* ca_layer_overlays) {
+    DCLayerOverlayList* dc_layer_overlays) {
   gfx::Rect this_frame_underlay_rect;
   QuadList* quad_list = &render_pass->quad_list;
 
@@ -286,7 +286,7 @@
       overlay_damage_rect->Union(rect_in_root);
 
       RecordDCLayerResult(DC_LAYER_SUCCESS);
-      ca_layer_overlays->push_back(dc_layer);
+      dc_layer_overlays->push_back(dc_layer);
       if (!base::FeatureList::IsEnabled(
               features::kDirectCompositionNonrootOverlays)) {
         // Only allow one overlay for now.
diff --git a/components/viz/service/surfaces/surface_dependency_deadline.cc b/components/viz/service/surfaces/surface_dependency_deadline.cc
index f60a39b..4e86b83 100644
--- a/components/viz/service/surfaces/surface_dependency_deadline.cc
+++ b/components/viz/service/surfaces/surface_dependency_deadline.cc
@@ -59,7 +59,7 @@
 }
 
 bool SurfaceDependencyDeadline::operator==(
-    const SurfaceDependencyDeadline& other) {
+    const SurfaceDependencyDeadline& other) const {
   return begin_frame_source_ == other.begin_frame_source_ &&
          deadline_ == other.deadline_;
 }
diff --git a/components/viz/service/surfaces/surface_dependency_deadline.h b/components/viz/service/surfaces/surface_dependency_deadline.h
index bc5913b..9c0349df 100644
--- a/components/viz/service/surfaces/surface_dependency_deadline.h
+++ b/components/viz/service/surfaces/surface_dependency_deadline.h
@@ -45,8 +45,8 @@
   // Takes on the same BeginFrameSource and deadline as |other|.
   void InheritFrom(const SurfaceDependencyDeadline& other);
 
-  bool operator==(const SurfaceDependencyDeadline& other);
-  bool operator!=(const SurfaceDependencyDeadline& other) {
+  bool operator==(const SurfaceDependencyDeadline& other) const;
+  bool operator!=(const SurfaceDependencyDeadline& other) const {
     return !(*this == other);
   }
 
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc
index 7118227d..4a82566 100644
--- a/content/browser/loader/resource_message_filter.cc
+++ b/content/browser/loader/resource_message_filter.cc
@@ -179,7 +179,10 @@
 
   if (base::FeatureList::IsEnabled(network::features::kOutOfBlinkCORS)) {
     url_loader_factory_ = std::make_unique<network::cors::CORSURLLoaderFactory>(
-        std::move(url_loader_factory_));
+        std::move(url_loader_factory_),
+        base::BindRepeating(&ResourceDispatcherHostImpl::CancelRequest,
+                            base::Unretained(ResourceDispatcherHostImpl::Get()),
+                            requester_info_->child_id()));
   }
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index f0f1018..95f60d73d 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1459,6 +1459,10 @@
   return base::EmptyString();
 }
 
+bool RenderWidgetHostViewAura::ShouldDoLearning() {
+  return GetTextInputManager() && GetTextInputManager()->should_do_learning();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // RenderWidgetHostViewAura, display::DisplayObserver implementation:
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index a711134..775967b8 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -240,6 +240,7 @@
   bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
   void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override;
   const std::string& GetClientSourceInfo() const override;
+  bool ShouldDoLearning() override;
 
   // Overridden from display::DisplayObserver:
   void OnDisplayAdded(const display::Display& new_display) override;
diff --git a/content/browser/renderer_host/text_input_manager.cc b/content/browser/renderer_host/text_input_manager.cc
index 8ab2992..24f32e72 100644
--- a/content/browser/renderer_host/text_input_manager.cc
+++ b/content/browser/renderer_host/text_input_manager.cc
@@ -35,7 +35,8 @@
 
 }  // namespace
 
-TextInputManager::TextInputManager() : active_view_(nullptr) {}
+TextInputManager::TextInputManager(bool should_do_learning)
+    : active_view_(nullptr), should_do_learning_(should_do_learning) {}
 
 TextInputManager::~TextInputManager() {
   // If there is an active view, we should unregister it first so that the
diff --git a/content/browser/renderer_host/text_input_manager.h b/content/browser/renderer_host/text_input_manager.h
index b4cbcae..8e4ecfe 100644
--- a/content/browser/renderer_host/text_input_manager.h
+++ b/content/browser/renderer_host/text_input_manager.h
@@ -131,7 +131,7 @@
     base::string16 text_;
   };
 
-  TextInputManager();
+  explicit TextInputManager(bool should_do_learning);
   ~TextInputManager();
 
   // Returns the currently active widget, i.e., the RWH which is associated with
@@ -226,6 +226,8 @@
       RenderWidgetHostViewBase* view);
   const gfx::Range* GetCompositionRangeForTesting() const;
 
+  bool should_do_learning() const { return should_do_learning_; }
+
  private:
   // This class is used to create maps which hold specific IME state for a
   // view.
@@ -249,6 +251,10 @@
   ViewMap<CompositionRangeInfo> composition_range_info_map_;
   ViewMap<TextSelection> text_selection_map_;
 
+  // Whether the text input should be used to improve typing suggestions for the
+  // user.
+  bool should_do_learning_;
+
   base::ObserverList<Observer> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(TextInputManager);
diff --git a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index 2868fc41..9c653a1e 100644
--- a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -137,11 +137,6 @@
   void TestBypassCache(const GURL& url,
                        ResourceType resource_type,
                        bool expect_bypass) {
-    // TODO(https://crbug.com/675540): Remove the following command line switch
-    // when updateViaCache is shipped to stable.
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kEnableExperimentalWebPlatformFeatures);
-
     std::unique_ptr<net::URLRequest> request(CreateRequest(url));
     std::unique_ptr<ServiceWorkerContextRequestHandler> handler(
         CreateHandler(resource_type));
@@ -190,34 +185,6 @@
   TestBypassCacheForImportedScript(false);
 }
 
-// TODO(https://crbug.com/675540): Remove the
-// UpdateBefore24HoursWithoutUpdateViaCache test when the update_via_cache flag
-// is shipped to stable as this is to test the legacy behavior.
-TEST_F(ServiceWorkerContextRequestHandlerTest,
-       UpdateBefore24HoursWithoutUpdateViaCache) {
-  registration_->set_last_update_check(base::Time::Now());
-  version_->SetStatus(ServiceWorkerVersion::NEW);
-
-  // Conduct a resource fetch for the main script.
-  base::HistogramTester histograms;
-  std::unique_ptr<net::URLRequest> request(CreateRequest(script_url_));
-  std::unique_ptr<ServiceWorkerContextRequestHandler> handler(
-      CreateHandler(RESOURCE_TYPE_SERVICE_WORKER));
-  std::unique_ptr<net::URLRequestJob> job(
-      handler->MaybeCreateJob(request.get(), nullptr, nullptr));
-  ASSERT_TRUE(job.get());
-  ServiceWorkerWriteToCacheJob* sw_job =
-      static_cast<ServiceWorkerWriteToCacheJob*>(job.get());
-  histograms.ExpectUniqueSample(
-      "ServiceWorker.ContextRequestHandlerStatus.NewWorker.MainScript",
-      static_cast<int>(
-          ServiceWorkerContextRequestHandler::CreateJobStatus::WRITE_JOB),
-      1);
-
-  // Verify the net request is not initialized to bypass the browser cache.
-  EXPECT_FALSE(sw_job->net_request_->load_flags() & net::LOAD_BYPASS_CACHE);
-}
-
 TEST_F(ServiceWorkerContextRequestHandlerTest,
        UpdateBefore24HoursWithUpdateViaCacheAll) {
   registration_->SetUpdateViaCache(
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index 5ff951c..c34711b2 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -1466,15 +1466,10 @@
   for (uint32_t feature : registration.used_features)
     data.add_used_features(feature);
 
-  // TODO(https://crbug.com/675540): Remove the the command line check and
-  // always set to data when shipping the updateViaCache flag to stable.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableExperimentalWebPlatformFeatures)) {
-    data.set_update_via_cache(
-        static_cast<
-            ServiceWorkerRegistrationData_ServiceWorkerUpdateViaCacheType>(
-            registration.update_via_cache));
-  }
+  data.set_update_via_cache(
+      static_cast<
+          ServiceWorkerRegistrationData_ServiceWorkerUpdateViaCacheType>(
+          registration.update_via_cache));
 
   std::string value;
   bool success = data.SerializeToString(&value);
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.h b/content/browser/service_worker/service_worker_write_to_cache_job.h
index 53b4536..1a3a3f2a 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.h
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.h
@@ -62,11 +62,6 @@
 
  private:
   friend class ServiceWorkerContextRequestHandlerTest;
-  // TODO(https://crbug.com/675540): Remove the following
-  // FRIEND_TEST_ALL_PREFIXES directive when the update_via_cache flag is
-  // shipped to stable.
-  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
-                           UpdateBefore24HoursWithoutUpdateViaCache);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
                            ServiceWorkerDataRequestAnnotation);
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 03ec3aa..2d1375e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2845,8 +2845,11 @@
   if (GetOuterWebContents())
     return GetOuterWebContents()->GetTextInputManager();
 
-  if (!text_input_manager_)
-    text_input_manager_.reset(new TextInputManager());
+  if (!text_input_manager_) {
+    text_input_manager_.reset(new TextInputManager(
+        GetBrowserContext() &&
+        !GetBrowserContext()->IsOffTheRecord()) /* should_do_learning */);
+  }
 
   return text_input_manager_.get();
 }
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.cc b/content/browser/web_package/signed_exchange_cert_fetcher.cc
index a91bdf9b..083d6c6 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.cc
@@ -70,15 +70,16 @@
     const GURL& cert_url,
     url::Origin request_initiator,
     bool force_fetch,
+    SignedExchangeVersion version,
     CertificateCallback callback,
     SignedExchangeDevToolsProxy* devtools_proxy) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
                "SignedExchangeCertFetcher::CreateAndStart");
   std::unique_ptr<SignedExchangeCertFetcher> cert_fetcher(
-      new SignedExchangeCertFetcher(std::move(shared_url_loader_factory),
-                                    std::move(throttles), cert_url,
-                                    std::move(request_initiator), force_fetch,
-                                    std::move(callback), devtools_proxy));
+      new SignedExchangeCertFetcher(
+          std::move(shared_url_loader_factory), std::move(throttles), cert_url,
+          std::move(request_initiator), force_fetch, version,
+          std::move(callback), devtools_proxy));
   cert_fetcher->Start();
   return cert_fetcher;
 }
@@ -89,11 +90,13 @@
     const GURL& cert_url,
     url::Origin request_initiator,
     bool force_fetch,
+    SignedExchangeVersion version,
     CertificateCallback callback,
     SignedExchangeDevToolsProxy* devtools_proxy)
     : shared_url_loader_factory_(std::move(shared_url_loader_factory)),
       throttles_(std::move(throttles)),
       resource_request_(std::make_unique<network::ResourceRequest>()),
+      version_(version),
       callback_(std::move(callback)),
       devtools_proxy_(devtools_proxy) {
   // TODO(https://crbug.com/803774): Revisit more ResourceRequest flags.
@@ -179,12 +182,10 @@
   body_.reset();
   handle_watcher_ = nullptr;
 
-  // TODO(https://crbug.com/803774): Take SignedExchangeVersion as a
-  // parameter of CreateAndStart() and use it here.
   std::unique_ptr<SignedExchangeCertificateChain> cert_chain =
       SignedExchangeCertificateChain::Parse(
-          SignedExchangeVersion::kB0,
-          base::as_bytes(base::make_span(body_string_)), devtools_proxy_);
+          version_, base::as_bytes(base::make_span(body_string_)),
+          devtools_proxy_);
   body_string_.clear();
   if (!cert_chain) {
     signed_exchange_utils::ReportErrorAndEndTraceEvent(
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher.h b/content/browser/web_package/signed_exchange_cert_fetcher.h
index 3e860f2c..23de061 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher.h
+++ b/content/browser/web_package/signed_exchange_cert_fetcher.h
@@ -52,6 +52,7 @@
       const GURL& cert_url,
       url::Origin request_initiator,
       bool force_fetch,
+      SignedExchangeVersion version,
       CertificateCallback callback,
       SignedExchangeDevToolsProxy* devtools_proxy);
 
@@ -73,6 +74,7 @@
       const GURL& cert_url,
       url::Origin request_initiator,
       bool force_fetch,
+      SignedExchangeVersion version,
       CertificateCallback callback,
       SignedExchangeDevToolsProxy* devtools_proxy);
   void Start();
@@ -99,6 +101,7 @@
   scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
   std::vector<std::unique_ptr<URLLoaderThrottle>> throttles_;
   std::unique_ptr<network::ResourceRequest> resource_request_;
+  const SignedExchangeVersion version_;
   CertificateCallback callback_;
 
   std::unique_ptr<ThrottlingURLLoader> url_loader_;
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher_factory.cc b/content/browser/web_package/signed_exchange_cert_fetcher_factory.cc
index a853b33..2023480 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher_factory.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher_factory.cc
@@ -25,6 +25,7 @@
   std::unique_ptr<SignedExchangeCertFetcher> CreateFetcherAndStart(
       const GURL& cert_url,
       bool force_fetch,
+      SignedExchangeVersion version,
       SignedExchangeCertFetcher::CertificateCallback callback,
       SignedExchangeDevToolsProxy* devtools_proxy) override;
 
@@ -38,6 +39,7 @@
 SignedExchangeCertFetcherFactoryImpl::CreateFetcherAndStart(
     const GURL& cert_url,
     bool force_fetch,
+    SignedExchangeVersion version,
     SignedExchangeCertFetcher::CertificateCallback callback,
     SignedExchangeDevToolsProxy* devtools_proxy) {
   DCHECK(url_loader_factory_);
@@ -46,7 +48,7 @@
       std::move(url_loader_throttles_getter_).Run();
   return SignedExchangeCertFetcher::CreateAndStart(
       std::move(url_loader_factory_), std::move(throttles), cert_url,
-      std::move(request_initiator_), force_fetch, std::move(callback),
+      std::move(request_initiator_), force_fetch, version, std::move(callback),
       devtools_proxy);
 }
 
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher_factory.h b/content/browser/web_package/signed_exchange_cert_fetcher_factory.h
index 808fc572..dc01c1c 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher_factory.h
+++ b/content/browser/web_package/signed_exchange_cert_fetcher_factory.h
@@ -32,6 +32,7 @@
   virtual std::unique_ptr<SignedExchangeCertFetcher> CreateFetcherAndStart(
       const GURL& cert_url,
       bool force_fetch,
+      SignedExchangeVersion version,
       SignedExchangeCertFetcher::CertificateCallback callback,
       SignedExchangeDevToolsProxy* devtools_proxy) = 0;
 
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
index 771e601..4d84e0e 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
@@ -210,7 +210,8 @@
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &mock_loader_factory_),
         std::move(throttles_), url_, request_initiator_, force_fetch,
-        std::move(callback), nullptr /* devtools_proxy */);
+        SignedExchangeVersion::kB0, std::move(callback),
+        nullptr /* devtools_proxy */);
   }
 
   void CallOnReceiveResponse() {
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 9b60011..3d0e9c1 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -10,7 +10,6 @@
 #include "content/browser/loader/merkle_integrity_source_stream.h"
 #include "content/browser/web_package/signed_exchange_cert_fetcher_factory.h"
 #include "content/browser/web_package/signed_exchange_certificate_chain.h"
-#include "content/browser/web_package/signed_exchange_consts.h"
 #include "content/browser/web_package/signed_exchange_devtools_proxy.h"
 #include "content/browser/web_package/signed_exchange_header.h"
 #include "content/browser/web_package/signed_exchange_signature_verifier.h"
@@ -89,10 +88,10 @@
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
                      "SignedExchangeHandler::SignedExchangeHandler");
 
-  base::Optional<std::string> content_type_version_param;
-  if (!SignedExchangeHeaderParser::GetVersionParamFromContentType(
-          content_type, &content_type_version_param) ||
-      !content_type_version_param || *content_type_version_param != "b0") {
+  // Currently, only 'v=b0' is supported.
+  if (!SignedExchangeHeaderParser::GetVersionParamFromContentType(content_type,
+                                                                  &version_) ||
+      version_ != SignedExchangeVersion::kB0) {
     base::SequencedTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&SignedExchangeHandler::RunErrorCallback,
                                   weak_factory_.GetWeakPtr(), net::ERR_FAILED));
@@ -237,11 +236,12 @@
   // TODO(https://crbug.com/819467): When we will support ed25519Key, |cert_url|
   // may be empty.
   DCHECK(cert_url.is_valid());
+  DCHECK(version_.has_value());
 
   DCHECK(cert_fetcher_factory_);
   cert_fetcher_ = std::move(cert_fetcher_factory_)
                       ->CreateFetcherAndStart(
-                          cert_url, false,
+                          cert_url, false, *version_,
                           base::BindOnce(&SignedExchangeHandler::OnCertReceived,
                                          base::Unretained(this)),
                           devtools_proxy_.get());
diff --git a/content/browser/web_package/signed_exchange_handler.h b/content/browser/web_package/signed_exchange_handler.h
index 83c7615..52386898 100644
--- a/content/browser/web_package/signed_exchange_handler.h
+++ b/content/browser/web_package/signed_exchange_handler.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "content/browser/web_package/signed_exchange_consts.h"
 #include "content/browser/web_package/signed_exchange_header.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/system/data_pipe.h"
@@ -96,6 +97,7 @@
   void OnCertVerifyComplete(int result);
 
   ExchangeHeadersCallback headers_callback_;
+  base::Optional<SignedExchangeVersion> version_;
   std::unique_ptr<net::SourceStream> source_;
 
   State state_ = State::kReadingHeadersLength;
diff --git a/content/browser/web_package/signed_exchange_handler_unittest.cc b/content/browser/web_package/signed_exchange_handler_unittest.cc
index 9610a99..cf72a86 100644
--- a/content/browser/web_package/signed_exchange_handler_unittest.cc
+++ b/content/browser/web_package/signed_exchange_handler_unittest.cc
@@ -60,13 +60,13 @@
   std::unique_ptr<SignedExchangeCertFetcher> CreateFetcherAndStart(
       const GURL& cert_url,
       bool force_fetch,
+      SignedExchangeVersion version,
       SignedExchangeCertFetcher::CertificateCallback callback,
       SignedExchangeDevToolsProxy* devtools_proxy) override {
     EXPECT_EQ(cert_url, expected_cert_url_);
 
     auto cert_chain = SignedExchangeCertificateChain::Parse(
-        SignedExchangeVersion::kB0, base::as_bytes(base::make_span(cert_str_)),
-        devtools_proxy);
+        version, base::as_bytes(base::make_span(cert_str_)), devtools_proxy);
     EXPECT_TRUE(cert_chain);
 
     base::SequencedTaskRunnerHandle::Get()->PostTask(
diff --git a/content/browser/web_package/signed_exchange_header_parser.cc b/content/browser/web_package/signed_exchange_header_parser.cc
index 5a9c66a..96e26d3 100644
--- a/content/browser/web_package/signed_exchange_header_parser.cc
+++ b/content/browser/web_package/signed_exchange_header_parser.cc
@@ -286,7 +286,7 @@
 // static
 bool SignedExchangeHeaderParser::GetVersionParamFromContentType(
     base::StringPiece content_type,
-    base::Optional<std::string>* version_param) {
+    base::Optional<SignedExchangeVersion>* version_param) {
   DCHECK(version_param);
   StructuredHeaderParser parser(content_type);
   ParameterisedLabel parameterised_label;
@@ -297,7 +297,12 @@
   if (it == parameterised_label.params.end()) {
     *version_param = base::nullopt;
   } else {
-    *version_param = it->second;
+    if (it->second == "b0")
+      *version_param = SignedExchangeVersion::kB0;
+    else if (it->second == "b1")
+      *version_param = SignedExchangeVersion::kB1;
+    else
+      return false;
   }
   return true;
 }
diff --git a/content/browser/web_package/signed_exchange_header_parser.h b/content/browser/web_package/signed_exchange_header_parser.h
index 7eb7660..01697eb5 100644
--- a/content/browser/web_package/signed_exchange_header_parser.h
+++ b/content/browser/web_package/signed_exchange_header_parser.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
+#include "content/browser/web_package/signed_exchange_consts.h"
 #include "content/common/content_export.h"
 #include "net/base/hash_value.h"
 #include "url/gurl.h"
@@ -49,11 +50,11 @@
       SignedExchangeDevToolsProxy* devtools_proxy);
 
   // Parses |content_type| to get the value of "v=" parameter of the signed
-  // exchange. Example: "b0" for "application/signed-exchange;v=b0". Returns
-  // false if failed to parse.
+  // exchange, and converts to SignedExchangeVersion. Returns false if failed to
+  // parse.
   static bool GetVersionParamFromContentType(
       base::StringPiece content_type,
-      base::Optional<std::string>* version_param);
+      base::Optional<SignedExchangeVersion>* version_param);
 };
 
 }  // namespace content
diff --git a/content/browser/web_package/signed_exchange_header_parser_unittest.cc b/content/browser/web_package/signed_exchange_header_parser_unittest.cc
index 096617d..32f912e 100644
--- a/content/browser/web_package/signed_exchange_header_parser_unittest.cc
+++ b/content/browser/web_package/signed_exchange_header_parser_unittest.cc
@@ -231,7 +231,7 @@
 
 TEST_F(SignedExchangeHeaderParserTest, VersionParam_None) {
   const char content_type[] = "application/signed-exchange";
-  base::Optional<std::string> version;
+  base::Optional<SignedExchangeVersion> version;
   EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
       content_type, &version));
   EXPECT_FALSE(version);
@@ -239,43 +239,43 @@
 
 TEST_F(SignedExchangeHeaderParserTest, VersionParam_NoneWithSemicolon) {
   const char content_type[] = "application/signed-exchange;";
-  base::Optional<std::string> version;
+  base::Optional<SignedExchangeVersion> version;
   EXPECT_FALSE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
       content_type, &version));
 }
 
 TEST_F(SignedExchangeHeaderParserTest, VersionParam_EmptyString) {
   const char content_type[] = "application/signed-exchange;v=";
-  base::Optional<std::string> version;
+  base::Optional<SignedExchangeVersion> version;
   EXPECT_FALSE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
       content_type, &version));
 }
 
 TEST_F(SignedExchangeHeaderParserTest, VersionParam_Simple) {
   const char content_type[] = "application/signed-exchange;v=b0";
-  base::Optional<std::string> version;
+  base::Optional<SignedExchangeVersion> version;
   EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
       content_type, &version));
   ASSERT_TRUE(version);
-  EXPECT_EQ(*version, "b0");
+  EXPECT_EQ(*version, SignedExchangeVersion::kB0);
 }
 
 TEST_F(SignedExchangeHeaderParserTest, VersionParam_SimpleWithSpace) {
-  const char content_type[] = "application/signed-exchange; v=b0";
-  base::Optional<std::string> version;
+  const char content_type[] = "application/signed-exchange; v=b1";
+  base::Optional<SignedExchangeVersion> version;
   EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
       content_type, &version));
   ASSERT_TRUE(version);
-  EXPECT_EQ(*version, "b0");
+  EXPECT_EQ(*version, SignedExchangeVersion::kB1);
 }
 
 TEST_F(SignedExchangeHeaderParserTest, VersionParam_SimpleWithDoublequotes) {
   const char content_type[] = "application/signed-exchange;v=\"b0\"";
-  base::Optional<std::string> version;
+  base::Optional<SignedExchangeVersion> version;
   EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
       content_type, &version));
   ASSERT_TRUE(version);
-  EXPECT_EQ(*version, "b0");
+  EXPECT_EQ(*version, SignedExchangeVersion::kB0);
 }
 
 }  // namespace content
diff --git a/content/common/service_worker/service_worker_utils.cc b/content/common/service_worker/service_worker_utils.cc
index 5584d42a..0820aad 100644
--- a/content/common/service_worker/service_worker_utils.cc
+++ b/content/common/service_worker/service_worker_utils.cc
@@ -215,12 +215,6 @@
 bool ServiceWorkerUtils::ShouldBypassCacheDueToUpdateViaCache(
     bool is_main_script,
     blink::mojom::ServiceWorkerUpdateViaCache cache_mode) {
-  // TODO(https://crbug.com/675540): Remove the command line check and always
-  // respect cache_mode when shipping updateViaCache flag to stable.
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableExperimentalWebPlatformFeatures)) {
-    return false;
-  }
   switch (cache_mode) {
     case blink::mojom::ServiceWorkerUpdateViaCache::kImports:
       return is_main_script;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index a238465..8911ec660 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -277,8 +277,15 @@
 
   if (type == blink::WebInputEvent::kChar ||
       type == blink::WebInputEvent::kRawKeyDown) {
-    event->text[0] = key_code;
-    event->unmodified_text[0] = key_code;
+    // |key| is the only parameter that contains information about the case of
+    // the character. Use it to be able to generate lower case input.
+    if (key.IsCharacter()) {
+      event->text[0] = key.ToCharacter();
+      event->unmodified_text[0] = key.ToCharacter();
+    } else {
+      event->text[0] = key_code;
+      event->unmodified_text[0] = key_code;
+    }
   }
 }
 
diff --git a/content/test/mock_render_widget_host_delegate.cc b/content/test/mock_render_widget_host_delegate.cc
index 9d2404e..bb23893 100644
--- a/content/test/mock_render_widget_host_delegate.cc
+++ b/content/test/mock_render_widget_host_delegate.cc
@@ -11,7 +11,9 @@
 
 namespace content {
 
-MockRenderWidgetHostDelegate::MockRenderWidgetHostDelegate() = default;
+MockRenderWidgetHostDelegate::MockRenderWidgetHostDelegate()
+    : text_input_manager_(false /* should_do_learning */) {}
+
 MockRenderWidgetHostDelegate::~MockRenderWidgetHostDelegate() = default;
 
 void MockRenderWidgetHostDelegate::ResizeDueToAutoResize(
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index f15a48a..02ada53 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -108,24 +108,6 @@
   ]
 }
 
-mojom("tab_socket") {
-  sources = [
-    "lib/tab_socket.mojom",
-  ]
-  public_deps = [
-    "//mojo/public/mojom/base",
-  ]
-}
-
-mojom("headless_render_frame_controller") {
-  sources = [
-    "lib/headless_render_frame_controller.mojom",
-  ]
-  public_deps = [
-    "//mojo/public/mojom/base",
-  ]
-}
-
 service_manifest("headless_browser_manifest_overlay") {
   source = "lib/browser/headless_browser_manifest_overlay.json"
 }
@@ -150,8 +132,6 @@
   deps = [
     ":headless_browser_manifest_overlay",
     ":headless_packaged_services_manifest_overlay",
-    ":headless_render_frame_controller_js",
-    ":tab_socket_js",
   ]
 }
 
@@ -338,8 +318,6 @@
     "lib/browser/headless_resource_dispatcher_host_delegate.h",
     "lib/browser/headless_shell_application_mac.h",
     "lib/browser/headless_shell_application_mac.mm",
-    "lib/browser/headless_tab_socket_impl.cc",
-    "lib/browser/headless_tab_socket_impl.h",
     "lib/browser/headless_url_request_context_getter.cc",
     "lib/browser/headless_url_request_context_getter.h",
     "lib/browser/headless_window_tree_host.h",
@@ -453,9 +431,7 @@
 
   deps = [
     ":gen_devtools_client_api",
-    ":headless_render_frame_controller",
     ":protocol_sources",
-    ":tab_socket",
     ":version_header",
     "//components/cookie_config",
     "//components/security_state/core",
@@ -483,10 +459,6 @@
       "lib/headless_content_main_delegate.h",
       "lib/renderer/headless_content_renderer_client.cc",
       "lib/renderer/headless_content_renderer_client.h",
-      "lib/renderer/headless_render_frame_controller_impl.cc",
-      "lib/renderer/headless_render_frame_controller_impl.h",
-      "lib/renderer/headless_tab_socket_bindings.cc",
-      "lib/renderer/headless_tab_socket_bindings.h",
       "lib/utility/headless_content_utility_client.cc",
       "lib/utility/headless_content_utility_client.h",
     ]
@@ -569,10 +541,6 @@
       "lib/headless_content_main_delegate.h",
       "lib/renderer/headless_content_renderer_client.cc",
       "lib/renderer/headless_content_renderer_client.h",
-      "lib/renderer/headless_render_frame_controller_impl.cc",
-      "lib/renderer/headless_render_frame_controller_impl.h",
-      "lib/renderer/headless_tab_socket_bindings.cc",
-      "lib/renderer/headless_tab_socket_bindings.h",
     ]
 
     deps = [
@@ -792,8 +760,6 @@
     "test/headless_browser_test.cc",
     "test/headless_browser_test.h",
     "test/headless_test_launcher.cc",
-    "test/tab_socket_test.cc",
-    "test/tab_socket_test.h",
     "test/test_protocol_handler.cc",
     "test/test_protocol_handler.h",
     "test/test_url_request_job.cc",
diff --git a/headless/lib/browser/devtools_api/devtools_connection.js b/headless/lib/browser/devtools_api/devtools_connection.js
index 461bd76..bcd64b1b 100644
--- a/headless/lib/browser/devtools_api/devtools_connection.js
+++ b/headless/lib/browser/devtools_api/devtools_connection.js
@@ -4,8 +4,7 @@
 
 /**
  * @fileoverview Contains a class which marshals DevTools protocol messages over
- * a provided low level message transport. This transport might be a headless
- * TabSocket, or a WebSocket or a mock for testing.
+ * a provided low level message transport.
  */
 
 'use strict';
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 2fff1c5d..cb38ee1 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -507,16 +507,6 @@
 }
 
 HeadlessBrowserContext::Builder&
-HeadlessBrowserContext::Builder::AddTabSocketMojoBindings() {
-  std::string js_bindings =
-      ui::ResourceBundle::GetSharedInstance()
-          .GetRawDataResource(IDR_HEADLESS_TAB_SOCKET_MOJOM_JS)
-          .as_string();
-  mojo_bindings_.emplace_back("headless/lib/tab_socket.mojom", js_bindings);
-  return *this;
-}
-
-HeadlessBrowserContext::Builder&
 HeadlessBrowserContext::Builder::EnableUnsafeNetworkAccessWithMojoBindings(
     bool enable_http_and_https_if_mojo_used) {
   enable_http_and_https_if_mojo_used_ = enable_http_and_https_if_mojo_used;
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index c2f5615..14d0d72 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -53,8 +53,6 @@
 namespace headless {
 
 namespace {
-const char kCapabilityPath[] =
-    "interface_provider_specs.navigation:frame.provides.renderer";
 
 #if defined(HEADLESS_USE_BREAKPAD)
 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
@@ -174,21 +172,7 @@
   base::StringPiece manifest_template =
       ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
           IDR_HEADLESS_BROWSER_MANIFEST_OVERLAY);
-  std::unique_ptr<base::Value> manifest =
-      base::JSONReader::Read(manifest_template);
-
-  // Add mojo_service_names to renderer capability specified in options.
-  base::DictionaryValue* manifest_dictionary = nullptr;
-  CHECK(manifest->GetAsDictionary(&manifest_dictionary));
-
-  base::ListValue* capability_list = nullptr;
-  CHECK(manifest_dictionary->GetList(kCapabilityPath, &capability_list));
-
-  for (std::string service_name : browser_->options()->mojo_service_names) {
-    capability_list->AppendString(service_name);
-  }
-
-  return manifest;
+  return base::JSONReader::Read(manifest_template);
 }
 
 std::unique_ptr<base::Value>
diff --git a/headless/lib/browser/headless_tab_socket_impl.cc b/headless/lib/browser/headless_tab_socket_impl.cc
deleted file mode 100644
index 4ea3c8c1..0000000
--- a/headless/lib/browser/headless_tab_socket_impl.cc
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "headless/lib/browser/headless_tab_socket_impl.h"
-
-#include "base/stl_util.h"
-#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/web_contents.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-
-namespace headless {
-
-HeadlessTabSocketImpl::HeadlessTabSocketImpl(content::WebContents* web_contents)
-    : web_contents_(web_contents),
-      listener_(nullptr),
-      weak_ptr_factory_(this) {}
-
-HeadlessTabSocketImpl::~HeadlessTabSocketImpl() = default;
-
-// Wrangles the async responses to
-// HeadlessRenderFrameControllerImpl::InstallTabSocket for which at most one
-// should succeed.
-class TabSocketInstallationController
-    : public base::RefCounted<TabSocketInstallationController> {
- public:
-  TabSocketInstallationController(
-      int v8_execution_context_id,
-      size_t render_frame_count,
-      base::WeakPtr<HeadlessTabSocketImpl> headless_tab_socket_impl,
-      base::OnceCallback<void(bool)> callback)
-      : v8_execution_context_id_(v8_execution_context_id),
-        render_frame_count_(render_frame_count),
-        headless_tab_socket_impl_(headless_tab_socket_impl),
-        callback_(std::move(callback)),
-        success_(false) {}
-
-  void InstallTabSocketCallback(content::RenderFrameHost* render_frame_host,
-                                bool success) {
-    render_frame_count_--;
-
-    // It's possible the HeadlessTabSocketImpl went away, if that happened we
-    // don't want to pretend TabSocket installation succeeded.
-    if (!headless_tab_socket_impl_)
-      success = false;
-
-    if (success) {
-      CHECK(!success_) << "At most one InstallTabSocket call should succeed!";
-      success_ = true;
-      headless_tab_socket_impl_->v8_execution_context_id_to_render_frame_host_
-          .insert(std::make_pair(v8_execution_context_id_, render_frame_host));
-
-      std::move(callback_).Run(true);
-    } else if (render_frame_count_ == 0 && !success_) {
-      std::move(callback_).Run(false);
-    }
-  }
-
- private:
-  int v8_execution_context_id_;
-  size_t render_frame_count_;
-
-  base::WeakPtr<HeadlessTabSocketImpl> headless_tab_socket_impl_;
-  base::OnceCallback<void(bool)> callback_;
-  bool success_;
-
-  friend class base::RefCounted<TabSocketInstallationController>;
-  ~TabSocketInstallationController() = default;
-};
-
-void HeadlessTabSocketImpl::InstallHeadlessTabSocketBindings(
-    int v8_execution_context_id,
-    base::OnceCallback<void(bool)> callback) {
-  // We need to find the right RenderFrameHost to install the bindings on but
-  // the browser doesn't know which RenderFrameHost |v8_execution_context_id|
-  // corresponds to if any. So we try all of them.
-  scoped_refptr<TabSocketInstallationController>
-      tab_socket_installation_controller = new TabSocketInstallationController(
-          v8_execution_context_id, render_frame_hosts_.size(),
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback));
-  for (content::RenderFrameHost* render_frame_host : render_frame_hosts_) {
-    HeadlessRenderFrameControllerPtr& headless_render_frame_controller =
-        render_frame_controllers_[render_frame_host];
-    if (!headless_render_frame_controller.is_bound()) {
-      render_frame_host->GetRemoteInterfaces()->GetInterface(
-          &headless_render_frame_controller);
-    }
-
-    // This will only succeed if the |render_frame_host_controller| contains
-    // |v8_execution_context_id|. The TabSocketInstallationController keeps
-    // track of how many callbacks have been received and if all of them have
-    // been unsuccessful it runs |callback| with false.  If one of them succeeds
-    //  it runs |callback| with true.
-    headless_render_frame_controller->InstallTabSocket(
-        v8_execution_context_id,
-        base::BindOnce(
-            &TabSocketInstallationController::InstallTabSocketCallback,
-            tab_socket_installation_controller, render_frame_host));
-  }
-}
-
-void HeadlessTabSocketImpl::InstallMainFrameMainWorldHeadlessTabSocketBindings(
-    base::OnceCallback<void(base::Optional<int>)> callback) {
-  content::RenderFrameHost* main_frame = web_contents_->GetMainFrame();
-  HeadlessRenderFrameControllerPtr& headless_render_frame_controller =
-      render_frame_controllers_[main_frame];
-  if (!headless_render_frame_controller.is_bound()) {
-    main_frame->GetRemoteInterfaces()->GetInterface(
-        &headless_render_frame_controller);
-  }
-  headless_render_frame_controller->InstallMainWorldTabSocket(
-      base::BindOnce(&HeadlessTabSocketImpl::OnInstallMainWorldTabSocket,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void HeadlessTabSocketImpl::OnInstallMainWorldTabSocket(
-    base::OnceCallback<void(base::Optional<int>)> callback,
-    int v8_execution_context_id) {
-  if (v8_execution_context_id == -1) {
-    std::move(callback).Run(base::nullopt);
-  } else {
-    v8_execution_context_id_to_render_frame_host_.insert(
-        std::make_pair(v8_execution_context_id, web_contents_->GetMainFrame()));
-    std::move(callback).Run(v8_execution_context_id);
-  }
-}
-
-void HeadlessTabSocketImpl::SendMessageToContext(
-    const std::string& message,
-    int32_t v8_execution_context_id) {
-  auto render_frame_host = v8_execution_context_id_to_render_frame_host_.find(
-      v8_execution_context_id);
-  if (render_frame_host ==
-      v8_execution_context_id_to_render_frame_host_.end()) {
-    LOG(WARNING) << "Unknown v8_execution_context_id "
-                 << v8_execution_context_id;
-    return;
-  }
-
-  auto render_frame_controller =
-      render_frame_controllers_.find(render_frame_host->second);
-  if (render_frame_controller == render_frame_controllers_.end()) {
-    LOG(WARNING) << "Unknown RenderFrameHist " << render_frame_host->second;
-    return;
-  }
-  render_frame_controller->second->SendMessageToTabSocket(
-      message, v8_execution_context_id);
-}
-
-void HeadlessTabSocketImpl::SetListener(Listener* listener) {
-  MessageQueue messages;
-
-  {
-    base::AutoLock lock(lock_);
-    listener_ = listener;
-    if (!listener)
-      return;
-
-    std::swap(messages, from_tab_message_queue_);
-  }
-
-  for (const Message& message : messages) {
-    listener_->OnMessageFromContext(message.first, message.second);
-  }
-}
-
-void HeadlessTabSocketImpl::SendMessageToEmbedder(
-    const std::string& message,
-    int32_t v8_execution_context_id) {
-  Listener* listener = nullptr;
-  {
-    base::AutoLock lock(lock_);
-    CHECK(v8_execution_context_id_to_render_frame_host_.find(
-              v8_execution_context_id) !=
-          v8_execution_context_id_to_render_frame_host_.end())
-        << "Unknown v8_execution_context_id " << v8_execution_context_id;
-    if (listener_) {
-      listener = listener_;
-    } else {
-      from_tab_message_queue_.emplace_back(message, v8_execution_context_id);
-      return;
-    }
-  }
-
-  listener->OnMessageFromContext(message, v8_execution_context_id);
-}
-
-void HeadlessTabSocketImpl::CreateMojoService(
-    mojo::InterfaceRequest<TabSocket> request) {
-  mojo_bindings_.AddBinding(this, std::move(request));
-}
-
-void HeadlessTabSocketImpl::RenderFrameCreated(
-    content::RenderFrameHost* render_frame_host) {
-  render_frame_hosts_.insert(render_frame_host);
-}
-
-void HeadlessTabSocketImpl::RenderFrameDeleted(
-    content::RenderFrameHost* render_frame_host) {
-  // Remove all entries from |v8_execution_context_id_to_render_frame_host_|
-  // where the mapped value is |render_frame_host|.
-  base::EraseIf(v8_execution_context_id_to_render_frame_host_,
-                [render_frame_host](
-                    const std::pair<int, content::RenderFrameHost*>& pair) {
-                  return render_frame_host == pair.second;
-                });
-
-  render_frame_controllers_.erase(render_frame_host);
-  render_frame_hosts_.erase(render_frame_host);
-}
-
-}  // namespace headless
diff --git a/headless/lib/browser/headless_tab_socket_impl.h b/headless/lib/browser/headless_tab_socket_impl.h
deleted file mode 100644
index 13e4c42..0000000
--- a/headless/lib/browser/headless_tab_socket_impl.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef HEADLESS_LIB_BROWSER_HEADLESS_TAB_SOCKET_IMPL_H_
-#define HEADLESS_LIB_BROWSER_HEADLESS_TAB_SOCKET_IMPL_H_
-
-#include <list>
-
-#include "base/synchronization/lock.h"
-#include "headless/lib/headless_render_frame_controller.mojom.h"
-#include "headless/lib/tab_socket.mojom.h"
-#include "headless/public/headless_tab_socket.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-
-namespace content {
-class RenderFrameHost;
-class WebContents;
-}  // namespace content
-
-namespace headless {
-
-class HeadlessTabSocketImpl : public HeadlessTabSocket, public TabSocket {
- public:
-  explicit HeadlessTabSocketImpl(content::WebContents* web_contents);
-  ~HeadlessTabSocketImpl() override;
-
-  // HeadlessTabSocket implementation:
-  void InstallHeadlessTabSocketBindings(
-      int v8_execution_context_id,
-      base::OnceCallback<void(bool)> callback) override;
-  void InstallMainFrameMainWorldHeadlessTabSocketBindings(
-      base::OnceCallback<void(base::Optional<int>)> callback) override;
-  void SendMessageToContext(const std::string& message,
-                            int v8_execution_context_id) override;
-  void SetListener(Listener* listener) override;
-
-  // TabSocket implementation:
-  void SendMessageToEmbedder(const std::string& message,
-                             int32_t v8_execution_context_id) override;
-
-  void CreateMojoService(mojo::InterfaceRequest<TabSocket> request);
-
-  void RenderFrameCreated(content::RenderFrameHost* render_frame_host);
-  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host);
-
- private:
-  friend class TabSocketInstallationController;
-
-  void OnInstallMainWorldTabSocket(
-      base::OnceCallback<void(base::Optional<int>)> callback,
-      int world_id);
-
-  base::Lock lock_;  // Protects everything below.
-  using Message = std::pair<std::string, int>;
-  using MessageQueue = std::list<Message>;
-
-  MessageQueue from_tab_message_queue_;
-  content::WebContents* web_contents_;  // NOT OWNED
-  Listener* listener_;  // NOT OWNED
-
-  mojo::BindingSet<TabSocket> mojo_bindings_;
-
-  std::set<content::RenderFrameHost*> render_frame_hosts_;
-  std::map<int, content::RenderFrameHost*>
-      v8_execution_context_id_to_render_frame_host_;
-  std::map<content::RenderFrameHost*, HeadlessRenderFrameControllerPtr>
-      render_frame_controllers_;
-  base::WeakPtrFactory<HeadlessTabSocketImpl> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(HeadlessTabSocketImpl);
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_LIB_BROWSER_HEADLESS_TAB_SOCKET_IMPL_H_
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index c447659..51d5010e 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -34,7 +34,6 @@
 #include "headless/lib/browser/headless_browser_context_impl.h"
 #include "headless/lib/browser/headless_browser_impl.h"
 #include "headless/lib/browser/headless_browser_main_parts.h"
-#include "headless/lib/browser/headless_tab_socket_impl.h"
 #include "headless/lib/browser/protocol/headless_handler.h"
 #include "headless/public/internal/headless_devtools_client_impl.h"
 #include "printing/buildflags/buildflags.h"
@@ -139,8 +138,6 @@
         HeadlessWebContentsImpl* child_contents = HeadlessWebContentsImpl::From(
             headless_web_contents_->browser_context()
                 ->CreateWebContentsBuilder()
-                .SetAllowTabSockets(
-                    !!headless_web_contents_->GetHeadlessTabSocket())
                 .SetWindowSize(source->GetContainerBounds().size())
                 .Build());
         headless_web_contents_->browser_context()->NotifyChildContentsCreated(
@@ -204,17 +201,6 @@
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
-namespace {
-
-void CreateTabSocketMojoServiceForContents(
-    HeadlessWebContents* web_contents,
-    mojo::ScopedMessagePipeHandle handle) {
-  HeadlessWebContentsImpl::From(web_contents)
-      ->CreateTabSocketMojoService(std::move(handle));
-}
-
-}  // namespace
-
 struct HeadlessWebContentsImpl::PendingFrame {
  public:
   PendingFrame() = default;
@@ -250,17 +236,6 @@
           content::WebContents::Create(create_params),
           builder->browser_context_));
 
-  if (builder->tab_sockets_allowed_) {
-    headless_web_contents->headless_tab_socket_ =
-        std::make_unique<HeadlessTabSocketImpl>(
-            headless_web_contents->web_contents_.get());
-    headless_web_contents->inject_mojo_services_into_isolated_world_ = true;
-
-    builder->mojo_services_.emplace_back(
-        TabSocket::Name_, base::Bind(&CreateTabSocketMojoServiceForContents));
-  }
-
-  headless_web_contents->mojo_services_ = std::move(builder->mojo_services_);
   headless_web_contents->begin_frame_control_enabled_ =
       builder->enable_begin_frame_control_ ||
       headless_web_contents->browser()->options()->enable_begin_frame_control;
@@ -283,15 +258,6 @@
   child->begin_frame_control_enabled_ = parent->begin_frame_control_enabled_;
   child->InitializeWindow(child->web_contents_->GetContainerBounds());
 
-  // Copy mojo services and tab socket settings from parent.
-  child->mojo_services_ = parent->mojo_services_;
-  if (parent->headless_tab_socket_) {
-    child->headless_tab_socket_ =
-        std::make_unique<HeadlessTabSocketImpl>(child->web_contents_.get());
-    child->inject_mojo_services_into_isolated_world_ =
-        parent->inject_mojo_services_into_isolated_world_;
-  }
-
   // There may already be frames, so make sure they also have our services.
   for (content::RenderFrameHost* frame_host :
        child->web_contents_->GetAllFrames())
@@ -328,7 +294,6 @@
       web_contents_(std::move(web_contents)),
       agent_host_(
           content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get())),
-      inject_mojo_services_into_isolated_world_(false),
       browser_context_(browser_context),
       render_process_host_(web_contents_->GetMainFrame()->GetProcess()),
       weak_ptr_factory_(this) {
@@ -356,48 +321,17 @@
   }
 }
 
-void HeadlessWebContentsImpl::CreateTabSocketMojoService(
-    mojo::ScopedMessagePipeHandle handle) {
-  headless_tab_socket_->CreateMojoService(TabSocketRequest(std::move(handle)));
-}
-
-void HeadlessWebContentsImpl::CreateMojoService(
-    const MojoService::ServiceFactoryCallback& service_factory,
-    mojo::ScopedMessagePipeHandle handle) {
-  service_factory.Run(this, std::move(handle));
-}
-
 void HeadlessWebContentsImpl::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
-  for (const MojoService& service : mojo_services_) {
-    registry_.AddInterface(
-        service.service_name,
-        base::Bind(&HeadlessWebContentsImpl::CreateMojoService,
-                   base::Unretained(this), service.service_factory),
-        browser()->BrowserMainThread());
-  }
-
   browser_context_->SetDevToolsFrameToken(
       render_frame_host->GetProcess()->GetID(),
       render_frame_host->GetRoutingID(),
       render_frame_host->GetDevToolsFrameToken(),
       render_frame_host->GetFrameTreeNodeId());
-
-  if (headless_tab_socket_)
-    headless_tab_socket_->RenderFrameCreated(render_frame_host);
-}
-
-void HeadlessWebContentsImpl::OnInterfaceRequestFromFrame(
-    content::RenderFrameHost* render_frame_host,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle* interface_pipe) {
-  registry_.TryBindInterface(interface_name, interface_pipe);
 }
 
 void HeadlessWebContentsImpl::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
-  if (headless_tab_socket_)
-    headless_tab_socket_->RenderFrameDeleted(render_frame_host);
   browser_context_->RemoveDevToolsFrameToken(
       render_frame_host->GetProcess()->GetID(),
       render_frame_host->GetRoutingID(),
@@ -540,10 +474,6 @@
   return browser_context_;
 }
 
-HeadlessTabSocket* HeadlessWebContentsImpl::GetHeadlessTabSocket() const {
-  return headless_tab_socket_.get();
-}
-
 void HeadlessWebContentsImpl::OnDisplayDidFinishFrame(
     const viz::BeginFrameAck& ack) {
   TRACE_EVENT2("headless", "HeadlessWebContentsImpl::OnDisplayDidFinishFrame",
@@ -669,12 +599,6 @@
   return *this;
 }
 
-HeadlessWebContents::Builder& HeadlessWebContents::Builder::SetAllowTabSockets(
-    bool tab_sockets_allowed) {
-  tab_sockets_allowed_ = tab_sockets_allowed;
-  return *this;
-}
-
 HeadlessWebContents::Builder&
 HeadlessWebContents::Builder::SetEnableBeginFrameControl(
     bool enable_begin_frame_control) {
@@ -686,16 +610,4 @@
   return browser_context_->CreateWebContents(this);
 }
 
-HeadlessWebContents::Builder::MojoService::MojoService() = default;
-
-HeadlessWebContents::Builder::MojoService::MojoService(
-    const MojoService& other) = default;
-
-HeadlessWebContents::Builder::MojoService::MojoService(
-    const std::string& service_name,
-    const ServiceFactoryCallback& service_factory)
-    : service_name(service_name), service_factory(service_factory) {}
-
-HeadlessWebContents::Builder::MojoService::~MojoService() = default;
-
 }  // namespace headless
diff --git a/headless/lib/browser/headless_web_contents_impl.h b/headless/lib/browser/headless_web_contents_impl.h
index 19ea985c..467275c8 100644
--- a/headless/lib/browser/headless_web_contents_impl.h
+++ b/headless/lib/browser/headless_web_contents_impl.h
@@ -19,7 +19,6 @@
 #include "headless/public/headless_devtools_target.h"
 #include "headless/public/headless_export.h"
 #include "headless/public/headless_web_contents.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
 #include "ui/compositor/external_begin_frame_client.h"
 
 class SkBitmap;
@@ -36,7 +35,6 @@
 namespace headless {
 class HeadlessBrowser;
 class HeadlessBrowserImpl;
-class HeadlessTabSocketImpl;
 
 // Exported for tests.
 class HEADLESS_EXPORT HeadlessWebContentsImpl
@@ -65,7 +63,6 @@
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
   HeadlessDevToolsTarget* GetDevToolsTarget() override;
-  HeadlessTabSocket* GetHeadlessTabSocket() const override;
   int GetMainFrameRenderProcessId() const override;
   int GetMainFrameTreeNodeId() const override;
   std::string GetMainFrameDevToolsId() const override;
@@ -91,10 +88,6 @@
   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
   void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void RenderViewReady() override;
-  void OnInterfaceRequestFromFrame(
-      content::RenderFrameHost* render_frame_host,
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle* interface_pipe) override;
 
   // ui::ExternalBeginFrameClient implementation:
   void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override;
@@ -129,8 +122,6 @@
   // Set bounds of WebContent's platform window.
   void SetBounds(const gfx::Rect& bounds);
 
-  void CreateTabSocketMojoService(mojo::ScopedMessagePipeHandle handle);
-
   bool begin_frame_control_enabled() const {
     return begin_frame_control_enabled_;
   }
@@ -159,11 +150,6 @@
 
   void InitializeWindow(const gfx::Rect& initial_bounds);
 
-  using MojoService = HeadlessWebContents::Builder::MojoService;
-  void CreateMojoService(
-      const MojoService::ServiceFactoryCallback& service_factory,
-      mojo::ScopedMessagePipeHandle handle);
-
   void PendingFrameReadbackComplete(PendingFrame* pending_frame,
                                     const SkBitmap& bitmap);
 
@@ -179,11 +165,8 @@
   std::unique_ptr<HeadlessWindowTreeHost> window_tree_host_;
   int window_id_ = 0;
   std::string window_state_;
-  std::unique_ptr<HeadlessTabSocketImpl> headless_tab_socket_;
   std::unique_ptr<content::WebContents> web_contents_;
   scoped_refptr<content::DevToolsAgentHost> agent_host_;
-  std::list<MojoService> mojo_services_;
-  bool inject_mojo_services_into_isolated_world_;
   bool devtools_target_ready_notification_sent_ = false;
   bool render_process_exited_ = false;
 
@@ -196,8 +179,6 @@
 
   base::Closure quit_closure_;
 
-  service_manager::BinderRegistry registry_;
-
   base::WeakPtrFactory<HeadlessWebContentsImpl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(HeadlessWebContentsImpl);
diff --git a/headless/lib/headless_render_frame_controller.mojom b/headless/lib/headless_render_frame_controller.mojom
deleted file mode 100644
index 3b6b061a..0000000
--- a/headless/lib/headless_render_frame_controller.mojom
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module headless;
-
-import "mojo/public/mojom/base/big_string.mojom";
-
-interface HeadlessRenderFrameController {
-  // Installs TabSocket bindings into a specified execution context.
-  InstallTabSocket(int32 v8_execution_context_id) => (bool success);
-
-  // Installs TabSocket bindings into the main world. This is useful if you
-  // don't know the execution context id (e.g. you don't have devtools
-  // connected).
-  InstallMainWorldTabSocket() => (int32 v8_execution_context_id);
-
-  // Send a message from the C++ embedder to the Tab.
-  SendMessageToTabSocket(mojo_base.mojom.BigString message,
-                         int32 v8_execution_context_id);
-
-  // To send a message from tab to the embedder use
-  // TabSocket::SendMessageToEmbedder.
-};
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc
index 6bd4265..9b0b059 100644
--- a/headless/lib/headless_web_contents_browsertest.cc
+++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -33,7 +33,6 @@
 #include "headless/public/headless_web_contents.h"
 #include "headless/public/util/testing/test_in_memory_protocol_handler.h"
 #include "headless/test/headless_browser_test.h"
-#include "headless/test/tab_socket_test.h"
 #include "printing/buildflags/buildflags.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -136,193 +135,6 @@
   browser_context->RemoveObserver(&observer);
 }
 
-class HeadlessWindowOpenTabSocketTest : public HeadlessBrowserTest,
-                                        public HeadlessTabSocket::Listener,
-                                        public HeadlessBrowserContext::Observer,
-                                        public HeadlessWebContents::Observer,
-                                        public runtime::Observer {
- public:
-  HeadlessWindowOpenTabSocketTest()
-      : devtools_client_(HeadlessDevToolsClient::Create()) {}
-
-  void SetUp() override {
-    options()->mojo_service_names.insert("headless::TabSocket");
-    HeadlessBrowserTest::SetUp();
-  }
-
-  // HeadlessTabSocket::Listener implementation.
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    message_ = message;
-    FinishAsynchronousTest();
-  }
-
-  // HeadlessBrowserContext::Observer implementation.
-  void OnChildContentsCreated(HeadlessWebContents* parent,
-                              HeadlessWebContents* child) override {
-    EXPECT_EQ(nullptr, child_);
-    child_ = child;
-    child_->AddObserver(this);
-  }
-
-  // HeadlessWebContents::Observer implementation.
-  void DevToolsTargetReady() override {
-    child_->RemoveObserver(this);
-
-    // Verify tab socket of child_contents works.
-    child_->GetDevToolsTarget()->AttachClient(devtools_client_.get());
-
-    devtools_client_->GetPage()->Enable();
-    devtools_client_->GetPage()->GetExperimental()->GetResourceTree(
-        page::GetResourceTreeParams::Builder().Build(),
-        base::BindOnce(&HeadlessWindowOpenTabSocketTest::OnResourceTree,
-                       base::Unretained(this)));
-  }
-
-  void OnResourceTree(std::unique_ptr<page::GetResourceTreeResult> result) {
-    child_frame_id_ = result->GetFrameTree()->GetFrame()->GetId();
-    devtools_client_->GetRuntime()->AddObserver(this);
-    // This will trigger OnExecutionContextCreated getting called for all
-    // existing contexts.
-    devtools_client_->GetRuntime()->Enable();
-  }
-
-  // runtime::Observer implementation.
-  void OnExecutionContextCreated(
-      const runtime::ExecutionContextCreatedParams& params) override {
-    std::string frame_id;
-    if (!params.GetContext()->HasAuxData())
-      return;
-
-    const base::Value* frame_id_value =
-        params.GetContext()->GetAuxData()->FindKey("frameId");
-    if (!frame_id_value || frame_id_value->GetString() != *child_frame_id_)
-      return;
-
-    child_frame_execution_context_id_ = params.GetContext()->GetId();
-
-    HeadlessTabSocket* tab_socket = child_->GetHeadlessTabSocket();
-    CHECK(tab_socket);
-    tab_socket->InstallHeadlessTabSocketBindings(
-        *child_frame_execution_context_id_,
-        base::BindOnce(&HeadlessWindowOpenTabSocketTest::OnTabSocketInstalled,
-                       base::Unretained(this)));
-  }
-
-  void OnTabSocketInstalled(bool success) {
-    ASSERT_TRUE(success);
-    HeadlessTabSocket* tab_socket = child_->GetHeadlessTabSocket();
-    CHECK(tab_socket);
-    tab_socket->SendMessageToContext("One", *child_frame_execution_context_id_);
-    tab_socket->SetListener(this);
-
-    devtools_client_->GetRuntime()->Evaluate(
-        R"(window.TabSocket.onmessage =
-            function(message) {
-              window.TabSocket.send('Embedder sent us: ' + message);
-            };
-          )",
-        base::BindOnce(&HeadlessWindowOpenTabSocketTest::OnEvaluateResult,
-                       base::Unretained(this)));
-  }
-
-  void OnEvaluateResult(std::unique_ptr<runtime::EvaluateResult> result) {
-    child_->GetDevToolsTarget()->DetachClient(devtools_client_.get());
-  }
-
- protected:
-  std::string message_;
-  base::Optional<std::string> child_frame_id_;
-  base::Optional<int> child_frame_execution_context_id_;
-  HeadlessWebContents* child_ = nullptr;
-  std::unique_ptr<HeadlessDevToolsClient> devtools_client_;
-};
-
-IN_PROC_BROWSER_TEST_F(HeadlessWindowOpenTabSocketTest,
-                       WindowOpenWithTabSocket) {
-  EXPECT_TRUE(embedded_test_server()->Start());
-
-  HeadlessBrowserContext* browser_context =
-      browser()->CreateBrowserContextBuilder().Build();
-  browser_context->AddObserver(this);
-
-  HeadlessWebContents* web_contents =
-      browser_context->CreateWebContentsBuilder()
-          .SetAllowTabSockets(true)
-          .SetInitialURL(embedded_test_server()->GetURL("/window_open.html"))
-          .Build();
-  EXPECT_TRUE(WaitForLoad(web_contents));
-
-  EXPECT_EQ(2u, browser_context->GetAllWebContents().size());
-  EXPECT_NE(nullptr, child_);
-
-  RunAsynchronousTest();
-  EXPECT_EQ("Embedder sent us: One", message_);
-
-  browser_context->RemoveObserver(this);
-}
-
-class HeadlessNoDevToolsTabSocketTest : public HeadlessBrowserTest,
-                                        public HeadlessTabSocket::Listener {
- public:
-  HeadlessNoDevToolsTabSocketTest() = default;
-
-  void SetUp() override {
-    options()->mojo_service_names.insert("headless::TabSocket");
-    HeadlessBrowserTest::SetUp();
-  }
-
-  // HeadlessTabSocket::Listener implementation.
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    EXPECT_EQ(*execution_context_id_, execution_context_id);
-    messages_.push_back(message);
-
-    if (messages_.size() == 2) {
-      EXPECT_THAT(messages_,
-                  ElementsAre("Hello world!", "Embedder sent us: One"));
-      FinishAsynchronousTest();
-    }
-  }
-
-  void OnInstalledHeadlessTabSocket(base::Optional<int> execution_context_id) {
-    EXPECT_TRUE(!!execution_context_id);
-    if (!execution_context_id) {
-      FinishAsynchronousTest();
-    } else {
-      execution_context_id_ = execution_context_id;
-      tab_socket_->SendMessageToContext("One", *execution_context_id);
-    }
-  }
-
-  std::vector<std::string> messages_;
-  HeadlessTabSocket* tab_socket_;
-  base::Optional<int> execution_context_id_;
-};
-
-IN_PROC_BROWSER_TEST_F(HeadlessNoDevToolsTabSocketTest, Test) {
-  EXPECT_TRUE(embedded_test_server()->Start());
-
-  HeadlessBrowserContext* browser_context =
-      browser()->CreateBrowserContextBuilder().Build();
-
-  HeadlessWebContents* web_contents =
-      browser_context->CreateWebContentsBuilder()
-          .SetAllowTabSockets(true)
-          .SetInitialURL(embedded_test_server()->GetURL("/tabsocket.html"))
-          .Build();
-
-  tab_socket_ = web_contents->GetHeadlessTabSocket();
-  CHECK(tab_socket_);
-  tab_socket_->InstallMainFrameMainWorldHeadlessTabSocketBindings(
-      base::BindOnce(
-          &HeadlessNoDevToolsTabSocketTest::OnInstalledHeadlessTabSocket,
-          base::Unretained(this)));
-  tab_socket_->SetListener(this);
-
-  RunAsynchronousTest();
-}
-
 IN_PROC_BROWSER_TEST_F(HeadlessWebContentsTest,
                        FocusOfHeadlessWebContents_IsIndependent) {
   EXPECT_TRUE(embedded_test_server()->Start());
@@ -577,366 +389,6 @@
   }
 };
 
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsSecurityTest);
-
-class GetHeadlessTabSocketButNoTabSocket
-    : public HeadlessAsyncDevTooledBrowserTest {
- public:
-  void SetUp() override {
-    options()->mojo_service_names.insert("headless::TabSocket");
-    HeadlessAsyncDevTooledBrowserTest::SetUp();
-  }
-
-  void RunDevTooledTest() override {
-    ASSERT_THAT(web_contents_->GetHeadlessTabSocket(), testing::IsNull());
-    FinishAsynchronousTest();
-  }
-
-  bool GetAllowTabSockets() override { return false; }
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(GetHeadlessTabSocketButNoTabSocket);
-
-class MainWorldHeadlessTabSocketTest : public TabSocketTest {
- public:
-  void RunTabSocketTest() override {
-    CreateMainWorldTabSocket(
-        main_frame_id(),
-        base::BindOnce(
-            &MainWorldHeadlessTabSocketTest::OnInstalledHeadlessTabSocket,
-            base::Unretained(this)));
-  }
-
-  void OnInstalledHeadlessTabSocket(int execution_context_id) {
-    devtools_client_->GetRuntime()->Evaluate(
-        R"(window.TabSocket.onmessage =
-            function(message) {
-              window.TabSocket.send('Embedder sent us: ' + message);
-            };
-          )",
-        base::BindOnce(
-            &MainWorldHeadlessTabSocketTest::FailOnJsEvaluateException,
-            base::Unretained(this)));
-
-    HeadlessTabSocket* headless_tab_socket =
-        web_contents_->GetHeadlessTabSocket();
-    DCHECK(headless_tab_socket);
-
-    headless_tab_socket->SendMessageToContext("One", execution_context_id);
-    headless_tab_socket->SendMessageToContext("Two", execution_context_id);
-    headless_tab_socket->SendMessageToContext("Three", execution_context_id);
-    headless_tab_socket->SetListener(this);
-    main_frame_execution_context_id_ = execution_context_id;
-  }
-
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    EXPECT_EQ(execution_context_id, *main_frame_execution_context_id_);
-    messages_.push_back(message);
-    if (messages_.size() == 3u) {
-      EXPECT_THAT(messages_,
-                  ElementsAre("Embedder sent us: One", "Embedder sent us: Two",
-                              "Embedder sent us: Three"));
-      FinishAsynchronousTest();
-    }
-  }
-
- private:
-  std::vector<std::string> messages_;
-  base::Optional<int> main_frame_execution_context_id_;
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(MainWorldHeadlessTabSocketTest);
-
-class MainWorldHeadlessTabSocketBindingsNotInstalledTest
-    : public TabSocketTest {
- public:
-  void RunTabSocketTest() override {
-    CreateIsolatedWorldTabSocket(
-        "Test World", main_frame_id(),
-        base::BindOnce(&MainWorldHeadlessTabSocketBindingsNotInstalledTest::
-                           OnIsolatedWorldCreated,
-                       base::Unretained(this)));
-  }
-
-  void OnIsolatedWorldCreated(int execution_context_id) {
-    // We expect this to fail because TabSocket bindings where injected into the
-    // isolated world not the main world.
-    devtools_client_->GetRuntime()->Evaluate(
-        "window.TabSocket.send('This should not work!');",
-        base::BindOnce(&MainWorldHeadlessTabSocketBindingsNotInstalledTest::
-                           ExpectJsException,
-                       base::Unretained(this)));
-
-    HeadlessTabSocket* headless_tab_socket =
-        web_contents_->GetHeadlessTabSocket();
-    DCHECK(headless_tab_socket);
-
-    headless_tab_socket->SetListener(this);
-  }
-
-  void OnMessageFromContext(const std::string&, int) override {
-    FinishAsynchronousTest();
-    FAIL() << "Should not receive a message from the tab!";
-  }
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(
-    MainWorldHeadlessTabSocketBindingsNotInstalledTest);
-
-class IsolatedWorldHeadlessTabSocketTest : public TabSocketTest {
- public:
-  void RunTabSocketTest() override {
-    CreateIsolatedWorldTabSocket(
-        "Test World", main_frame_id(),
-        base::BindOnce(
-            &IsolatedWorldHeadlessTabSocketTest::OnIsolatedWorldCreated,
-            base::Unretained(this)));
-  }
-
-  void OnIsolatedWorldCreated(int execution_context_id) {
-    main_frame_execution_context_id_ = execution_context_id;
-
-    HeadlessTabSocket* headless_tab_socket =
-        web_contents_->GetHeadlessTabSocket();
-    DCHECK(headless_tab_socket);
-    headless_tab_socket->SendMessageToContext(
-        "Hello!!!", *main_frame_execution_context_id_);
-    headless_tab_socket->SetListener(this);
-
-    devtools_client_->GetRuntime()->Evaluate(
-        runtime::EvaluateParams::Builder()
-            .SetExpression(
-                R"(window.TabSocket.onmessage =
-                    function(message) {
-                      TabSocket.send('Embedder sent us: ' + message);
-                    };
-                  )")
-            .SetContextId(GetV8ExecutionContextIdByWorldName("Test World"))
-            .Build(),
-        base::BindOnce(
-            &IsolatedWorldHeadlessTabSocketTest::FailOnJsEvaluateException,
-            base::Unretained(this)));
-  }
-
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    EXPECT_EQ("Embedder sent us: Hello!!!", message);
-    EXPECT_EQ(*main_frame_execution_context_id_, execution_context_id);
-    FinishAsynchronousTest();
-  }
-
-  base::Optional<int> main_frame_execution_context_id_;
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(IsolatedWorldHeadlessTabSocketTest);
-
-class MultipleIframesIsolatedWorldHeadlessTabSocketTest : public TabSocketTest {
- public:
-  void RunTabSocketTest() override {
-    EXPECT_TRUE(embedded_test_server()->Start());
-    devtools_client_->GetPage()->Navigate(
-        embedded_test_server()->GetURL("/two_iframes.html").spec());
-  }
-
-  void OnLoadEventFired(const page::LoadEventFiredParams& params) override {
-    devtools_client_->GetPage()->Disable();
-    devtools_client_->GetPage()->RemoveObserver(this);
-    devtools_client_->GetDOMSnapshot()->GetExperimental()->GetSnapshot(
-        dom_snapshot::GetSnapshotParams::Builder()
-            .SetComputedStyleWhitelist(std::vector<std::string>())
-            .Build(),
-        base::BindOnce(
-            &MultipleIframesIsolatedWorldHeadlessTabSocketTest::OnSnapshot,
-            base::Unretained(this)));
-  }
-
-  void OnSnapshot(std::unique_ptr<dom_snapshot::GetSnapshotResult> result) {
-    bool seen_main_frame = false;
-    for (const auto& node : *result->GetDomNodes()) {
-      if (node->HasFrameId()) {
-        std::string frame_name;
-        if (node->GetNodeName() == "IFRAME") {
-          // Use the iframe id attribute for the name.
-          for (const auto& key_value : *node->GetAttributes()) {
-            if (key_value->GetName() == "id") {
-              frame_name = key_value->GetValue();
-            }
-          }
-          CHECK(!frame_name.empty());
-        } else {
-          if (seen_main_frame)
-            continue;
-          seen_main_frame = true;
-          frame_name = "main frame";
-        }
-        CreateIsolatedWorldTabSocket(
-            frame_name, node->GetFrameId(),
-            base::BindOnce(&MultipleIframesIsolatedWorldHeadlessTabSocketTest::
-                               OnIsolatedWorldCreated,
-                           base::Unretained(this), frame_name));
-      }
-    }
-  }
-
-  void OnIsolatedWorldCreated(std::string frame_name,
-                              int execution_context_id) {
-    HeadlessTabSocket* headless_tab_socket =
-        web_contents_->GetHeadlessTabSocket();
-    DCHECK(headless_tab_socket);
-    headless_tab_socket->SendMessageToContext("Hello!!!", execution_context_id);
-    headless_tab_socket->SetListener(this);
-
-    devtools_client_->GetRuntime()->Evaluate(
-        runtime::EvaluateParams::Builder()
-            .SetExpression(base::StringPrintf(
-                R"(window.TabSocket.onmessage =
-                    function(message) {
-                      TabSocket.send('Echo from %s: ' + message);
-                    };
-                  )",
-                frame_name.c_str()))
-            .SetContextId(execution_context_id)
-            .Build(),
-        base::BindOnce(&MultipleIframesIsolatedWorldHeadlessTabSocketTest::
-                           FailOnJsEvaluateException,
-                       base::Unretained(this)));
-  }
-
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    messages_.push_back(message);
-    if (messages_.size() < 3)
-      return;
-    EXPECT_THAT(messages_,
-                UnorderedElementsAre("Echo from main frame: Hello!!!",
-                                     "Echo from iframe1: Hello!!!",
-                                     "Echo from iframe2: Hello!!!"));
-    FinishAsynchronousTest();
-  }
-
-  std::vector<std::string> messages_;
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(
-    MultipleIframesIsolatedWorldHeadlessTabSocketTest);
-
-class SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest
-    : public TabSocketTest {
- public:
-  void RunTabSocketTest() override {
-    CreateIsolatedWorldTabSocket(
-        "Isolated World 1", main_frame_id(),
-        base::BindOnce(&SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest::
-                           OnIsolatedWorldCreated,
-                       base::Unretained(this), "Isolated World 1"));
-
-    CreateIsolatedWorldTabSocket(
-        "Isolated World 2", main_frame_id(),
-        base::BindOnce(&SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest::
-                           OnIsolatedWorldCreated,
-                       base::Unretained(this), "Isolated World 2"));
-
-    CreateIsolatedWorldTabSocket(
-        "Isolated World 3", main_frame_id(),
-        base::BindOnce(&SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest::
-                           OnIsolatedWorldCreated,
-                       base::Unretained(this), "Isolated World 3"));
-  }
-
-  void OnIsolatedWorldCreated(std::string frame_name,
-                              int execution_context_id) {
-    HeadlessTabSocket* headless_tab_socket =
-        web_contents_->GetHeadlessTabSocket();
-    DCHECK(headless_tab_socket);
-    headless_tab_socket->SendMessageToContext("Hello!!!", execution_context_id);
-    headless_tab_socket->SetListener(this);
-
-    devtools_client_->GetRuntime()->Evaluate(
-        runtime::EvaluateParams::Builder()
-            .SetExpression(base::StringPrintf(
-                R"(window.TabSocket.onmessage =
-                    function(message) {
-                      TabSocket.send('Echo from %s: ' + message);
-                    };
-                  )",
-                frame_name.c_str()))
-            .SetContextId(execution_context_id)
-            .Build(),
-        base::BindOnce(&SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest::
-                           FailOnJsEvaluateException,
-                       base::Unretained(this)));
-  }
-
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    messages_.push_back(message);
-    if (messages_.size() < 3)
-      return;
-    EXPECT_THAT(messages_,
-                UnorderedElementsAre("Echo from Isolated World 1: Hello!!!",
-                                     "Echo from Isolated World 2: Hello!!!",
-                                     "Echo from Isolated World 3: Hello!!!"));
-    FinishAsynchronousTest();
-  }
-
-  std::vector<std::string> messages_;
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(
-    SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest);
-
-class LargeStringTabSocketTest : public TabSocketTest {
- public:
-  void RunTabSocketTest() override {
-    CreateMainWorldTabSocket(
-        main_frame_id(),
-        base::BindOnce(&LargeStringTabSocketTest::OnInstalledHeadlessTabSocket,
-                       base::Unretained(this)));
-  }
-
-  void OnInstalledHeadlessTabSocket(int execution_context_id) {
-    devtools_client_->GetRuntime()->Evaluate(
-        R"(window.TabSocket.onmessage =
-            function(message) {
-              window.TabSocket.send('Embedder sent us: ' + message);
-            };
-          )",
-        base::BindOnce(&LargeStringTabSocketTest::FailOnJsEvaluateException,
-                       base::Unretained(this)));
-
-    HeadlessTabSocket* headless_tab_socket =
-        web_contents_->GetHeadlessTabSocket();
-    DCHECK(headless_tab_socket);
-
-    std::string big_string;
-    big_string.reserve(IPC::Channel::kMaximumMessageSize);
-    for (size_t i = 0; i < IPC::Channel::kMaximumMessageSize; i++) {
-      big_string.push_back('A' + (i % 24));
-    }
-
-    headless_tab_socket->SendMessageToContext(big_string, execution_context_id);
-    headless_tab_socket->SetListener(this);
-    main_frame_execution_context_id_ = execution_context_id;
-  }
-
-  void OnMessageFromContext(const std::string& message,
-                            int execution_context_id) override {
-    EXPECT_EQ(execution_context_id, *main_frame_execution_context_id_);
-    messages_.push_back(message);
-    if (messages_.size() == 1u) {
-      EXPECT_EQ(18 + IPC::Channel::kMaximumMessageSize, messages_[0].size());
-      FinishAsynchronousTest();
-    }
-  }
-
- private:
-  std::vector<std::string> messages_;
-  base::Optional<int> main_frame_execution_context_id_;
-};
-
-HEADLESS_ASYNC_DEVTOOLED_TEST_F(LargeStringTabSocketTest);
-
 // Regression test for https://crbug.com/733569.
 class HeadlessWebContentsRequestStorageQuotaTest
     : public HeadlessAsyncDevTooledBrowserTest,
diff --git a/headless/lib/renderer/headless_content_renderer_client.cc b/headless/lib/renderer/headless_content_renderer_client.cc
index 6af167a..4d972d67 100644
--- a/headless/lib/renderer/headless_content_renderer_client.cc
+++ b/headless/lib/renderer/headless_content_renderer_client.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "headless/lib/renderer/headless_render_frame_controller_impl.h"
 #include "printing/buildflags/buildflags.h"
 
 #if BUILDFLAG(ENABLE_PRINTING)
@@ -26,7 +25,6 @@
   new printing::PrintRenderFrameHelper(
       render_frame, std::make_unique<HeadlessPrintRenderFrameHelperDelegate>());
 #endif
-  new HeadlessRenderFrameControllerImpl(render_frame);
 }
 
 }  // namespace headless
diff --git a/headless/lib/renderer/headless_render_frame_controller_impl.cc b/headless/lib/renderer/headless_render_frame_controller_impl.cc
deleted file mode 100644
index 9f695f6..0000000
--- a/headless/lib/renderer/headless_render_frame_controller_impl.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "headless/lib/renderer/headless_render_frame_controller_impl.h"
-
-#include "content/public/common/isolated_world_ids.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-#include "v8/include/v8-inspector.h"
-
-namespace headless {
-
-HeadlessRenderFrameControllerImpl::HeadlessRenderFrameControllerImpl(
-    content::RenderFrame* render_frame)
-    : content::RenderFrameObserver(render_frame),
-      render_frame_(render_frame),
-      weak_ptr_factory_(this) {
-  registry_.AddInterface(base::Bind(
-      &HeadlessRenderFrameControllerImpl::OnRenderFrameControllerRequest,
-      base::Unretained(this)));
-}
-
-HeadlessRenderFrameControllerImpl::~HeadlessRenderFrameControllerImpl() =
-    default;
-
-void HeadlessRenderFrameControllerImpl::OnRenderFrameControllerRequest(
-    HeadlessRenderFrameControllerRequest request) {
-  headless_render_frame_controller_bindings_.AddBinding(this,
-                                                        std::move(request));
-}
-
-void HeadlessRenderFrameControllerImpl::InstallTabSocket(
-    int32_t execution_context_id,
-    InstallTabSocketCallback callback) {
-  auto find_it = tab_socket_bindings_.find(execution_context_id);
-  if (find_it == tab_socket_bindings_.end()) {
-    LOG(WARNING) << "InstallTabSocket failed, unknown execution_context_id "
-                 << execution_context_id;
-    std::move(callback).Run(false);
-  } else {
-    std::move(callback).Run(find_it->second.InitializeTabSocketBindings());
-  }
-}
-
-void HeadlessRenderFrameControllerImpl::InstallMainWorldTabSocket(
-    InstallMainWorldTabSocketCallback callback) {
-  // Check any pre-existing script contexts.
-  for (auto& pair : tab_socket_bindings_) {
-    if (pair.second.world_id() == content::ISOLATED_WORLD_ID_GLOBAL) {
-      std::move(callback).Run(
-          pair.second.InitializeTabSocketBindings() ? pair.first : -1);
-      return;
-    }
-  }
-  pending_install_main_world_tab_socket_callback_ = std::move(callback);
-}
-
-void HeadlessRenderFrameControllerImpl::SendMessageToTabSocket(
-    const std::string& message,
-    int32_t world_id) {
-  auto find_it = tab_socket_bindings_.find(world_id);
-  if (find_it == tab_socket_bindings_.end()) {
-    LOG(WARNING) << "Dropping message for " << world_id
-                 << " because the world doesn't exist.";
-    return;
-  }
-
-  find_it->second.OnMessageFromEmbedder(message);
-}
-
-void HeadlessRenderFrameControllerImpl::OnInterfaceRequestForFrame(
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle* interface_pipe) {
-  registry_.TryBindInterface(interface_name, interface_pipe);
-}
-
-void HeadlessRenderFrameControllerImpl::DidCreateScriptContext(
-    v8::Local<v8::Context> context,
-    int world_id) {
-  int v8_execution_context_id =
-      v8_inspector::V8ContextInfo::executionContextId(context);
-  auto find_it = tab_socket_bindings_.find(v8_execution_context_id);
-  if (find_it != tab_socket_bindings_.end())
-    tab_socket_bindings_.erase(find_it);
-
-  auto emplace_result = tab_socket_bindings_.emplace(
-      std::piecewise_construct, std::forward_as_tuple(v8_execution_context_id),
-      std::forward_as_tuple(this, render_frame_, context, world_id));
-
-  // If main world tab socket bindings have been requested and this is the main
-  // world then install the bindings.
-  if (world_id == content::ISOLATED_WORLD_ID_GLOBAL &&
-      !pending_install_main_world_tab_socket_callback_.is_null()) {
-    std::move(pending_install_main_world_tab_socket_callback_)
-        .Run(emplace_result.first->second.InitializeTabSocketBindings()
-                 ? v8_execution_context_id
-                 : -1);
-    pending_install_main_world_tab_socket_callback_ =
-        InstallMainWorldTabSocketCallback();
-  }
-}
-
-void HeadlessRenderFrameControllerImpl::WillReleaseScriptContext(
-    v8::Local<v8::Context> context,
-    int world_id) {
-  tab_socket_bindings_.erase(
-      v8_inspector::V8ContextInfo::executionContextId(context));
-}
-
-void HeadlessRenderFrameControllerImpl::OnDestruct() {
-  delete this;
-}
-
-TabSocketPtr& HeadlessRenderFrameControllerImpl::EnsureTabSocketPtr() {
-  if (!tab_socket_ptr_.is_bound()) {
-    render_frame_->GetRemoteInterfaces()->GetInterface(
-        mojo::MakeRequest(&tab_socket_ptr_));
-  }
-  return tab_socket_ptr_;
-}
-
-}  // namespace headless
diff --git a/headless/lib/renderer/headless_render_frame_controller_impl.h b/headless/lib/renderer/headless_render_frame_controller_impl.h
deleted file mode 100644
index 1a657b99..0000000
--- a/headless/lib/renderer/headless_render_frame_controller_impl.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef HEADLESS_LIB_RENDERER_HEADLESS_RENDER_FRAME_CONTROLLER_IMPL_H_
-#define HEADLESS_LIB_RENDERER_HEADLESS_RENDER_FRAME_CONTROLLER_IMPL_H_
-
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "headless/lib/headless_render_frame_controller.mojom.h"
-#include "headless/lib/renderer/headless_tab_socket_bindings.h"
-#include "headless/lib/tab_socket.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-
-namespace headless {
-
-class HeadlessRenderFrameControllerImpl : public HeadlessRenderFrameController,
-                                          public content::RenderFrameObserver {
- public:
-  explicit HeadlessRenderFrameControllerImpl(
-      content::RenderFrame* render_frame);
-  ~HeadlessRenderFrameControllerImpl() override;
-
-  void OnRenderFrameControllerRequest(
-      HeadlessRenderFrameControllerRequest request);
-
-  // HeadlessRenderFrameController implementation:
-  void InstallTabSocket(int32_t v8_execution_context_id,
-                        InstallTabSocketCallback callback) override;
-  void InstallMainWorldTabSocket(
-      InstallMainWorldTabSocketCallback callback) override;
-  void SendMessageToTabSocket(const std::string& message,
-                              int32_t world_id) override;
-
-  // content::RenderFrameObserver implementation:
-  void OnInterfaceRequestForFrame(
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle* interface_pipe) override;
-  void DidCreateScriptContext(v8::Local<v8::Context> context,
-                              int world_id) override;
-
-  void WillReleaseScriptContext(v8::Local<v8::Context> context,
-                                int world_id) override;
-
-  void OnDestruct() override;
-
-  TabSocketPtr& EnsureTabSocketPtr();
-
- private:
-  content::RenderFrame* const render_frame_;  // NOT OWNED
-  mojo::BindingSet<HeadlessRenderFrameController>
-      headless_render_frame_controller_bindings_;
-  std::map<int, HeadlessTabSocketBindings> tab_socket_bindings_;
-  TabSocketPtr tab_socket_ptr_;
-  InstallMainWorldTabSocketCallback
-      pending_install_main_world_tab_socket_callback_;
-  service_manager::BinderRegistry registry_;
-  base::WeakPtrFactory<HeadlessRenderFrameControllerImpl> weak_ptr_factory_;
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_LIB_RENDERER_HEADLESS_RENDER_FRAME_CONTROLLER_IMPL_H_
diff --git a/headless/lib/renderer/headless_tab_socket_bindings.cc b/headless/lib/renderer/headless_tab_socket_bindings.cc
deleted file mode 100644
index 1890ec38..0000000
--- a/headless/lib/renderer/headless_tab_socket_bindings.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "headless/lib/renderer/headless_tab_socket_bindings.h"
-
-#include "headless/lib/renderer/headless_render_frame_controller_impl.h"
-#include "third_party/blink/public/web/blink.h"
-#include "third_party/blink/public/web/web_local_frame.h"
-#include "v8/include/v8-inspector.h"
-
-namespace headless {
-
-HeadlessTabSocketBindings::HeadlessTabSocketBindings(
-    HeadlessRenderFrameControllerImpl* parent_controller,
-    content::RenderFrame* render_frame,
-    v8::Local<v8::Context> context,
-    int world_id)
-    : parent_controller_(parent_controller),
-      render_frame_(render_frame),
-      context_(blink::MainThreadIsolate(), context),
-      world_id_(world_id),
-      installed_(false) {}
-
-HeadlessTabSocketBindings::~HeadlessTabSocketBindings() = default;
-
-bool HeadlessTabSocketBindings::InitializeTabSocketBindings() {
-  if (installed_)
-    return false;
-
-  v8::Isolate* isolate = blink::MainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  if (context_.IsEmpty())
-    return false;
-
-  v8::Local<v8::Context> context = context_.Get(blink::MainThreadIsolate());
-  v8::Context::Scope context_scope(context);
-  gin::Handle<HeadlessTabSocketBindings> bindings =
-      gin::CreateHandle(isolate, this);
-  if (bindings.IsEmpty())
-    return false;
-
-  v8::Local<v8::Object> global = context->Global();
-  global->Set(gin::StringToV8(isolate, "TabSocket"), bindings.ToV8());
-  installed_ = true;
-  return true;
-}
-
-void HeadlessTabSocketBindings::OnMessageFromEmbedder(
-    const std::string& message) {
-  if (on_message_callback_.IsEmpty()) {
-    pending_messages_.push_back(message);
-    return;
-  }
-
-  v8::Isolate* isolate = blink::MainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context = context_.Get(isolate);
-  v8::Local<v8::Value> argv[] = {
-      gin::Converter<std::string>::ToV8(isolate, message),
-  };
-
-  render_frame_->GetWebFrame()->RequestExecuteV8Function(
-      context, GetOnMessageCallback(), context->Global(), arraysize(argv), argv,
-      this);
-}
-
-gin::ObjectTemplateBuilder HeadlessTabSocketBindings::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return gin::Wrappable<HeadlessTabSocketBindings>::GetObjectTemplateBuilder(
-             isolate)
-      .SetMethod("send", &HeadlessTabSocketBindings::SendImpl)
-      .SetProperty("onmessage", &HeadlessTabSocketBindings::GetOnMessage,
-                   &HeadlessTabSocketBindings::SetOnMessage);
-}
-
-void HeadlessTabSocketBindings::SendImpl(const std::string& message) {
-  v8::Local<v8::Context> context = context_.Get(blink::MainThreadIsolate());
-  int execution_context_id =
-      v8_inspector::V8ContextInfo::executionContextId(context);
-  parent_controller_->EnsureTabSocketPtr()->SendMessageToEmbedder(
-      message, execution_context_id);
-}
-
-void HeadlessTabSocketBindings::SetOnMessage(v8::Local<v8::Function> callback) {
-  on_message_callback_.Reset(blink::MainThreadIsolate(), callback);
-  for (const std::string& message : pending_messages_) {
-    OnMessageFromEmbedder(message);
-  }
-  pending_messages_.clear();
-}
-
-v8::Local<v8::Function> HeadlessTabSocketBindings::GetOnMessageCallback() {
-  return v8::Local<v8::Function>::New(blink::MainThreadIsolate(),
-                                      on_message_callback_);
-}
-
-gin::WrapperInfo HeadlessTabSocketBindings::kWrapperInfo = {
-    gin::kEmbedderNativeGin};
-
-}  // namespace headless
diff --git a/headless/lib/renderer/headless_tab_socket_bindings.h b/headless/lib/renderer/headless_tab_socket_bindings.h
deleted file mode 100644
index 0be27bb9..0000000
--- a/headless/lib/renderer/headless_tab_socket_bindings.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef HEADLESS_LIB_RENDERER_HEADLESS_TAB_SOCKET_BINDINGS_H_
-#define HEADLESS_LIB_RENDERER_HEADLESS_TAB_SOCKET_BINDINGS_H_
-
-#include "content/public/renderer/render_frame.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "headless/lib/tab_socket.mojom.h"
-#include "third_party/blink/public/web/web_script_execution_callback.h"
-
-namespace headless {
-class HeadlessRenderFrameControllerImpl;
-
-class HeadlessTabSocketBindings
-    : public gin::Wrappable<HeadlessTabSocketBindings>,
-      public blink::WebScriptExecutionCallback {
- public:
-  HeadlessTabSocketBindings(
-      HeadlessRenderFrameControllerImpl* parent_controller,
-      content::RenderFrame* render_frame,
-      v8::Local<v8::Context> context,
-      int world_id);
-
-  ~HeadlessTabSocketBindings() override;
-
-  // Add TabSocket bindings to |context_|.
-  bool InitializeTabSocketBindings();
-
-  void OnMessageFromEmbedder(const std::string& message);
-
-  // gin::WrappableBase implementation:
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  static gin::WrapperInfo kWrapperInfo;
-
-  int world_id() const { return world_id_; }
-
- private:
-  void SendImpl(const std::string& message);
-
-  v8::Local<v8::Value> GetOnMessage() { return GetOnMessageCallback(); }
-
-  void SetOnMessage(v8::Local<v8::Function> callback);
-
-  v8::Local<v8::Function> GetOnMessageCallback();
-
-  HeadlessRenderFrameControllerImpl* const parent_controller_;  // NOT OWNED
-  content::RenderFrame* const render_frame_;                    // NOT OWNED
-  const v8::UniquePersistent<v8::Context> context_;
-  const int world_id_;
-  bool installed_;
-  std::list<std::string> pending_messages_;
-  v8::UniquePersistent<v8::Function> on_message_callback_;
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_LIB_RENDERER_HEADLESS_TAB_SOCKET_BINDINGS_H_
diff --git a/headless/lib/resources/headless_lib_resources.grd b/headless/lib/resources/headless_lib_resources.grd
index 9322c4c..8162c847 100644
--- a/headless/lib/resources/headless_lib_resources.grd
+++ b/headless/lib/resources/headless_lib_resources.grd
@@ -13,7 +13,6 @@
       <include name="IDR_HEADLESS_BROWSER_MANIFEST_OVERLAY" file="${mojom_root}/headless/headless_browser_manifest_overlay.json" use_base_dir="false" type="BINDATA" />
       <include name="IDR_HEADLESS_RENDERER_MANIFEST_OVERLAY" file="../renderer/headless_renderer_manifest_overlay.json" type="BINDATA" />
       <include name="IDR_HEADLESS_PACKAGED_SERVICES_MANIFEST_OVERLAY" file="${mojom_root}/headless/headless_packaged_services_manifest_overlay.json" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_HEADLESS_TAB_SOCKET_MOJOM_JS" file="${mojom_root}/headless/lib/tab_socket.mojom.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_PDF_COMPOSITOR_MANIFEST" file="${mojom_root}/components/printing/service/pdf_compositor_manifest.json" use_base_dir="false" type="BINDATA" />
     </includes>
   </release>
diff --git a/headless/lib/tab_socket.mojom b/headless/lib/tab_socket.mojom
deleted file mode 100644
index 07c5649..0000000
--- a/headless/lib/tab_socket.mojom
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module headless;
-
-import "mojo/public/mojom/base/big_string.mojom";
-
-interface TabSocket {
-  // Send a message from the Tab to C++ embedder.
-  SendMessageToEmbedder(mojo_base.mojom.BigString message,
-                        int32 v8_execution_context_id);
-
-  // To send a message to the tab use
-  // HeadlessRenderFrameController::SendMessageToTabSocket.
-};
diff --git a/headless/public/headless_browser.cc b/headless/public/headless_browser.cc
index 5e5dc03..41e4b1b 100644
--- a/headless/public/headless_browser.cc
+++ b/headless/public/headless_browser.cc
@@ -134,11 +134,6 @@
   return *this;
 }
 
-Builder& Builder::AddMojoServiceName(const std::string& mojo_service_name) {
-  options_.mojo_service_names.insert(mojo_service_name);
-  return *this;
-}
-
 Builder& Builder::SetAppendCommandLineFlagsCallback(
     const Options::AppendCommandLineFlagsCallback& callback) {
   options_.append_command_line_flags_callback = callback;
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index 47cb798d..532f250 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -148,10 +148,6 @@
   // string can be used to disable GL rendering (e.g., WebGL support).
   std::string gl_implementation;
 
-  // Names of mojo services exposed by the browser to the renderer. These
-  // services will be added to the browser's service manifest.
-  std::unordered_set<std::string> mojo_service_names;
-
   // Default per-context options, can be specialized on per-context basis.
 
   std::string product_name_and_version;
@@ -251,7 +247,6 @@
   Builder& SetDisableSandbox(bool disable_sandbox);
   Builder& SetEnableResourceScheduler(bool enable_resource_scheduler);
   Builder& SetGLImplementation(const std::string& gl_implementation);
-  Builder& AddMojoServiceName(const std::string& mojo_service_name);
   Builder& SetAppendCommandLineFlagsCallback(
       const Options::AppendCommandLineFlagsCallback& callback);
 #if defined(OS_WIN)
diff --git a/headless/public/headless_browser_context.h b/headless/public/headless_browser_context.h
index 84532dc..3665efb 100644
--- a/headless/public/headless_browser_context.h
+++ b/headless/public/headless_browser_context.h
@@ -120,8 +120,6 @@
   // fetching for different network schemes.
   Builder& SetProtocolHandlers(ProtocolHandlerMap protocol_handlers);
 
-  Builder& AddTabSocketMojoBindings();
-
   // By default if you add mojo bindings, http and https are disabled because
   // its almost certinly unsafe for arbitary sites on the internet to have
   // access to these bindings.  If you know what you're doing it may be OK to
diff --git a/headless/public/headless_tab_socket.h b/headless/public/headless_tab_socket.h
deleted file mode 100644
index 51cb7d3..0000000
--- a/headless/public/headless_tab_socket.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef HEADLESS_PUBLIC_HEADLESS_TAB_SOCKET_H_
-#define HEADLESS_PUBLIC_HEADLESS_TAB_SOCKET_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/optional.h"
-#include "headless/public/headless_export.h"
-
-namespace headless {
-
-// A bidirectional communications channel between C++ and JS.
-class HEADLESS_EXPORT HeadlessTabSocket {
- public:
-  class HEADLESS_EXPORT Listener {
-   public:
-    Listener() {}
-    virtual ~Listener() {}
-
-    // The |message| and |v8_execution_context_id| may be potentially sent by
-    // untrusted web content so it should be validated carefully.
-    virtual void OnMessageFromContext(const std::string& message,
-                                      int v8_execution_context_id) = 0;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Listener);
-  };
-
-  // Installs headless tab socket bindings into the specified execution context.
-  // If the bindings are successfully installed then the |callback| is run with
-  // |success| = true, otherwise with |success| = false.
-  virtual void InstallHeadlessTabSocketBindings(
-      int v8_execution_context_id,
-      base::OnceCallback<void(bool success)> callback) = 0;
-
-  // Installs headless tab socket bindings into the main frame main world. If
-  // the bindings were installed correctly then |callback| is run with a
-  // non-empty base::Optional<int> containing the main world
-  // v8_execution_context_id, otherwise |callback| is run with an empty
-  // base::Optional<int>.
-  virtual void InstallMainFrameMainWorldHeadlessTabSocketBindings(
-      base::OnceCallback<void(base::Optional<int> v8_execution_context_id)>
-          callback) = 0;
-
-  // Note this will fail unless the bindings have been installed.
-  virtual void SendMessageToContext(const std::string& message,
-                                    int v8_execution_context_id) = 0;
-
-  virtual void SetListener(Listener* listener) = 0;
-
- protected:
-  HeadlessTabSocket() {}
-  virtual ~HeadlessTabSocket() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HeadlessTabSocket);
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_PUBLIC_HEADLESS_TAB_SOCKET_H_
diff --git a/headless/public/headless_web_contents.h b/headless/public/headless_web_contents.h
index f05595fe..6f67659 100644
--- a/headless/public/headless_web_contents.h
+++ b/headless/public/headless_web_contents.h
@@ -21,7 +21,6 @@
 class HeadlessBrowserContextImpl;
 class HeadlessBrowserImpl;
 class HeadlessDevToolsTarget;
-class HeadlessTabSocket;
 
 // Class representing contents of a browser tab. Should be accessed from browser
 // main thread.
@@ -80,10 +79,6 @@
   // Close this page. |HeadlessWebContents| object will be destroyed.
   virtual void Close() = 0;
 
-  // Returns the headless tab socket interface for C++ <---> JS, or null if tab
-  // sockets are not allowed.
-  virtual HeadlessTabSocket* GetHeadlessTabSocket() const = 0;
-
   // Returns the main frame's process id or -1 if there's no main frame.
   virtual int GetMainFrameRenderProcessId() const = 0;
 
@@ -113,9 +108,6 @@
   // Specify the initial window size (default is configured in browser options).
   Builder& SetWindowSize(const gfx::Size& size);
 
-  // Specify whether or not TabSockets are allowed.
-  Builder& SetAllowTabSockets(bool tab_sockets_allowed);
-
   // Specify whether BeginFrames should be controlled via DevTools commands.
   Builder& SetEnableBeginFrameControl(bool enable_begin_frame_control);
 
@@ -130,27 +122,10 @@
 
   explicit Builder(HeadlessBrowserContextImpl* browser_context);
 
-  struct MojoService {
-    using ServiceFactoryCallback =
-        base::RepeatingCallback<void(HeadlessWebContents*,
-                                     mojo::ScopedMessagePipeHandle)>;
-
-    MojoService();
-    MojoService(const MojoService& other);
-    MojoService(const std::string& service_name,
-                const ServiceFactoryCallback& service_factory);
-    ~MojoService();
-
-    std::string service_name;
-    ServiceFactoryCallback service_factory;
-  };
-
   HeadlessBrowserContextImpl* browser_context_;
 
   GURL initial_url_ = GURL("about:blank");
   gfx::Size window_size_;
-  std::list<MojoService> mojo_services_;
-  bool tab_sockets_allowed_ = false;
   bool enable_begin_frame_control_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(Builder);
diff --git a/headless/test/data/tabsocket.html b/headless/test/data/tabsocket.html
deleted file mode 100644
index 789191f..0000000
--- a/headless/test/data/tabsocket.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<html>
-<script>
-function tabsocketTest() {
-  // Unfortunately, the order in which
-  // HeadlessRenderFrameControllerImpl::DidCreateScriptContext and
-  // HeadlessRenderFrameControllerImpl::InstallMainWorldTabSocket are called
-  // is non-deterministic.  This means the TabSocket might not have been
-  // installed yet.  If that happens just try again a bit later.
-  if (window.hasOwnProperty('TabSocket')) {
-    window.TabSocket.send('Hello world!');
-
-    window.TabSocket.onmessage = function(message) {
-      window.TabSocket.send('Embedder sent us: ' + message);
-    };
-  } else {
-    setTimeout(tabsocketTest, 1);
-  }
-}
-tabsocketTest();
-</script>
-</html>
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc
index 7f1312b..0a862f41 100644
--- a/headless/test/headless_browser_test.cc
+++ b/headless/test/headless_browser_test.cc
@@ -256,10 +256,6 @@
   HeadlessBrowserContext::Builder builder =
       browser()->CreateBrowserContextBuilder();
   builder.SetProtocolHandlers(GetProtocolHandlers());
-  if (GetAllowTabSockets()) {
-    builder.EnableUnsafeNetworkAccessWithMojoBindings(true);
-    builder.AddTabSocketMojoBindings();
-  }
   CustomizeHeadlessBrowserContext(builder);
   browser_context_ = builder.Build();
 
@@ -268,7 +264,6 @@
 
   HeadlessWebContents::Builder web_contents_builder =
       browser_context_->CreateWebContentsBuilder();
-  web_contents_builder.SetAllowTabSockets(GetAllowTabSockets());
   web_contents_builder.SetEnableBeginFrameControl(GetEnableBeginFrameControl());
   CustomizeHeadlessWebContents(web_contents_builder);
   web_contents_ = web_contents_builder.Build();
@@ -291,10 +286,6 @@
   return ProtocolHandlerMap();
 }
 
-bool HeadlessAsyncDevTooledBrowserTest::GetAllowTabSockets() {
-  return false;
-}
-
 bool HeadlessAsyncDevTooledBrowserTest::GetEnableBeginFrameControl() {
   return false;
 }
diff --git a/headless/test/headless_browser_test.h b/headless/test/headless_browser_test.h
index 1e3f027cc..defe5e3 100644
--- a/headless/test/headless_browser_test.h
+++ b/headless/test/headless_browser_test.h
@@ -144,9 +144,6 @@
   // the map returned is empty.
   virtual ProtocolHandlerMap GetProtocolHandlers();
 
-  // Whether to allow TabSockets when creating |web_contents_|.
-  virtual bool GetAllowTabSockets();
-
   // Whether to enable BeginFrameControl when creating |web_contents_|.
   virtual bool GetEnableBeginFrameControl();
 
diff --git a/headless/test/headless_js_bindings_browsertest.cc b/headless/test/headless_js_bindings_browsertest.cc
index 295f722..abdb42be 100644
--- a/headless/test/headless_js_bindings_browsertest.cc
+++ b/headless/test/headless_js_bindings_browsertest.cc
@@ -8,6 +8,7 @@
 
 #include "base/base64.h"
 #include "base/json/json_reader.h"
+#include "base/memory/weak_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
@@ -19,10 +20,9 @@
 #include "headless/public/devtools/domains/runtime.h"
 #include "headless/public/headless_browser.h"
 #include "headless/public/headless_devtools_client.h"
-#include "headless/public/headless_tab_socket.h"
 #include "headless/public/headless_web_contents.h"
 #include "headless/public/util/testing/test_in_memory_protocol_handler.h"
-#include "headless/test/tab_socket_test.h"
+#include "headless/test/headless_browser_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -30,26 +30,34 @@
 namespace headless {
 
 namespace {
-static constexpr char kIndexHtml[] = R"(
+const char kIndexHtml[] = R"(
 <html>
 <body>
 <script src="bindings.js"></script>
 </body>
 </html>
 )";
+
+const char kTabSocketScript[] = R"(
+window.TabSocket = {};
+window.TabSocket.onmessage = () => {};
+window.TabSocket.send = (json) => console.debug(json);
+)";
+
 }  // namespace
 
 class HeadlessJsBindingsTest
     : public HeadlessAsyncDevTooledBrowserTest,
       public HeadlessDevToolsClient::RawProtocolListener,
       public TestInMemoryProtocolHandler::RequestDeferrer,
-      public HeadlessTabSocket::Listener,
+      public headless::runtime::Observer,
       public page::ExperimentalObserver {
  public:
-  void SetUp() override {
-    options()->mojo_service_names.insert("headless::TabSocket");
-    HeadlessAsyncDevTooledBrowserTest::SetUp();
-  }
+  using ConsoleAPICalledParams = headless::runtime::ConsoleAPICalledParams;
+  using EvaluateResult = headless::runtime::EvaluateResult;
+  using RemoteObject = headless::runtime::RemoteObject;
+
+  HeadlessJsBindingsTest() : weak_factory_(this) {}
 
   void SetUpOnMainThread() override {
     base::ThreadRestrictions::SetIOAllowed(true);
@@ -62,7 +70,6 @@
 
   void CustomizeHeadlessBrowserContext(
       HeadlessBrowserContext::Builder& builder) override {
-    builder.AddTabSocketMojoBindings();
     builder.EnableUnsafeNetworkAccessWithMojoBindings(true);
   }
 
@@ -74,8 +81,6 @@
     http_handler_->SetHeadlessBrowserContext(browser_context_);
   }
 
-  bool GetAllowTabSockets() override { return true; }
-
   ProtocolHandlerMap GetProtocolHandlers() override {
     ProtocolHandlerMap protocol_handlers;
     std::unique_ptr<TestInMemoryProtocolHandler> http_handler(
@@ -96,28 +101,24 @@
   void RunDevTooledTest() override {
     devtools_client_->GetPage()->GetExperimental()->AddObserver(this);
     devtools_client_->GetPage()->Enable();
-    headless_tab_socket_ = web_contents_->GetHeadlessTabSocket();
-    CHECK(headless_tab_socket_);
-    headless_tab_socket_->SetListener(this);
+    devtools_client_->GetPage()->AddScriptToEvaluateOnNewDocument(
+        kTabSocketScript);
+    devtools_client_->GetRuntime()->AddObserver(this);
+    devtools_client_->GetRuntime()->Enable();
+    devtools_client_->GetRuntime()->Evaluate(
+        kTabSocketScript,
+        base::BindOnce(&HeadlessJsBindingsTest::ConnectionEstablished,
+                       weak_factory_.GetWeakPtr()));
     devtools_client_->SetRawProtocolListener(this);
-
-    headless_tab_socket_->InstallMainFrameMainWorldHeadlessTabSocketBindings(
-        base::BindOnce(&HeadlessJsBindingsTest::OnInstalledHeadlessTabSocket,
-                       base::Unretained(this)));
   }
 
   void OnRequest(const GURL& url,
                  base::RepeatingClosure complete_request) override {
-    if (!tab_socket_installed_ && url.spec() == "http://test.com/bindings.js") {
-      complete_request_ = std::move(complete_request);
-    } else {
-      complete_request.Run();
-    }
+    complete_request.Run();
   }
 
-  void OnInstalledHeadlessTabSocket(base::Optional<int> context_id) {
-    main_world_execution_context_id_ = *context_id;
-    tab_socket_installed_ = true;
+  void ConnectionEstablished(std::unique_ptr<EvaluateResult>) {
+    connection_established_ = true;
     if (complete_request_) {
       browser()->BrowserIOThread()->PostTask(FROM_HERE, complete_request_);
       complete_request_ = base::RepeatingClosure();
@@ -147,9 +148,28 @@
                    : "");
   }
 
-  void OnMessageFromContext(const std::string& json_message,
-                            int v8_execution_context_id) override {
-    EXPECT_EQ(main_world_execution_context_id_, v8_execution_context_id);
+  void OnConsoleAPICalled(const ConsoleAPICalledParams& params) override {
+    const std::vector<std::unique_ptr<RemoteObject>>& args = *params.GetArgs();
+    if (args.empty())
+      return;
+    if (params.GetType() != headless::runtime::ConsoleAPICalledType::DEBUG)
+      return;
+
+    RemoteObject* object = args[0].get();
+    if (object->GetType() != headless::runtime::RemoteObjectType::STRING)
+      return;
+
+    OnMessageFromJS(object->GetValue()->GetString());
+  }
+
+  void SendMessageToJS(const std::string& message) {
+    std::string encoded;
+    base::Base64Encode(message, &encoded);
+    devtools_client_->GetRuntime()->Evaluate(
+        "window.TabSocket.onmessage(atob(\"" + encoded + "\"))");
+  }
+
+  void OnMessageFromJS(const std::string& json_message) {
     std::unique_ptr<base::Value> message =
         base::JSONReader::Read(json_message, base::JSON_PARSE_RFC);
     const base::Value* method_value = message->FindKey("method");
@@ -184,7 +204,7 @@
   bool OnProtocolMessage(const std::string& devtools_agent_host_id,
                          const std::string& json_message,
                          const base::DictionaryValue& parsed_message) override {
-    if (main_world_execution_context_id_ == -1)
+    if (!connection_established_)
       return false;
 
     const base::Value* id_value = parsed_message.FindKey("id");
@@ -198,8 +218,7 @@
       if ((id % 2) == 0)
         return false;
 
-      headless_tab_socket_->SendMessageToContext(
-          json_message, main_world_execution_context_id_);
+      SendMessageToJS(json_message);
       return true;
     }
 
@@ -207,24 +226,28 @@
     if (!method_value)
       return false;
 
-    headless_tab_socket_->SendMessageToContext(
-        json_message, main_world_execution_context_id_);
+    if (method_value->GetString() == "Runtime.consoleAPICalled") {
+      // console.debug is used for transport.
+      return false;
+    }
+
+    SendMessageToJS(json_message);
 
     // Check which domain the event belongs to, if it's the DOM domain then
     // assume js handled it.
     std::vector<base::StringPiece> sections =
         SplitStringPiece(method_value->GetString(), ".", base::KEEP_WHITESPACE,
                          base::SPLIT_WANT_ALL);
+
     return sections[0] == "DOM" || sections[0] == "Runtime";
   }
 
  protected:
   TestInMemoryProtocolHandler* http_handler_;  // NOT OWNED
-  HeadlessTabSocket* headless_tab_socket_;     // NOT OWNED
-  int main_world_execution_context_id_ = -1;
   std::string bindings_js_;
   base::RepeatingClosure complete_request_;
-  bool tab_socket_installed_ = false;
+  bool connection_established_ = false;
+  base::WeakPtrFactory<HeadlessJsBindingsTest> weak_factory_;
 };
 
 class SimpleCommandJsBindingsTest : public HeadlessJsBindingsTest {
@@ -316,8 +339,6 @@
     EXPECT_EQ("2", result);
 
     if (first_result) {
-      tab_socket_installed_ = false;
-      main_world_execution_context_id_ = -1;
       devtools_client_->GetPage()->Reload();
     } else {
       EXPECT_TRUE(metadata_received_);
@@ -326,25 +347,6 @@
     first_result = false;
   }
 
-  // Called on the IO thread.
-  void OnRequest(const GURL& url,
-                 base::RepeatingClosure complete_request) override {
-    HeadlessJsBindingsTest::OnRequest(url, complete_request);
-    if (!first_result && url.spec() == "http://test.com/bindings.js") {
-      browser()->BrowserMainThread()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&CachedJsBindingsTest::ReinstallTabSocketBindings,
-                         base::Unretained(this)));
-    }
-  }
-
-  void ReinstallTabSocketBindings() {
-    headless_tab_socket_->InstallMainFrameMainWorldHeadlessTabSocketBindings(
-        base::BindRepeating(
-            &HeadlessJsBindingsTest::OnInstalledHeadlessTabSocket,
-            base::Unretained(this)));
-  }
-
   void OnMetadataForResource(const GURL& url,
                              net::IOBuffer* buf,
                              int buf_len) override {
diff --git a/headless/test/tab_socket_test.cc b/headless/test/tab_socket_test.cc
deleted file mode 100644
index ee7d58d8..0000000
--- a/headless/test/tab_socket_test.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "headless/test/tab_socket_test.h"
-
-#include "headless/public/headless_devtools_client.h"
-#include "headless/public/headless_tab_socket.h"
-
-namespace headless {
-
-TabSocketTest::TabSocketTest() = default;
-TabSocketTest::~TabSocketTest() = default;
-
-void TabSocketTest::SetUp() {
-  options()->mojo_service_names.insert("headless::TabSocket");
-  HeadlessAsyncDevTooledBrowserTest::SetUp();
-}
-
-void TabSocketTest::RunDevTooledTest() {
-  devtools_client_->GetRuntime()->AddObserver(this);
-  devtools_client_->GetRuntime()->Enable();
-  // Note we must enable the page domain or the browser won't get told the
-  // devtools frame ids.
-  devtools_client_->GetPage()->AddObserver(this);
-  devtools_client_->GetPage()->Enable(
-      page::EnableParams::Builder().Build(),
-      base::BindOnce(&TabSocketTest::OnPageEnabled, base::Unretained(this)));
-}
-
-void TabSocketTest::OnPageEnabled(std::unique_ptr<page::EnableResult> result) {
-  devtools_client_->GetPage()->GetExperimental()->GetResourceTree(
-      page::GetResourceTreeParams::Builder().Build(),
-      base::BindOnce(&TabSocketTest::OnResourceTree, base::Unretained(this)));
-}
-
-void TabSocketTest::OnResourceTree(
-    std::unique_ptr<page::GetResourceTreeResult> result) {
-  main_frame_id_ = result->GetFrameTree()->GetFrame()->GetId();
-  RunTabSocketTest();
-}
-
-void TabSocketTest::OnExecutionContextCreated(
-    const runtime::ExecutionContextCreatedParams& params) {
-  const base::DictionaryValue* dictionary;
-  bool is_main_world;
-  if (params.GetContext()->HasAuxData() &&
-      params.GetContext()->GetAuxData()->GetAsDictionary(&dictionary)) {
-    if (dictionary->GetBoolean("isDefault", &is_main_world) && !is_main_world) {
-      world_name_to_v8_execution_context_id_[params.GetContext()->GetName()] =
-          params.GetContext()->GetId();
-    }
-    std::string frame_id;
-    if (dictionary->GetString("frameId", &frame_id)) {
-      frame_id_to_v8_execution_context_ids_[frame_id].insert(
-          params.GetContext()->GetId());
-    }
-  }
-}
-
-void TabSocketTest::ExpectJsException(
-    std::unique_ptr<runtime::EvaluateResult> result) {
-  EXPECT_TRUE(result->HasExceptionDetails());
-  FinishAsynchronousTest();
-}
-
-void TabSocketTest::FailOnJsEvaluateException(
-    std::unique_ptr<runtime::EvaluateResult> result) {
-  if (!result->HasExceptionDetails())
-    return;
-
-  FinishAsynchronousTest();
-
-  const runtime::ExceptionDetails* exception_details =
-      result->GetExceptionDetails();
-  FAIL() << exception_details->GetText()
-         << (exception_details->HasException()
-                 ? exception_details->GetException()->GetDescription().c_str()
-                 : "");
-}
-
-bool TabSocketTest::GetAllowTabSockets() {
-  return true;
-}
-
-int TabSocketTest::GetV8ExecutionContextIdByWorldName(const std::string& name) {
-  const auto find_it = world_name_to_v8_execution_context_id_.find(name);
-  if (find_it == world_name_to_v8_execution_context_id_.end()) {
-    FinishAsynchronousTest();
-    CHECK(false) << "Unknown isolated world: " << name;
-    return -1;
-  }
-  return find_it->second;
-}
-
-const std::set<int>* TabSocketTest::GetV8ExecutionContextIdsForFrame(
-    const std::string& devtools_frame_id) const {
-  const auto find_it =
-      frame_id_to_v8_execution_context_ids_.find(devtools_frame_id);
-  if (find_it == frame_id_to_v8_execution_context_ids_.end())
-    return nullptr;
-  return &find_it->second;
-}
-
-void TabSocketTest::CreateMainWorldTabSocket(
-    std::string devtools_frame_id,
-    base::OnceCallback<void(int)> callback) {
-  const auto find_it =
-      frame_id_to_v8_execution_context_ids_.find(devtools_frame_id);
-  CHECK(find_it != frame_id_to_v8_execution_context_ids_.end());
-  if (find_it->second.size() != 1u) {
-    FinishAsynchronousTest();
-    FAIL() << "More than one v8 execution context exists for the main frame!";
-  }
-  InstallHeadlessTabSocketBindings(std::move(callback),
-                                   *find_it->second.begin());
-}
-
-void TabSocketTest::CreateIsolatedWorldTabSocket(
-    std::string isolated_world_name,
-    std::string devtools_frame_id,
-    base::OnceCallback<void(int)> callback) {
-  devtools_client_->GetPage()->GetExperimental()->CreateIsolatedWorld(
-      page::CreateIsolatedWorldParams::Builder()
-          .SetFrameId(devtools_frame_id)
-          .SetWorldName(isolated_world_name)
-          .Build(),
-      base::BindOnce(&TabSocketTest::OnCreatedIsolatedWorld,
-                     base::Unretained(this), std::move(callback)));
-}
-
-void TabSocketTest::OnCreatedIsolatedWorld(
-    base::OnceCallback<void(int)> callback,
-    std::unique_ptr<page::CreateIsolatedWorldResult> result) {
-  InstallHeadlessTabSocketBindings(std::move(callback),
-                                   result->GetExecutionContextId());
-}
-
-void TabSocketTest::InstallHeadlessTabSocketBindings(
-    base::OnceCallback<void(int)> callback,
-    int execution_context_id) {
-  HeadlessTabSocket* tab_socket = web_contents_->GetHeadlessTabSocket();
-  CHECK(tab_socket);
-  tab_socket->InstallHeadlessTabSocketBindings(
-      execution_context_id,
-      base::BindOnce(&TabSocketTest::OnInstalledHeadlessTabSocketBindings,
-                     base::Unretained(this), execution_context_id,
-                     std::move(callback)));
-}
-
-void TabSocketTest::OnInstalledHeadlessTabSocketBindings(
-    int execution_context_id,
-    base::OnceCallback<void(int)> callback,
-    bool success) {
-  if (!success) {
-    FinishAsynchronousTest();
-    CHECK(false) << "InstallHeadlessTabSocketBindings failed";
-  }
-  std::move(callback).Run(execution_context_id);
-}
-
-}  // namespace headless
diff --git a/headless/test/tab_socket_test.h b/headless/test/tab_socket_test.h
deleted file mode 100644
index e4065b7..0000000
--- a/headless/test/tab_socket_test.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef HEADLESS_TEST_TAB_SOCKET_TEST_H_
-#define HEADLESS_TEST_TAB_SOCKET_TEST_H_
-
-#include "headless/public/devtools/domains/page.h"
-#include "headless/public/devtools/domains/runtime.h"
-#include "headless/public/headless_tab_socket.h"
-#include "headless/test/headless_browser_test.h"
-
-namespace headless {
-
-class TabSocketTest : public HeadlessAsyncDevTooledBrowserTest,
-                      public HeadlessTabSocket::Listener,
-                      public page::Observer,
-                      public runtime::Observer {
- public:
-  TabSocketTest();
-  ~TabSocketTest() override;
-
-  // HeadlessAsyncDevTooledBrowserTest implementation:
-  void SetUp() override;
-  void RunDevTooledTest() override;
-  bool GetAllowTabSockets() override;
-
-  // runtime::Observer implementation:
-  void OnExecutionContextCreated(
-      const runtime::ExecutionContextCreatedParams& params) override;
-
-  void ExpectJsException(std::unique_ptr<runtime::EvaluateResult> result);
-
-  void FailOnJsEvaluateException(
-      std::unique_ptr<runtime::EvaluateResult> result);
-
-  // Note this will fail the test if an execution context corresponding to
-  // |name| doesn't exist.
-  int GetV8ExecutionContextIdByWorldName(const std::string& name);
-
-  // Returns a pointer to the set of v8 execution context ids corresponding to
-  // |devtools_frame_id| or null if none exist.
-  const std::set<int>* GetV8ExecutionContextIdsForFrame(
-      const std::string& devtools_frame_id) const;
-
-  // Attempts to install a main world TabSocket in |devtools_frame_id|.
-  // If successful |callback| will run with the execution context id of the
-  // main world tab socket.
-  void CreateMainWorldTabSocket(std::string devtools_frame_id,
-                                base::OnceCallback<void(int)> callback);
-
-  // Attempts to create an isolated world in |isolated_world_name| and then
-  // install a world TabSocket. If successful |callback| will run with the
-  // execution context id of the newly created isolated world as a parameter.
-  // Note |isolated_world_name| must be unique.
-  void CreateIsolatedWorldTabSocket(std::string isolated_world_name,
-                                    std::string devtools_frame_id,
-                                    base::OnceCallback<void(int)> callback);
-
-  virtual void RunTabSocketTest() = 0;
-
-  const std::string& main_frame_id() const { return *main_frame_id_; }
-
- private:
-  void OnPageEnabled(std::unique_ptr<page::EnableResult> result);
-
-  void OnResourceTree(std::unique_ptr<page::GetResourceTreeResult> result);
-
-  void CreateMainWorldTabSocketStep2(std::string devtools_frame_id,
-                                     base::OnceCallback<void(int)> callback,
-                                     int v8_execution_context_id);
-
-  void OnCreatedIsolatedWorld(
-      base::OnceCallback<void(int)> callback,
-      std::unique_ptr<page::CreateIsolatedWorldResult> result);
-
-  void InstallHeadlessTabSocketBindings(base::OnceCallback<void(int)> callback,
-                                        int execution_context_id);
-
-  void OnInstalledHeadlessTabSocketBindings(
-      int execution_context_id,
-      base::OnceCallback<void(int)> callback,
-      bool success);
-
-  std::map<std::string, int> world_name_to_v8_execution_context_id_;
-  std::map<std::string, std::set<int>> frame_id_to_v8_execution_context_ids_;
-  base::Optional<std::string> main_frame_id_;
-};
-
-}  // namespace headless
-
-#endif  // HEADLESS_TEST_TAB_SOCKET_TEST_H_
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 0f5a17dd9..9c90ef05 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -134,6 +134,14 @@
 }
 
 builder_mixins {
+  name: "android-gpu-ci"
+  dimensions: "os:Ubuntu-14.04"
+  recipe {
+    properties: "mastername:chromium.gpu"
+  }
+}
+
+builder_mixins {
   name: "android-gpu-fyi-ci"
   dimensions: "os:Ubuntu-14.04"
   mixins: "gpu-fyi-ci"
@@ -387,6 +395,14 @@
   }
 }
 
+builder_mixins {
+  name: "win-gpu-ci"
+  mixins: "win"
+  recipe {
+    properties: "mastername:chromium.gpu"
+  }
+}
+
 # GPU bots run very long tests sometimes on a single tester. The regular
 # timeout isn't enough on some testers during the migration when they run both
 # the buildbot and LUCI tests. Double the timeout for them.
@@ -525,6 +541,11 @@
     }
 
     builders {
+      name: "Android Release (Nexus 5X)"
+      mixins: "android-gpu-ci"
+    }
+
+    builders {
       name: "Android Tests (trial)(dbg)"
       mixins: "android-fyi-ci"
       dimensions: "os:Ubuntu-14.04"
@@ -713,11 +734,6 @@
     }
 
     builders {
-      name: "GPU Linux Builder"
-      mixins: "linux-gpu-ci"
-    }
-
-    builders {
       name: "Deterministic Linux"
       mixins: "linux-ci"
       recipe {
@@ -763,11 +779,6 @@
     }
 
     builders {
-      name: "Linux Release (NVIDIA)"
-      mixins: "linux-gpu-ci"
-    }
-
-    builders {
       name: "Linux Tests"
       mixins: "linux-ci"
     }
@@ -854,6 +865,28 @@
       mixins: "memory-ci"
     }
 
+    # chromium.gpu
+    builders {
+      name: "GPU Linux Builder"
+      mixins: "linux-gpu-ci"
+    }
+
+    builders {
+      name: "GPU Linux Builder (dbg)"
+      mixins: "linux-gpu-ci"
+    }
+
+    builders {
+      name: "Linux Debug (NVIDIA)"
+      mixins: "linux-gpu-ci"
+    }
+
+    builders {
+      name: "Linux Release (NVIDIA)"
+      mixins: "linux-gpu-ci"
+    }
+
+    # chromium.gpu.fyi
     builders {
       name: "GPU FYI Linux Builder"
       mixins: "linux-gpu-fyi-ci"
@@ -1133,6 +1166,26 @@
       dimensions: "cpu:x86-64"
       dimensions: "cores:8"
     }
+
+    # chromium.gpu
+    builders {
+      name: "GPU Win Builder"
+      mixins: "win-gpu-ci"
+    }
+    builders {
+      name: "GPU Win Builder (dbg)"
+      mixins: "win-gpu-ci"
+    }
+    builders {
+      name: "Win10 Debug (NVIDIA)"
+      mixins: "win-gpu-ci"
+    }
+    builders {
+      name: "Win10 Release (NVIDIA)"
+      mixins: "win-gpu-ci"
+    }
+
+    # chromium.gpu.fyi
     builders {
       name: "GPU FYI Win Builder"
       mixins: "win-gpu-fyi-ci"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 9d28ad6..08f8d5a1 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -1617,83 +1617,73 @@
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Android arm Builder (dbg)"
-    category: "android|builder|arm|debug|32"
+    name: "buildbucket/luci.chromium.ci/GPU Win Builder"
+    category: "gpu|win|release|builder"
     short_name: "ci"
   }
   builders {
-    name: "buildbot/chromium.android/Android arm Builder (dbg)"
-    category: "android|builder|arm|debug|32"
+    name: "buildbot/chromium.gpu/GPU Win Builder"
+    category: "gpu|win|release|builder"
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Android WebView L (dbg)"
-    category: "android|builder|arm|tester|32"
+    name: "buildbucket/luci.chromium.ci/GPU Win Builder (dbg)"
+    category: "gpu|win|debug|builder"
     short_name: "ci"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Android WebView M (dbg)"
-    category: "android|builder|arm|tester|32"
-    short_name: "ci"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/KitKat Phone Tester (dbg)"
-    category: "android|builder|arm|tester|32"
-    short_name: "ci"
-  }
-  builders {
-    name: "buildbot/chromium.android/KitKat Phone Tester (dbg)"
-    category: "android|builder|arm|tester|32"
+    name: "buildbot/chromium.gpu/GPU Win Builder (dbg)"
+    category: "gpu|win|debug|builder"
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/KitKat Tablet Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbucket/luci.chromium.ci/Win10 Release (NVIDIA)"
+    category: "gpu|win|release|tester"
     short_name: "ci"
   }
   builders {
-    name: "buildbot/chromium.android/KitKat Tablet Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbot/chromium.gpu/Win10 Release (NVIDIA)"
+    category: "gpu|win|release|tester"
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Lollipop Phone Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbucket/luci.chromium.ci/Win10 Debug (NVIDIA)"
+    category: "gpu|win|debug|tester"
     short_name: "ci"
   }
   builders {
-    name: "buildbot/chromium.android/Lollipop Phone Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbot/chromium.gpu/Win10 Debug (NVIDIA)"
+    category: "gpu|win|debug|tester"
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Lollipop Tablet Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbucket/luci.chromium.ci/GPU Linux Builder (dbg)"
+    category: "gpu|linux|debug|builder"
     short_name: "ci"
   }
   builders {
-    name: "buildbot/chromium.android/Lollipop Tablet Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbot/chromium.gpu/GPU Linux Builder (dbg)"
+    category: "gpu|linux|debug|builder"
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Marshmallow Tablet Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbucket/luci.chromium.ci/Linux Debug (NVIDIA)"
+    category: "gpu|linux|debug|tester"
     short_name: "ci"
   }
   builders {
-    name: "buildbot/chromium.android/Marshmallow Tablet Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbot/chromium.gpu/Linux Debug (NVIDIA)"
+    category: "gpu|linux|debug|tester"
     short_name: "bb"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Lollipop Low-end Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbucket/luci.chromium.ci/Android Release (Nexus 5X)"
+    category: "gpu|android|release"
     short_name: "ci"
   }
   builders {
-    name: "buildbot/chromium.android.fyi/Lollipop Low-end Tester"
-    category: "android|builder|arm|tester|32"
+    name: "buildbot/chromium.gpu/Android Release (Nexus 5X)"
+    category: "gpu|android|release"
     short_name: "bb"
   }
   include_experimental_builds: true
@@ -1808,7 +1798,6 @@
     short_name: "dbg"
   }
   builders {
-    name: "buildbot/chromium.android/Android arm Builder (dbg)"
     name: "buildbucket/luci.chromium.ci/Android arm Builder (dbg)"
     category: "builder|arm"
     short_name: "32"
@@ -1839,13 +1828,11 @@
     short_name: "dbg"
   }
   builders {
-    name: "buildbot/chromium.android/KitKat Phone Tester (dbg)"
     name: "buildbucket/luci.chromium.ci/KitKat Phone Tester (dbg)"
     category: "tester|phone"
     short_name: "K"
   }
   builders {
-    name: "buildbot/chromium.android/Lollipop Phone Tester"
     name: "buildbucket/luci.chromium.ci/Lollipop Phone Tester"
     category: "tester|phone"
     short_name: "L"
@@ -1861,19 +1848,16 @@
     short_name: "N"
   }
   builders {
-    name: "buildbot/chromium.android/KitKat Tablet Tester"
     name: "buildbucket/luci.chromium.ci/KitKat Tablet Tester"
     category: "tester|tablet"
     short_name: "K"
   }
   builders {
-    name: "buildbot/chromium.android/Lollipop Tablet Tester"
     name: "buildbucket/luci.chromium.ci/Lollipop Tablet Tester"
     category: "tester|tablet"
     short_name: "L"
   }
   builders {
-    name: "buildbot/chromium.android/Marshmallow Tablet Tester"
     name: "buildbucket/luci.chromium.ci/Marshmallow Tablet Tester"
     category: "tester|tablet"
     short_name: "M"
@@ -2826,7 +2810,6 @@
     category: "Mac"
   }
   builders {
-    name: "buildbot/chromium.gpu/GPU Linux Builder"
     name: "buildbucket/luci.chromium.ci/GPU Linux Builder"
     category: "Linux"
   }
@@ -2841,7 +2824,6 @@
     category: "Linux"
   }
   builders {
-    name: "buildbot/chromium.gpu/Linux Release (NVIDIA)"
     name: "buildbucket/luci.chromium.ci/Linux Release (NVIDIA)"
     category: "Linux"
   }
@@ -4005,7 +3987,7 @@
     name: "buildbot/tryserver.chromium.android/android_clang_dbg_recipe"
   }
   builders {
-    name: "buildbot/tryserver.chromium.android/android_compile_dbg"
+    name: "buildbucket/luci.chromium.try/android_compile_dbg"
   }
   builders {
     name: "buildbot/tryserver.chromium.android/android_compile_rel"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index bdc3035..28221dd 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -67,6 +67,7 @@
   triggers: "Android FYI Release (Nexus 6P)"
   triggers: "Android FYI Release (Nexus 9)"
   triggers: "Android FYI Release (NVIDIA Shield TV)"
+  triggers: "Android Release (Nexus 5X)"
   triggers: "Android x64 Builder (dbg)"
   triggers: "Android x86 Builder (dbg)"
   triggers: "android-kitkat-arm-rel"
@@ -98,6 +99,7 @@
   triggers: "GPU FYI Linux dEQP Builder"
   triggers: "GPU FYI Linux Ozone Builder"
   triggers: "GPU Linux Builder"
+  triggers: "GPU Linux Builder (dbg)"
   triggers: "Headless Linux (dbg)"
   triggers: "Leak Detection Linux"
   triggers: "linux-blink-heap-incremental-marking"
@@ -133,6 +135,8 @@
   triggers: "GPU FYI Win x64 Builder"
   triggers: "GPU FYI Win x64 Builder (dbg)"
   triggers: "GPU FYI Win x64 dEQP Builder"
+  triggers: "GPU Win Builder"
+  triggers: "GPU Win Builder (dbg)"
   triggers: "win-jumbo-rel"
   triggers: "Win Builder"
   triggers: "Win Builder (dbg)"
@@ -297,6 +301,16 @@
 }
 
 job {
+  id: "Android Release (Nexus 5X)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Android Release (Nexus 5X)"
+  }
+}
+
+job {
   id: "Android Tests (trial)(dbg)"
   # triggered by "Android arm Builder (dbg)"
   acl_sets: "triggered-by-parent-builders"
@@ -855,6 +869,27 @@
 }
 
 job {
+  id: "GPU Linux Builder (dbg)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Linux Builder (dbg)"
+  }
+}
+
+job {
+  id: "Linux Debug (NVIDIA)"
+  # Triggered by "GPU Linux Builder (dbg)".
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Linux Debug (NVIDIA)"
+  }
+}
+
+job {
   id: "Headless Linux (dbg)"
   acl_sets: "default"
   buildbucket: {
@@ -1661,6 +1696,48 @@
 }
 
 job {
+  id: "GPU Win Builder"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Win Builder"
+  }
+}
+
+job {
+  id: "Win10 Release (NVIDIA)"
+  # Triggered by "GPU Win Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 Release (NVIDIA)"
+  }
+}
+
+job {
+  id: "GPU Win Builder (dbg)"
+  acl_sets: "default"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "GPU Win Builder (dbg)"
+  }
+}
+
+job {
+  id: "Win10 Debug (NVIDIA)"
+  # Triggered by "GPU Win Builder (dbg)"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 Debug (NVIDIA)"
+  }
+}
+
+job {
   id: "Win Builder (dbg)"
   acl_sets: "default"
   buildbucket: {
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index 724268d..e403df6 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -332,7 +332,9 @@
   def _ClosureType(self, kind):
     if kind in mojom.PRIMITIVES:
       return _kind_to_closure_type[kind]
-    if (mojom.IsStructKind(kind) or mojom.IsInterfaceKind(kind) or
+    if mojom.IsInterfaceKind(kind):
+      return kind.module.namespace + "." + kind.name + "Ptr"
+    if (mojom.IsStructKind(kind) or
         mojom.IsEnumKind(kind)):
       return kind.module.namespace + "." + kind.name
     # TODO(calamity): Support unions properly.
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README
index 65c3e681..85de448 100644
--- a/net/data/ssl/certificates/README
+++ b/net/data/ssl/certificates/README
@@ -191,6 +191,11 @@
    https://g.co/chrome/symantecpkicerts. (Note, however, that the leaf and
    root do not actually form a chain.)
 
+- may_2018.pem
+   An 825-day certificate issued on May 1, 2018, the official start of
+   enforcement requiring Certificate Transparency for new certificates. This
+   certificate does not have any embedded SCTs.
+
 - tls_feature_extension.pem
   A certificate that contains the TLS Feature Extension.
 
diff --git a/net/data/ssl/certificates/may_2018.pem b/net/data/ssl/certificates/may_2018.pem
new file mode 100644
index 0000000..3b275fc
--- /dev/null
+++ b/net/data/ssl/certificates/may_2018.pem
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 31 (0x1f)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=Test Root CA
+        Validity
+            Not Before: May  1 00:00:00 2018 GMT
+            Not After : Aug  3 00:00:00 2020 GMT
+        Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:dc:25:f0:b1:e7:f4:9a:33:24:c7:c7:55:bf:9f:
+                    06:3f:3d:61:ec:6e:38:21:04:87:7b:ea:c9:37:1d:
+                    ad:61:46:3d:0f:43:54:ea:b0:01:45:a8:5f:fc:04:
+                    44:36:a5:0b:0e:53:49:ad:d4:de:70:b3:0e:9a:42:
+                    35:17:44:c8:7b:80:6e:a3:1b:3e:16:21:1d:b3:b5:
+                    08:89:97:ec:83:61:c6:a1:a5:6b:e7:f1:38:96:1b:
+                    d1:db:2d:7e:93:90:3c:07:5b:77:6b:e0:18:63:f3:
+                    ca:42:f1:97:7f:5b:44:9d:c1:65:34:cf:e8:4d:db:
+                    b7:b2:8f:11:f9:0d:99:97:bd:56:24:22:aa:9a:02:
+                    cb:93:e4:b2:55:bf:2d:82:2b:49:4f:2e:69:e2:e9:
+                    a0:a5:18:95:f4:40:90:d7:90:34:cb:ad:a9:d8:a3:
+                    1b:3c:a9:d9:0b:00:60:6c:43:1f:42:82:07:f0:99:
+                    4b:d1:a6:66:7a:4e:69:3a:2f:c6:db:20:d0:58:80:
+                    90:c2:dc:70:ee:22:85:fb:59:bb:25:ba:12:1a:27:
+                    44:d6:f0:14:1a:71:f7:f9:fc:e5:3e:a5:7d:ad:e3:
+                    35:9b:c8:61:f5:13:e4:b6:58:e6:8f:46:1f:f4:18:
+                    69:76:78:eb:f9:ad:75:90:7c:69:dc:89:39:37:d7:
+                    fc:2f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                FE:66:FC:2C:74:C7:2C:BB:9D:03:C1:68:2F:63:DC:AA:E7:7B:5F:F3
+            X509v3 Authority Key Identifier: 
+                keyid:9B:26:0B:8A:98:A9:BB:1D:B9:1F:1C:E3:1A:40:33:ED:8E:17:88:AB
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Subject Alternative Name: 
+                IP Address:127.0.0.1
+    Signature Algorithm: sha256WithRSAEncryption
+         2a:c8:c1:eb:97:c0:a7:01:7e:36:67:9b:8d:fe:ce:7d:30:25:
+         7c:63:9b:be:fd:b0:b8:1d:25:ef:bf:f8:3a:58:78:24:08:de:
+         37:b9:a9:48:66:8e:b7:db:e3:57:49:7f:f4:09:64:72:45:83:
+         c2:d2:d7:0b:01:85:cc:4a:d9:1c:bc:0f:88:f2:2e:fa:e6:ee:
+         3c:76:b3:f7:5d:ec:57:f1:23:be:54:18:b3:6f:95:56:c6:fe:
+         29:ca:85:3f:4d:d8:d5:23:63:8f:fd:68:c0:54:d0:e0:7f:b3:
+         2f:36:fb:3b:60:ec:5a:25:2a:88:0b:00:94:a5:c4:13:c6:d0:
+         da:a6:f2:de:00:aa:ac:11:32:c3:30:ae:52:75:86:91:e5:5c:
+         6a:b3:22:8d:2f:31:91:34:d1:2f:e3:59:53:4a:95:b9:17:34:
+         e7:ab:15:9f:96:a0:61:e7:ad:a2:dc:ac:3b:71:65:3b:e5:a5:
+         36:56:69:a3:ce:c5:fc:44:f6:28:85:72:7b:90:0e:c1:df:a5:
+         36:0a:3b:d6:76:9c:1d:2c:b7:3f:9a:c0:95:93:e8:31:e7:e4:
+         8b:07:67:06:20:44:56:be:a1:1f:9a:aa:24:53:93:3e:f2:0d:
+         e4:f4:16:47:68:c5:6d:f4:c1:a6:c0:92:97:75:4e:f4:49:77:
+         08:24:5e:8a
+-----BEGIN CERTIFICATE-----
+MIIDvzCCAqegAwIBAgIBHzANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzET
+MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4G
+A1UECgwHVGVzdCBDQTEVMBMGA1UEAwwMVGVzdCBSb290IENBMB4XDTE4MDUwMTAw
+MDAwMFoXDTIwMDgwMzAwMDAwMFowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
+bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB1Rlc3Qg
+Q0ExEjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBANwl8LHn9JozJMfHVb+fBj89YexuOCEEh3vqyTcdrWFGPQ9DVOqwAUWo
+X/wERDalCw5TSa3U3nCzDppCNRdEyHuAbqMbPhYhHbO1CImX7INhxqGla+fxOJYb
+0dstfpOQPAdbd2vgGGPzykLxl39bRJ3BZTTP6E3bt7KPEfkNmZe9ViQiqpoCy5Pk
+slW/LYIrSU8uaeLpoKUYlfRAkNeQNMutqdijGzyp2QsAYGxDH0KCB/CZS9GmZnpO
+aTovxtsg0FiAkMLccO4ihftZuyW6EhonRNbwFBpx9/n85T6lfa3jNZvIYfUT5LZY
+5o9GH/QYaXZ46/mtdZB8adyJOTfX/C8CAwEAAaOBgDB+MAwGA1UdEwEB/wQCMAAw
+HQYDVR0OBBYEFP5m/Cx0xyy7nQPBaC9j3Krne1/zMB8GA1UdIwQYMBaAFJsmC4qY
+qbsduR8c4xpAM+2OF4irMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAP
+BgNVHREECDAGhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQAqyMHrl8CnAX42Z5uN
+/s59MCV8Y5u+/bC4HSXvv/g6WHgkCN43ualIZo632+NXSX/0CWRyRYPC0tcLAYXM
+StkcvA+I8i765u48drP3XexX8SO+VBizb5VWxv4pyoU/TdjVI2OP/WjAVNDgf7Mv
+Nvs7YOxaJSqICwCUpcQTxtDapvLeAKqsETLDMK5SdYaR5VxqsyKNLzGRNNEv41lT
+SpW5FzTnqxWflqBh562i3Kw7cWU75aU2VmmjzsX8RPYohXJ7kA7B36U2CjvWdpwd
+LLc/msCVk+gx5+SLB2cGIERWvqEfmqokU5M+8g3k9BZHaMVt9MGmwJKXdU70SXcI
+JF6K
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/scripts/generate-test-certs.sh b/net/data/ssl/scripts/generate-test-certs.sh
index a4e309f..c5b4fe9 100755
--- a/net/data/ssl/scripts/generate-test-certs.sh
+++ b/net/data/ssl/scripts/generate-test-certs.sh
@@ -528,6 +528,22 @@
     -out ../certificates/dec_2017.pem \
     -config ca.cnf
 
+# Issued on 1 May 2018 (after the 30 Apr 2018 CT Requirement date)
+openssl req \
+  -config ../scripts/ee.cnf \
+  -newkey rsa:2048 \
+  -text \
+  -out out/may_2018.req
+CA_NAME="req_ca_dn" \
+  openssl ca \
+    -batch \
+    -extensions user_cert \
+    -startdate 180501000000Z \
+    -enddate   200803000000Z \
+    -in out/may_2018.req \
+    -out ../certificates/may_2018.pem \
+    -config ca.cnf
+
 # Regenerate CRLSets
 ## Block a leaf cert directly by SPKI
 python crlsetutil.py -o ../certificates/crlset_by_leaf_spki.raw \
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 2d04890..0dff0ec 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1357,8 +1357,6 @@
   nqe::internal::NetworkQuality network_quality =
       cached_network_quality.network_quality();
 
-  const base::TimeTicks now = tick_clock_->NowTicks();
-
   bool update_network_quality_store = false;
 
   // Populate |network_quality| with synthetic RTT and throughput observations
@@ -1387,25 +1385,25 @@
   }
 
   if (update_network_quality_store) {
-    network_quality_store_->Add(
-        current_network_id_,
-        nqe::internal::CachedNetworkQuality(now, network_quality,
-                                            effective_connection_type));
+    network_quality_store_->Add(current_network_id_,
+                                nqe::internal::CachedNetworkQuality(
+                                    tick_clock_->NowTicks(), network_quality,
+                                    effective_connection_type));
   }
 
   Observation http_rtt_observation(
-      network_quality.http_rtt().InMilliseconds(), now, INT32_MIN,
-      NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
+      network_quality.http_rtt().InMilliseconds(), tick_clock_->NowTicks(),
+      INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
   AddAndNotifyObserversOfRTT(http_rtt_observation);
 
   Observation transport_rtt_observation(
-      network_quality.transport_rtt().InMilliseconds(), now, INT32_MIN,
-      NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE);
+      network_quality.transport_rtt().InMilliseconds(), tick_clock_->NowTicks(),
+      INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE);
   AddAndNotifyObserversOfRTT(transport_rtt_observation);
 
   Observation througphput_observation(
-      network_quality.downstream_throughput_kbps(), now, INT32_MIN,
-      NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
+      network_quality.downstream_throughput_kbps(), tick_clock_->NowTicks(),
+      INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
   AddAndNotifyObserversOfThroughput(througphput_observation);
 
   ComputeEffectiveConnectionType();
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 62f996ab..00b425eb 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -81,7 +81,8 @@
     const ResourceRequest& resource_request,
     mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
-    mojom::URLLoaderFactory* network_loader_factory)
+    mojom::URLLoaderFactory* network_loader_factory,
+    const base::RepeatingCallback<void(int)>& preflight_finalizer)
     : network_loader_factory_(network_loader_factory),
       network_client_binding_(this),
       request_(resource_request),
@@ -123,13 +124,19 @@
     return;
   }
 
+  base::OnceCallback<void()> preflight_finalizer_for_request;
+  if (preflight_finalizer) {
+    preflight_finalizer_for_request =
+        base::BindOnce(preflight_finalizer, request_id);
+  }
+
   PreflightController::GetDefaultController()->PerformPreflightCheck(
       base::BindOnce(&CORSURLLoader::StartNetworkRequest,
                      weak_factory_.GetWeakPtr(), routing_id, request_id,
                      options, traffic_annotation),
       request_id, request_,
       net::NetworkTrafficAnnotationTag(traffic_annotation),
-      network_loader_factory);
+      network_loader_factory, std::move(preflight_finalizer_for_request));
 }
 
 CORSURLLoader::~CORSURLLoader() {}
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h
index a3eee10f..00119620 100644
--- a/services/network/cors/cors_url_loader.h
+++ b/services/network/cors/cors_url_loader.h
@@ -29,6 +29,8 @@
       public mojom::URLLoaderClient {
  public:
   // Assumes network_loader_factory outlives this loader.
+  // TODO(yhirano): Remove |preflight_finalizer| when the network service is
+  // fully enabled.
   CORSURLLoader(
       int32_t routing_id,
       int32_t request_id,
@@ -36,7 +38,8 @@
       const ResourceRequest& resource_request,
       mojom::URLLoaderClientPtr client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
-      mojom::URLLoaderFactory* network_loader_factory);
+      mojom::URLLoaderFactory* network_loader_factory,
+      const base::RepeatingCallback<void(int)>& preflight_finalizer);
 
   ~CORSURLLoader() override;
 
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index 14cbb44..c7c399f6 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -15,6 +15,12 @@
     std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory)
     : network_loader_factory_(std::move(network_loader_factory)) {}
 
+CORSURLLoaderFactory::CORSURLLoaderFactory(
+    std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory,
+    const base::RepeatingCallback<void(int)>& preflight_finalizer)
+    : network_loader_factory_(std::move(network_loader_factory)),
+      preflight_finalizer_(preflight_finalizer) {}
+
 CORSURLLoaderFactory::~CORSURLLoaderFactory() = default;
 
 void CORSURLLoaderFactory::CreateLoaderAndStart(
@@ -27,10 +33,10 @@
     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()),
+        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));
   } else {
     network_loader_factory_->CreateLoaderAndStart(
diff --git a/services/network/cors/cors_url_loader_factory.h b/services/network/cors/cors_url_loader_factory.h
index 13f90e13..7fa3846 100644
--- a/services/network/cors/cors_url_loader_factory.h
+++ b/services/network/cors/cors_url_loader_factory.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -27,6 +28,11 @@
  public:
   explicit CORSURLLoaderFactory(
       std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory);
+  // TODO(yhirano): Remove |preflight_finalizer| when the network service is
+  // fully enabled.
+  CORSURLLoaderFactory(
+      std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory,
+      const base::RepeatingCallback<void(int)>& preflight_finalizer);
   ~CORSURLLoaderFactory() override;
 
  private:
@@ -45,6 +51,8 @@
 
   std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory_;
 
+  base::RepeatingCallback<void(int)> preflight_finalizer_;
+
   // The factory owns the CORSURLLoader it creates.
   mojo::StrongBindingSet<mojom::URLLoader> loader_bindings_;
 
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index f161962..2394437 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -225,10 +225,12 @@
   PreflightLoader(PreflightController* controller,
                   CompletionCallback completion_callback,
                   const ResourceRequest& request,
-                  const net::NetworkTrafficAnnotationTag& annotation_tag)
+                  const net::NetworkTrafficAnnotationTag& annotation_tag,
+                  base::OnceCallback<void()> preflight_finalizer)
       : controller_(controller),
         completion_callback_(std::move(completion_callback)),
-        original_request_(request) {
+        original_request_(request),
+        preflight_finalizer_(std::move(preflight_finalizer)) {
     loader_ = SimpleURLLoader::Create(CreatePreflightRequest(request),
                                       annotation_tag);
   }
@@ -310,6 +312,8 @@
 
   void FinalizeLoader() {
     DCHECK(loader_);
+    if (preflight_finalizer_)
+      std::move(preflight_finalizer_).Run();
     loader_.reset();
   }
 
@@ -327,6 +331,11 @@
   PreflightController::CompletionCallback completion_callback_;
   const ResourceRequest original_request_;
 
+  // This is needed because we sometimes need to cancel the preflight loader
+  // synchronously.
+  // TODO(yhirano): Remove this when the network service is fully enabled.
+  base::OnceCallback<void()> preflight_finalizer_;
+
   DISALLOW_COPY_AND_ASSIGN(PreflightLoader);
 };
 
@@ -352,7 +361,8 @@
     int32_t request_id,
     const ResourceRequest& request,
     const net::NetworkTrafficAnnotationTag& annotation_tag,
-    mojom::URLLoaderFactory* loader_factory) {
+    mojom::URLLoaderFactory* loader_factory,
+    base::OnceCallback<void()> preflight_finalizer) {
   DCHECK(request.request_initiator);
 
   if (!request.is_external_request &&
@@ -364,7 +374,8 @@
   }
 
   auto emplaced_pair = loaders_.emplace(std::make_unique<PreflightLoader>(
-      this, std::move(callback), request, annotation_tag));
+      this, std::move(callback), request, annotation_tag,
+      std::move(preflight_finalizer)));
   (*emplaced_pair.first)->Request(loader_factory, request_id);
 }
 
diff --git a/services/network/cors/preflight_controller.h b/services/network/cors/preflight_controller.h
index b280625..eb8707b 100644
--- a/services/network/cors/preflight_controller.h
+++ b/services/network/cors/preflight_controller.h
@@ -49,13 +49,21 @@
   // Determines if a CORS-preflight request is needed, and checks the cache, or
   // makes a preflight request if it is needed. A result will be notified
   // synchronously or asynchronously.
+  // |request_id| and |preflight_finalizer| are needed when the Network Service
+  // is disabled, in such a case, we need to use the actual request's request
+  // ID for the preflight request (thus we need |request_id|) and we need to
+  // cancel the preflight request synchronously before starting the actual
+  // request (thus we need |preflight_finalizer|).
   // TODO(toyoshim): Remove |request_id| once the Network Service is enabled.
+  // TODO(yhirano): Remove |preflight_finalizer| once the Network Service is
+  // fully enabled.
   void PerformPreflightCheck(
       CompletionCallback callback,
       int32_t request_id,
       const ResourceRequest& resource_request,
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
-      mojom::URLLoaderFactory* loader_factory);
+      mojom::URLLoaderFactory* loader_factory,
+      base::OnceCallback<void()> preflight_finalizer);
 
  private:
   class PreflightLoader;
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc
index 777cf9f..43b7608 100644
--- a/services/network/cors/preflight_controller_unittest.cc
+++ b/services/network/cors/preflight_controller_unittest.cc
@@ -163,13 +163,16 @@
         base::BindOnce(&PreflightControllerTest::HandleRequestCompletion,
                        base::Unretained(this)),
         0 /* request_id */, request, TRAFFIC_ANNOTATION_FOR_TESTS,
-        url_loader_factory_ptr_.get());
+        url_loader_factory_ptr_.get(),
+        base::BindOnce(&PreflightControllerTest::CancelPreflight,
+                       base::Unretained(this)));
     run_loop_->Run();
   }
 
   base::Optional<CORSErrorStatus> status() { return status_; }
   base::Optional<CORSErrorStatus> success() { return base::nullopt; }
   size_t access_count() { return access_count_; }
+  bool cancel_preflight_called() const { return cancel_preflight_called_; }
 
  private:
   void SetUp() override {
@@ -207,6 +210,8 @@
     return response;
   }
 
+  void CancelPreflight() { cancel_preflight_called_ = true; }
+
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<base::RunLoop> run_loop_;
 
@@ -216,6 +221,7 @@
 
   net::test_server::EmbeddedTestServer test_server_;
   size_t access_count_ = 0;
+  bool cancel_preflight_called_ = false;
 
   std::unique_ptr<PreflightController> preflight_controller_;
   base::Optional<CORSErrorStatus> status_;
@@ -246,6 +252,20 @@
   EXPECT_EQ(1u, access_count());  // Should be from the preflight cache.
 }
 
+// TODO(yhirano): Remove this test case when the network service is fully
+// enabled.
+TEST_F(PreflightControllerTest, CancelPreflightIsCalled) {
+  ResourceRequest request;
+  request.url = GetURL("/allow");
+  request.request_initiator = url::Origin::Create(request.url);
+
+  EXPECT_FALSE(cancel_preflight_called());
+  PerformPreflightCheck(request);
+  ASSERT_FALSE(status());
+  EXPECT_TRUE(cancel_preflight_called());
+  EXPECT_EQ(1u, access_count());
+}
+
 }  // namespace
 
 }  // namespace cors
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 7e24e6f..9ca169e8 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -18,7 +18,7 @@
 #include "base/task_scheduler/task_traits.h"
 #include "build/build_config.h"
 #include "components/certificate_transparency/chrome_ct_policy_enforcer.h"
-#include "components/certificate_transparency/ct_policy_manager.h"
+#include "components/certificate_transparency/chrome_require_ct_delegate.h"
 #include "components/certificate_transparency/features.h"
 #include "components/certificate_transparency/sth_distributor.h"
 #include "components/certificate_transparency/sth_reporter.h"
@@ -228,7 +228,7 @@
       builder.get(), params_.get(), network_service->quic_disabled(),
       network_service->net_log(), network_service->network_quality_estimator(),
       network_service_->sth_reporter(), &ct_tree_tracker_,
-      &user_agent_settings_);
+      &require_ct_delegate_, &user_agent_settings_);
   url_request_context_ = url_request_context_owner_.url_request_context.get();
 
   network_service_->RegisterNetworkContext(this);
@@ -264,7 +264,8 @@
     network_service_->DeregisterNetworkContext(this);
 
   if (url_request_context_ &&
-      url_request_context_->transport_security_state()) {
+      url_request_context_->transport_security_state() &&
+      require_ct_delegate_) {
     url_request_context_->transport_security_state()->SetRequireCTDelegate(
         nullptr);
   }
@@ -524,13 +525,11 @@
     const std::vector<std::string>& excluded_hosts,
     const std::vector<std::string>& excluded_spkis,
     const std::vector<std::string>& excluded_legacy_spkis) {
-  if (!ct_policy_manager_) {
-    ct_policy_manager_.reset(new certificate_transparency::CTPolicyManager());
-    url_request_context_->transport_security_state()->SetRequireCTDelegate(
-        ct_policy_manager_->GetDelegate());
-  }
-  ct_policy_manager_->UpdateCTPolicies(required_hosts, excluded_hosts,
-                                       excluded_spkis, excluded_legacy_spkis);
+  if (!require_ct_delegate_)
+    return;
+
+  require_ct_delegate_->UpdateCTPolicies(required_hosts, excluded_hosts,
+                                         excluded_spkis, excluded_legacy_spkis);
 }
 
 void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request,
@@ -623,6 +622,8 @@
     certificate_transparency::STHReporter* sth_reporter,
     std::unique_ptr<certificate_transparency::TreeStateTracker>*
         out_ct_tree_tracker,
+    std::unique_ptr<certificate_transparency::ChromeRequireCTDelegate>*
+        out_require_ct_delegate,
     net::StaticHttpUserAgentSettings** out_http_user_agent_settings) {
   if (net_log)
     builder->set_net_log(net_log);
@@ -790,6 +791,14 @@
   }
 #endif
 
+  if (out_require_ct_delegate &&
+      network_context_params->enforce_chrome_ct_policy) {
+    *out_require_ct_delegate =
+        std::make_unique<certificate_transparency::ChromeRequireCTDelegate>();
+    result.url_request_context->transport_security_state()
+        ->SetRequireCTDelegate(out_require_ct_delegate->get());
+  }
+
   return result;
 }
 
@@ -908,7 +917,7 @@
       network_service_ ? network_service_->network_quality_estimator()
                        : nullptr,
       network_service_ ? network_service_->sth_reporter() : nullptr,
-      &ct_tree_tracker_, &user_agent_settings_);
+      &ct_tree_tracker_, &require_ct_delegate_, &user_agent_settings_);
 
   return result;
 }
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 779b2bebc..9ee4c51 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -40,7 +40,7 @@
 }  // namespace net
 
 namespace certificate_transparency {
-class CTPolicyManager;
+class ChromeRequireCTDelegate;
 class TreeStateTracker;
 class STHReporter;
 }  // namespace certificate_transparency
@@ -200,6 +200,8 @@
       certificate_transparency::STHReporter* sth_reporter,
       std::unique_ptr<certificate_transparency::TreeStateTracker>*
           out_tree_state_tracker,
+      std::unique_ptr<certificate_transparency::ChromeRequireCTDelegate>*
+          out_require_ct_delegate,
       net::StaticHttpUserAgentSettings** out_http_user_agent_settings);
 
   // Invoked when the HTTP cache was cleared. Invokes |callback|.
@@ -254,7 +256,8 @@
   // TODO(yhirano): Consult with switches::kDisableResourceScheduler.
   constexpr static bool enable_resource_scheduler_ = true;
 
-  std::unique_ptr<certificate_transparency::CTPolicyManager> ct_policy_manager_;
+  std::unique_ptr<certificate_transparency::ChromeRequireCTDelegate>
+      require_ct_delegate_;
   std::unique_ptr<certificate_transparency::TreeStateTracker> ct_tree_tracker_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkContext);
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 99d7a7f1..ed89f47 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -324,7 +324,10 @@
   // Updates the Accept-Language header to be used for requests.
   SetAcceptLanguage(string new_accept_language);
 
-  // Updates the CT policy to be used for requests.
+  // Updates the CT policy to be used for requests. Only applies if the
+  // NetworkContextParams set enforce_chrome_ct_policy to true.
+  // TODO(rsleevi): Remove this once Chrome-specific policies are moved out
+  // of the network service.
   SetCTPolicy(array<string> required_hosts,
               array<string> excluded_hosts,
               array<string> excluded_spkis,
diff --git a/services/network/url_request_context_builder_mojo.cc b/services/network/url_request_context_builder_mojo.cc
index a4e4c48..94187ad 100644
--- a/services/network/url_request_context_builder_mojo.cc
+++ b/services/network/url_request_context_builder_mojo.cc
@@ -41,6 +41,7 @@
       this, params, quic_disabled, net_log, network_quality_estimator,
       nullptr, /* sth_distributor */
       nullptr, /* out_ct_tree_tracker */
+      nullptr, /* out_require_ct_delegate */
       nullptr /* out_static_user_agent_settings */);
 }
 
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 1658e5d..ec9071d 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -8098,6 +8098,19 @@
             }
           ]
         },
+        "test": "cros_vm_sanity_test"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1",
+              "os": "Ubuntu-14.04",
+              "pool": "Chrome-CrOS-VM"
+            }
+          ]
+        },
         "test": "net_unittests"
       }
     ],
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 9f15556a..36ed932 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -483,6 +483,10 @@
     "label": "//components/cronet/android:cronet_test_instrumentation_apk",
     "type": "additional_compile_target",
   },
+  "cros_vm_sanity_test": {
+    "label": "//chromeos:cros_vm_sanity_test",
+    "type": "raw",
+  },
   "crypto_unittests": {
     "label": "//crypto:crypto_unittests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 0112d7f..dc83b7d 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -371,6 +371,7 @@
 
   'chromeos_gtests_experimental': {
     'base_unittests': {},
+    'cros_vm_sanity_test': {},
     'net_unittests': {},
   },
 
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index d0aafe89..ca76fcf0 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -1388,6 +1388,7 @@
 crbug.com/591099 fast/spatial-navigation/snav-fully-aligned-vertically.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/computedstylemargin.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/inline-block-with-padding.html [ Failure ]
+crbug.com/708452 fast/sub-pixel/selection/selection-rect-in-sub-pixel-table.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
 crbug.com/591099 fast/table/032.html [ Failure ]
 crbug.com/591099 fast/table/background-gradient-border-collapsed.html [ Failure ]
@@ -1912,6 +1913,8 @@
 crbug.com/591099 paint/selection/text-selection-drag-in-frame-scrolled.html [ Failure ]
 crbug.com/591099 paint/selection/text-selection-drag-in-frame.html [ Failure ]
 crbug.com/714962 paint/selection/text-selection-drag.html [ Failure ]
+crbug.com/708452 paint/selection/text-selection-inline-block-rtl.html [ Failure ]
+crbug.com/708452 paint/selection/text-selection-inline-block.html [ Failure ]
 crbug.com/591099 paint/selection/text-selection-newline-across-blocks-line-beginning-end.html [ Failure ]
 crbug.com/591099 paint/selection/text-selection-newline-across-blocks.html [ Failure ]
 crbug.com/591099 paint/selection/text-selection-newline-br.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index a64b13d1..b5f6f63 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1750,6 +1750,8 @@
 
 # ====== IncrementalShadowDOM-only failures until here ======
 
+crbug.com/840238 http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ]
+
 crbug.com/667560 [ Debug ] http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Pass Failure ]
 crbug.com/778515 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Pass Failure ]
 
@@ -2823,6 +2825,7 @@
 crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.12 ] external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/078.html [ Timeout ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Skip ]
 crbug.com/626703 [ Retina ] external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Skip ]
 crbug.com/626703 [ Win7 ] external/wpt/pointerevents/pointerevent_pointerout_received_once-manual.html [ Skip ]
@@ -4690,6 +4693,7 @@
 crbug.com/832842 [ Win7 ] virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure ]
 crbug.com/833655 [ Linux ] media/controls/closed-captions-dynamic-update.html [ Skip ]
 crbug.com/833655 [ Linux ] virtual/new-remote-playback-pipeline/media/controls/closed-captions-dynamic-update.html [ Skip ]
+crbug.com/833655 [ Linux ] virtual/incremental-shadow-dom/media/controls/closed-captions-dynamic-update.html [ Skip ]
 crbug.com/833655 [ Linux ] virtual/video-surface-layer/media/controls/closed-captions-dynamic-update.html [ Skip ]
 crbug.com/833658 [ Linux Win Mac ] media/video-controls-focus-movement-on-hide.html [ Pass Failure ]
 crbug.com/833100 [ Mac ] external/wpt/battery-status/battery-full-manual.https.html [ Failure ]
@@ -4711,12 +4715,9 @@
 
 crbug.com/839332 [ Mac ] virtual/video-surface-layer/media/video-no-audio.html [ Pass Failure ]
 
-# Sheriff 2018-05-14
-crbug.com/842793 [ Linux ] virtual/incremental-shadow-dom/media/controls/closed-captions-dynamic-update.html [ Pass Failure ]
-
 # Sheriff 2018-05-17
 crbug.com/840792 [ Mac10.12 Mac10.13 ] external/wpt/pointerevents/pointerevent_touch-action-table-test_touch-manual.html [ Pass Timeout ]
 crbug.com/810437 fast/events/hr-timestamp/input-events.html [ Pass Timeout ]
 
 # This will break for now
-crbug.com/841933 http/tests/webaudio/autoplay-crossorigin.html [ Skip ]
\ No newline at end of file
+crbug.com/841933 http/tests/webaudio/autoplay-crossorigin.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index dac1f6c..a6f9c8d4 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -108961,11 +108961,6 @@
      {}
     ]
    ],
-   "css/css-backgrounds/resources/parsing-testcommon.js": [
-    [
-     {}
-    ]
-   ],
    "css/css-backgrounds/support/100x100-blue-and-orange.png": [
     [
      {}
@@ -120216,7 +120211,7 @@
      {}
     ]
    ],
-   "css/css-images/parsing/image-resolution-invalid-expected.txt": [
+   "css/css-images/parsing/image-resolution-valid-expected.txt": [
     [
      {}
     ]
@@ -160301,6 +160296,16 @@
      {}
     ]
    ],
+   "server-timing/resources/blue_tao.png": [
+    [
+     {}
+    ]
+   ],
+   "server-timing/resources/blue_tao.png.sub.headers": [
+    [
+     {}
+    ]
+   ],
    "server-timing/resources/green.png": [
     [
      {}
@@ -262558,7 +262563,7 @@
    "testharness"
   ],
   "cookie-store/OWNERS": [
-   "2118c49146d7ca543b37104c35c79aea5839de32",
+   "a99b955e85074ac568413a5cc12f675a01b2a431",
    "support"
   ],
   "cookie-store/README.md": [
@@ -280806,7 +280811,7 @@
    "reftest"
   ],
   "css/css-backgrounds/box-shadow-syntax-001.html": [
-   "90c15e29e3675b2dada46ea9d9d940fcb37c5b79",
+   "fcf77540a8d60885c814fedad81ce86e8b5255c9",
    "testharness"
   ],
   "css/css-backgrounds/box-shadow/box-shadow-blur-definition-001.xht": [
@@ -281090,7 +281095,7 @@
    "testharness"
   ],
   "css/css-backgrounds/parsing/resources/parsing-testcommon.js": [
-   "b5cc6f7c0c7729328bbbc45ec2a8147dae8d8668",
+   "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95",
    "support"
   ],
   "css/css-backgrounds/reference/60x60-green-background.html": [
@@ -281333,10 +281338,6 @@
    "121d1dcc21d4fb64b984bf54456bbe40d10f5dd9",
    "support"
   ],
-  "css/css-backgrounds/resources/parsing-testcommon.js": [
-   "b5cc6f7c0c7729328bbbc45ec2a8147dae8d8668",
-   "support"
-  ],
   "css/css-backgrounds/scroll-positioned-multiple-background-images.html": [
    "2fafa8d282711ae7b4a996ca5fe0fd9079c350c6",
    "reftest"
@@ -286502,11 +286503,11 @@
    "support"
   ],
   "css/css-fonts/alternates-order-ref.html": [
-   "5ca219e9f3b14418a44e771d6b00d487debe15af",
+   "9c5fe651a47243060ec7a30bc02cba7d85f853f2",
    "support"
   ],
   "css/css-fonts/alternates-order.html": [
-   "9232ad7768f5bea41d87469113b210b3c663750e",
+   "104ef4541a76b22dc574fc1a0dfbcb0fc822ef88",
    "reftest"
   ],
   "css/css-fonts/calc-in-font-variation-settings.html": [
@@ -296305,14 +296306,14 @@
    "ee2bd095839ad643e8e1fc4e9924d11ee8befc22",
    "testharness"
   ],
-  "css/css-images/parsing/image-resolution-invalid-expected.txt": [
-   "5b3eb98fba42f93d7154afd9d1eb6ca3ed316179",
-   "support"
-  ],
   "css/css-images/parsing/image-resolution-invalid.html": [
    "f48b7620d2e486815c51c616ddfa211739921dd4",
    "testharness"
   ],
+  "css/css-images/parsing/image-resolution-valid-expected.txt": [
+   "e4e56177c6b1d1a945cc13ecbf03a5858065ef02",
+   "support"
+  ],
   "css/css-images/parsing/image-resolution-valid.html": [
    "b5306320fe0ab963bfcd81874616d19866d9fea6",
    "testharness"
@@ -296338,7 +296339,7 @@
    "testharness"
   ],
   "css/css-images/parsing/resources/parsing-testcommon.js": [
-   "b5cc6f7c0c7729328bbbc45ec2a8147dae8d8668",
+   "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95",
    "support"
   ],
   "css/css-images/support/1x1-green.gif": [
@@ -299422,7 +299423,7 @@
    "testharness"
   ],
   "css/css-shapes/parsing/resources/parsing-testcommon.js": [
-   "b5cc6f7c0c7729328bbbc45ec2a8147dae8d8668",
+   "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95",
    "support"
   ],
   "css/css-shapes/parsing/shape-image-threshold-invalid.html": [
@@ -308878,7 +308879,7 @@
    "testharness"
   ],
   "css/css-transforms/parsing/resources/parsing-testcommon.js": [
-   "b5cc6f7c0c7729328bbbc45ec2a8147dae8d8668",
+   "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95",
    "support"
   ],
   "css/css-transforms/parsing/rotate-parsing-invalid.html": [
@@ -316562,7 +316563,7 @@
    "testharness"
   ],
   "css/css-ui/parsing/resources/parsing-testcommon.js": [
-   "b5cc6f7c0c7729328bbbc45ec2a8147dae8d8668",
+   "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95",
    "support"
   ],
   "css/css-ui/parsing/text-overflow-invalid.html": [
@@ -325970,7 +325971,7 @@
    "testharness"
   ],
   "css/motion/parsing/offset-path-parsing-valid-expected.txt": [
-   "b5f9bc844990511e454dd8323793a9aa9282399b",
+   "dd8003dfba27d2c6b4b90621085ac4b9f1001ce5",
    "support"
   ],
   "css/motion/parsing/offset-path-parsing-valid.html": [
@@ -325994,7 +325995,7 @@
    "testharness"
   ],
   "css/motion/parsing/resources/parsing-testcommon.js": [
-   "bb1376de12185a14f77fd28be757cc8db2a9929d",
+   "14f32b772f27a9bc75fe90e2ea1d8e4fb3649e95",
    "support"
   ],
   "css/reference/black_box_ends_when_blue_box_ends_6_boxes_ahem.html": [
@@ -337126,7 +337127,7 @@
    "testharness"
   ],
   "fetch/api/response/response-stream-disturbed-6.html": [
-   "af3dcd2f8918b5c1365191490d127dcf2cc35cd9",
+   "f55b1c4a1fd57c227f52abddf002bbf5f76bc455",
    "testharness"
   ],
   "fetch/api/response/response-stream-with-broken-then.any.js": [
@@ -377806,7 +377807,7 @@
    "support"
   ],
   "server-timing/cross_origin.html": [
-   "661cf7f329590a89aa2644a102a10d1ba34feb75",
+   "e20e60bef34167b4608a837d0ddb311effa20773",
    "testharness"
   ],
   "server-timing/navigation_timing_idl.html": [
@@ -377833,6 +377834,14 @@
    "549289fb534722e17eea4477638e8da59e043c13",
    "support"
   ],
+  "server-timing/resources/blue_tao.png": [
+   "7de5cdb5ad04ac365430b3b5f5ba01d2ba57ea23",
+   "support"
+  ],
+  "server-timing/resources/blue_tao.png.sub.headers": [
+   "b946f1d6581cf7a62aa01e0deda46cd04ef858c4",
+   "support"
+  ],
   "server-timing/resources/green.png": [
    "ef91d21307a12b2cfaf33a90dffe16aa1cba42c9",
    "support"
@@ -384322,7 +384331,7 @@
    "support"
   ],
   "url/README.md": [
-   "165b2a70da8bc2a7df3fe424a540f36b4f7be899",
+   "67bbc49a62ee08a94b7b55fff97e1160bf88bc33",
    "support"
   ],
   "url/a-element-origin-xhtml.xhtml": [
@@ -384358,7 +384367,7 @@
    "testharness"
   ],
   "url/failure.html": [
-   "908456e354703473b0806bbdac6d60216505905f",
+   "82c87b01a847f2821d1d71ea5e1c2ce8528f4deb",
    "testharness"
   ],
   "url/historical.any-expected.txt": [
@@ -384470,7 +384479,7 @@
    "testharness"
   ],
   "url/urltestdata.json": [
-   "59d1f7c678f29a70df885bdfbf9d491899f0038c",
+   "442c5f9d5faeb6752c8b33a04c73f3f3ba82ccb7",
    "support"
   ],
   "user-timing/OWNERS": [
@@ -388742,7 +388751,7 @@
    "support"
   ],
   "webstorage/OWNERS": [
-   "4e5fe0528ae51c9ac475c29195e1c473a5a01e1f",
+   "1efc045eed87783f0c6933f59d3dafa765b04ba9",
    "support"
   ],
   "webstorage/README.md": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/box-shadow-syntax-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/box-shadow-syntax-001.html
index a66c3b60..e7c83b3ec2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/box-shadow-syntax-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/box-shadow-syntax-001.html
@@ -5,7 +5,7 @@
 <meta name="assert" content="Box shadow color, inset, and length parameters can be mixed in any order, but lengths must stay adjacent." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/parsing-testcommon.js"></script>
+<script src="parsing/resources/parsing-testcommon.js"></script>
 <script>
   // color only
   test_valid_value("box-shadow", "4px 4px green", "green 4px 4px");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/parsing/resources/parsing-testcommon.js
index 9427f53..b075882 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/parsing/resources/parsing-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/parsing/resources/parsing-testcommon.js
@@ -12,18 +12,18 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_not_equals(div.style[property], "", "property should be set");
+        assert_not_equals(div.style.getPropertyValue(property), "", "property should be set");
 
         var div = document.createElement('div');
         div.style[property] = value;
-        var readValue = div.style[property];
+        var readValue = div.style.getPropertyValue(property);
         if (serializedValue instanceof Array)
-            assert_true(serializedValue.includes(readValue), "serialization should be sound");
+            assert_in_array(readValue, serializedValue, "serialization should be sound");
         else
             assert_equals(readValue, serializedValue, "serialization should be canonical");
 
         div.style[property] = readValue;
-        assert_equals(div.style[property], readValue, "serialization should round-trip");
+        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");
 
     }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
 }
@@ -34,6 +34,6 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_equals(div.style[property], "");
+        assert_equals(div.style.getPropertyValue(property), "");
     }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/resources/parsing-testcommon.js
deleted file mode 100644
index 9427f53..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-backgrounds/resources/parsing-testcommon.js
+++ /dev/null
@@ -1,39 +0,0 @@
-'use strict';
-
-// serializedValue can be the expected serialization of value,
-// or an array of permitted serializations,
-// or omitted if value should serialize as value.
-function test_valid_value(property, value, serializedValue) {
-    if (arguments.length < 3)
-        serializedValue = value;
-
-    var stringifiedValue = JSON.stringify(value);
-
-    test(function(){
-        var div = document.createElement('div');
-        div.style[property] = value;
-        assert_not_equals(div.style[property], "", "property should be set");
-
-        var div = document.createElement('div');
-        div.style[property] = value;
-        var readValue = div.style[property];
-        if (serializedValue instanceof Array)
-            assert_true(serializedValue.includes(readValue), "serialization should be sound");
-        else
-            assert_equals(readValue, serializedValue, "serialization should be canonical");
-
-        div.style[property] = readValue;
-        assert_equals(div.style[property], readValue, "serialization should round-trip");
-
-    }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
-}
-
-function test_invalid_value(property, value) {
-    var stringifiedValue = JSON.stringify(value);
-
-    test(function(){
-        var div = document.createElement('div');
-        div.style[property] = value;
-        assert_equals(div.style[property], "");
-    }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
-}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order-ref.html
index ed53a27..fdb477f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order-ref.html
@@ -19,6 +19,9 @@
   font-feature-settings: "ss05"; /* crossed W */
 }
 
+/* tests that should NOT use the feature, due to case-sensitivity of font-feature-values names */
+#test2, #test3 { font-feature-settings: "ss05" off; }
+
 </style>
 </head>
 <body lang="en">
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order.html
index e5310b3..d47cbce 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-fonts/alternates-order.html
@@ -65,13 +65,13 @@
 }
 
 #test2 {
-  /* testing case-insensitivity of styleset name */
+  /* testing case-sensitivity of styleset name */
   font-family: fontB;
   font-variant-alternates: styleset(altW);
 }
 
 #test3 {
-  /* testing case-insensitivity of styleset name */
+  /* testing case-sensitivity of styleset name */
   font-family: fontB;
   font-variant-alternates: styleset(ALTW);
 }
@@ -79,7 +79,7 @@
 #test4 {
   /* testing escapes in styleset name */
   font-family: fontB;
-  font-variant-alternates: styleset(\41 ltW);
+  font-variant-alternates: styleset(\41 lTw);
 }
 
 #test5 {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/image-resolution-invalid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/image-resolution-invalid-expected.txt
deleted file mode 100644
index e41d26f..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/image-resolution-invalid-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-FAIL e.style['image-resolution'] = "auto" should not set the property value assert_equals: expected "" but got "auto"
-FAIL e.style['image-resolution'] = "100%" should not set the property value assert_equals: expected "" but got "100%"
-FAIL e.style['image-resolution'] = "2" should not set the property value assert_equals: expected "" but got "2"
-FAIL e.style['image-resolution'] = "3dpi snap from-image" should not set the property value assert_equals: expected "" but got "3dpi snap from-image"
-FAIL e.style['image-resolution'] = "from-image snap 4dppx" should not set the property value assert_equals: expected "" but got "from-image snap 4dppx"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/image-resolution-valid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/image-resolution-valid-expected.txt
new file mode 100644
index 0000000..feb98a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/image-resolution-valid-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL e.style['image-resolution'] = "1dpi" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "2dpcm from-image" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "3dppx from-image snap" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "4dpi snap" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "from-image" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "from-image 5dpcm" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "from-image 6dppx snap" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "from-image snap" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "snap 7.5dpi" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "snap -8dpcm from-image" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "snap from-image" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['image-resolution'] = "snap from-image 0dppx" should set the property value assert_not_equals: property should be set got disallowed value ""
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/resources/parsing-testcommon.js
index 9427f53..b075882 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/resources/parsing-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-images/parsing/resources/parsing-testcommon.js
@@ -12,18 +12,18 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_not_equals(div.style[property], "", "property should be set");
+        assert_not_equals(div.style.getPropertyValue(property), "", "property should be set");
 
         var div = document.createElement('div');
         div.style[property] = value;
-        var readValue = div.style[property];
+        var readValue = div.style.getPropertyValue(property);
         if (serializedValue instanceof Array)
-            assert_true(serializedValue.includes(readValue), "serialization should be sound");
+            assert_in_array(readValue, serializedValue, "serialization should be sound");
         else
             assert_equals(readValue, serializedValue, "serialization should be canonical");
 
         div.style[property] = readValue;
-        assert_equals(div.style[property], readValue, "serialization should round-trip");
+        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");
 
     }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
 }
@@ -34,6 +34,6 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_equals(div.style[property], "");
+        assert_equals(div.style.getPropertyValue(property), "");
     }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/parsing/resources/parsing-testcommon.js
index 9427f53..b075882 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/parsing/resources/parsing-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-shapes/parsing/resources/parsing-testcommon.js
@@ -12,18 +12,18 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_not_equals(div.style[property], "", "property should be set");
+        assert_not_equals(div.style.getPropertyValue(property), "", "property should be set");
 
         var div = document.createElement('div');
         div.style[property] = value;
-        var readValue = div.style[property];
+        var readValue = div.style.getPropertyValue(property);
         if (serializedValue instanceof Array)
-            assert_true(serializedValue.includes(readValue), "serialization should be sound");
+            assert_in_array(readValue, serializedValue, "serialization should be sound");
         else
             assert_equals(readValue, serializedValue, "serialization should be canonical");
 
         div.style[property] = readValue;
-        assert_equals(div.style[property], readValue, "serialization should round-trip");
+        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");
 
     }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
 }
@@ -34,6 +34,6 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_equals(div.style[property], "");
+        assert_equals(div.style.getPropertyValue(property), "");
     }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/parsing/resources/parsing-testcommon.js
index 9427f53..b075882 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/parsing/resources/parsing-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/parsing/resources/parsing-testcommon.js
@@ -12,18 +12,18 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_not_equals(div.style[property], "", "property should be set");
+        assert_not_equals(div.style.getPropertyValue(property), "", "property should be set");
 
         var div = document.createElement('div');
         div.style[property] = value;
-        var readValue = div.style[property];
+        var readValue = div.style.getPropertyValue(property);
         if (serializedValue instanceof Array)
-            assert_true(serializedValue.includes(readValue), "serialization should be sound");
+            assert_in_array(readValue, serializedValue, "serialization should be sound");
         else
             assert_equals(readValue, serializedValue, "serialization should be canonical");
 
         div.style[property] = readValue;
-        assert_equals(div.style[property], readValue, "serialization should round-trip");
+        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");
 
     }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
 }
@@ -34,6 +34,6 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_equals(div.style[property], "");
+        assert_equals(div.style.getPropertyValue(property), "");
     }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/parsing/resources/parsing-testcommon.js
index 9427f53..b075882 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/parsing/resources/parsing-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/parsing/resources/parsing-testcommon.js
@@ -12,18 +12,18 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_not_equals(div.style[property], "", "property should be set");
+        assert_not_equals(div.style.getPropertyValue(property), "", "property should be set");
 
         var div = document.createElement('div');
         div.style[property] = value;
-        var readValue = div.style[property];
+        var readValue = div.style.getPropertyValue(property);
         if (serializedValue instanceof Array)
-            assert_true(serializedValue.includes(readValue), "serialization should be sound");
+            assert_in_array(readValue, serializedValue, "serialization should be sound");
         else
             assert_equals(readValue, serializedValue, "serialization should be canonical");
 
         div.style[property] = readValue;
-        assert_equals(div.style[property], readValue, "serialization should round-trip");
+        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");
 
     }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
 }
@@ -34,6 +34,6 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_equals(div.style[property], "");
+        assert_equals(div.style.getPropertyValue(property), "");
     }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt
index 2d0ddaa..bfae70a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt
@@ -1,31 +1,17 @@
 This is a testharness.js-based test.
 PASS e.style['offset-path'] = "none" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "none"
 PASS e.style['offset-path'] = "ray(0rad closest-side)" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "ray(0rad closest-side)"
 PASS e.style['offset-path'] = "ray(0.25turn closest-corner contain)" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "ray(0.25turn closest-corner contain)"
 PASS e.style['offset-path'] = "ray(200grad farthest-side)" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "ray(200grad farthest-side)"
 PASS e.style['offset-path'] = "ray(270deg farthest-corner contain)" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "ray(270deg farthest-corner contain)"
 PASS e.style['offset-path'] = "ray(-720deg sides)" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "ray(-720deg sides)"
 PASS e.style['offset-path'] = "ray(calc(180deg - 45deg) farthest-side)" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "ray(calc(180deg - 45deg) farthest-side)"
 PASS e.style['offset-path'] = "path('m 0 0 h -100')" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "path('m 0 0 h -100')"
 PASS e.style['offset-path'] = "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z')" should set the property value
-PASS Serialization should round-trip after setting e.style['offset-path'] = "path('M 0 0 L 100 100 M 100 200 L 200 200 Z L 300 300 Z')"
-FAIL e.style['offset-path'] = "url(\"http://www.example.com/index.html#polyline1\")" should set the property value assert_not_equals: got disallowed value ""
-FAIL Serialization should round-trip after setting e.style['offset-path'] = "url(\"http://www.example.com/index.html#polyline1\")" assert_equals: expected "url(\"http://www.example.com/index.html#polyline1\")" but got ""
-FAIL e.style['offset-path'] = "circle(100px)" should set the property value assert_not_equals: got disallowed value ""
-FAIL Serialization should round-trip after setting e.style['offset-path'] = "circle(100px)" assert_equals: expected "circle(100px)" but got ""
-FAIL e.style['offset-path'] = "margin-box" should set the property value assert_not_equals: got disallowed value ""
-FAIL Serialization should round-trip after setting e.style['offset-path'] = "margin-box" assert_equals: expected "margin-box" but got ""
-FAIL e.style['offset-path'] = "inset(10% 20% 30% 40%) border-box" should set the property value assert_not_equals: got disallowed value ""
-FAIL Serialization should round-trip after setting e.style['offset-path'] = "inset(10% 20% 30% 40%) border-box" assert_equals: expected "inset(10% 20% 30% 40%) border-box" but got ""
-FAIL e.style['offset-path'] = "fill-box ellipse(50% 60%)" should set the property value assert_not_equals: got disallowed value ""
-FAIL Serialization should round-trip after setting e.style['offset-path'] = "fill-box ellipse(50% 60%)" assert_equals: expected "ellipse(50% 60%) fill-box" but got ""
+FAIL e.style['offset-path'] = "url(\"http://www.example.com/index.html#polyline1\")" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['offset-path'] = "circle(100px)" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['offset-path'] = "margin-box" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['offset-path'] = "inset(10% 20% 30% 40%) border-box" should set the property value assert_not_equals: property should be set got disallowed value ""
+FAIL e.style['offset-path'] = "fill-box ellipse(50% 60%)" should set the property value assert_not_equals: property should be set got disallowed value ""
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/resources/parsing-testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/resources/parsing-testcommon.js
index 688356b..b075882 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/resources/parsing-testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/motion/parsing/resources/parsing-testcommon.js
@@ -1,5 +1,8 @@
 'use strict';
 
+// serializedValue can be the expected serialization of value,
+// or an array of permitted serializations,
+// or omitted if value should serialize as value.
 function test_valid_value(property, value, serializedValue) {
     if (arguments.length < 3)
         serializedValue = value;
@@ -9,17 +12,20 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_not_equals(div.style[property], "");
-    }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
+        assert_not_equals(div.style.getPropertyValue(property), "", "property should be set");
 
-    test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        var readValue = div.style[property];
-        assert_equals(readValue, serializedValue);
+        var readValue = div.style.getPropertyValue(property);
+        if (serializedValue instanceof Array)
+            assert_in_array(readValue, serializedValue, "serialization should be sound");
+        else
+            assert_equals(readValue, serializedValue, "serialization should be canonical");
+
         div.style[property] = readValue;
-        assert_equals(div.style[property], readValue);
-    }, "Serialization should round-trip after setting e.style['" + property + "'] = " + stringifiedValue);
+        assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip");
+
+    }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value");
 }
 
 function test_invalid_value(property, value) {
@@ -28,6 +34,6 @@
     test(function(){
         var div = document.createElement('div');
         div.style[property] = value;
-        assert_equals(div.style[property], "");
+        assert_equals(div.style.getPropertyValue(property), "");
     }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value");
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-stream-disturbed-6.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-stream-disturbed-6.html
index 15c8dfd..30492d4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-stream-disturbed-6.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-stream-disturbed-6.html
@@ -65,7 +65,7 @@
   const reader = stream.getReader();
   assert_false(response.bodyUsed, "After getting a reader");
 
-  reader.read();
+  reader.read().then(() => { }, () => { });
   assert_true(response.bodyUsed, "After calling stream.read()");
 }, "An errored stream on which read() has been called");
 
@@ -81,7 +81,7 @@
   const reader = stream.getReader();
   assert_false(response.bodyUsed, "After getting a reader");
 
-  reader.cancel();
+  reader.cancel().then(() => { }, () => { });
   assert_true(response.bodyUsed, "After calling stream.cancel()");
 }, "An errored stream on which cancel() has been called");
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.html b/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.html
index f525103..94c502ee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/cross_origin.html
@@ -9,10 +9,10 @@
       setup({explicit_done: true})
 
       const hostInfo = get_host_info()
-      const resourceUrl = 'server-timing/resources/blue.png'
       const urls = {
-        'same-origin': `${hostInfo.HTTP_ORIGIN}/${resourceUrl}`,
-        'cross-origin': `${hostInfo.HTTP_REMOTE_ORIGIN}/${resourceUrl}`
+        'same-origin': `${hostInfo.HTTP_ORIGIN}/server-timing/resources/blue.png`,
+        'cross-origin': `${hostInfo.HTTP_REMOTE_ORIGIN}/server-timing/resources/blue.png`,
+        'cross-origin-tao': `${hostInfo.HTTP_REMOTE_ORIGIN}/server-timing/resources/blue_tao.png`
       }
       Object.keys(urls).forEach(function(key) {
         const img = document.createElement('img')
@@ -28,6 +28,7 @@
         }
         assertServerTimingEntries(urls['same-origin'], 1)
         assertServerTimingEntries(urls['cross-origin'], 0)
+        assertServerTimingEntries(urls['cross-origin-tao'], 1)
         done()
       })
     </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/resources/blue_tao.png b/third_party/WebKit/LayoutTests/external/wpt/server-timing/resources/blue_tao.png
new file mode 100644
index 0000000..4498dd2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/resources/blue_tao.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/server-timing/resources/blue_tao.png.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/server-timing/resources/blue_tao.png.sub.headers
new file mode 100644
index 0000000..3ca09d6a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/server-timing/resources/blue_tao.png.sub.headers
@@ -0,0 +1,2 @@
+Timing-Allow-Origin: *
+Server-Timing: metric2; dur=2.1; desc=blue.png
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/README.md b/third_party/WebKit/LayoutTests/external/wpt/url/README.md
index 4cb3c00..cc63177a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/README.md
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/README.md
@@ -1,10 +1,10 @@
 These tests are for browsers, but the data for
-`a-element.html`, `url-constructor.html`, and `a-element-xhtml.xhtml`
+`a-element.html`, `url-constructor.html`, `a-element-xhtml.xhtml`, and `failure.html`
 is in `urltestdata.json` and can be re-used by non-browser implementations.
 This file contains a JSON array of comments as strings and test cases as objects.
 The keys for each test case are:
 
-* `base`: an absolute URL as a string whose [parsing] without a base of its own should succeed.
+* `base`: an absolute URL as a string whose [parsing] without a base of its own must succeed.
   This key is always present,
   and may have a value like `"about:blank"` when `input` is an absolute URL.
 * `input`: an URL as a string to be [parsed][parsing] with `base` as its base URL.
@@ -19,5 +19,11 @@
     The `origin` key may be missing.
     In that case, the API’s `origin` attribute is not tested.
 
+In addition to testing that parsing `input` against `base` gives the result, a test harness for the
+`URL` constructor (or similar APIs) should additionally test the following pattern: if `failure` is
+true, parsing `about:blank` against `base` must give failure. This tests that the logic for
+converting base URLs into strings properly fails the whole parsing algorithm if the base URL cannot
+be parsed.
+
 [parsing]: https://url.spec.whatwg.org/#concept-basic-url-parser
 [API]: https://url.spec.whatwg.org/#api
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/failure.html b/third_party/WebKit/LayoutTests/external/wpt/url/failure.html
index d097d4e3..8ae9da7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/failure.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/failure.html
@@ -16,7 +16,13 @@
 
     const name = test.input + " should throw"
 
-    self.test(() => { // new URL itself is already tested by url-constructor.html
+    self.test(() => { // URL's constructor's first argument is tested by url-constructor.html
+      // If a URL fails to parse with any valid base, it must also fail to parse with no base, i.e.
+      // when used as a base URL itself.
+      assert_throws(new TypeError(), () => new URL("about:blank", test.input));
+    }, "URL's constructor's base argument: " + name)
+
+    self.test(() => {
       const url = new URL("about:blank")
       assert_throws(new TypeError, () => url.href = test.input)
     }, "URL's href: " + name)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json b/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json
index 8670566..8c87da2b 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/urltestdata.json
@@ -6521,28 +6521,35 @@
     "search": "?a",
     "hash": "#%GH"
   },
-  "Bad bases",
+  "URLs that require a non-about:blank base. (Also serve as invalid base tests.)",
   {
-    "input": "test-a.html",
-    "base": "a",
+    "input": "a",
+    "base": "about:blank",
     "failure": true
   },
   {
-    "input": "test-a-slash.html",
-    "base": "a/",
+    "input": "a/",
+    "base": "about:blank",
     "failure": true
   },
   {
-    "input": "test-a-slash-slash.html",
-    "base": "a//",
+    "input": "a//",
+    "base": "about:blank",
     "failure": true
   },
+  "Bases that don't fail to parse but fail to be bases",
   {
     "input": "test-a-colon.html",
     "base": "a:",
     "failure": true
   },
   {
+    "input": "test-a-colon-b.html",
+    "base": "a:b",
+    "failure": true
+  },
+  "Other base URL tests, that must succeed",
+  {
     "input": "test-a-colon-slash.html",
     "base": "a:/",
     "href": "a:/test-a-colon-slash.html",
@@ -6571,11 +6578,6 @@
     "hash": ""
   },
   {
-    "input": "test-a-colon-b.html",
-    "base": "a:b",
-    "failure": true
-  },
-  {
     "input": "test-a-colon-slash-b.html",
     "base": "a:/b",
     "href": "a:/test-a-colon-slash-b.html",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/service-worker-interception-tests.js b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/service-worker-interception-tests.js
index 310b26d..16d29873 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/service-worker-interception-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/worklets/resources/service-worker-interception-tests.js
@@ -120,6 +120,4 @@
             })
           .then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
     }, 'Static import should be intercepted by a service worker.');
-
-    // TODO(nhiroki): Add tests for dynamic import.
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/performance-timing/custom-user-timing/po-customusertiming-featuredetection.html b/third_party/WebKit/LayoutTests/http/tests/performance-timing/custom-user-timing/po-customusertiming-featuredetection.html
index 66ff5a8..94c4681 100644
--- a/third_party/WebKit/LayoutTests/http/tests/performance-timing/custom-user-timing/po-customusertiming-featuredetection.html
+++ b/third_party/WebKit/LayoutTests/http/tests/performance-timing/custom-user-timing/po-customusertiming-featuredetection.html
@@ -10,8 +10,15 @@
   async_test(function (t) {
     self.performance.clearMeasures();
     const measure = self.performance.measure("measure1",
-        { startTime: 12, endTime:23, detail: {info: 45 }});
+        { startTime: 12, endTime:23 });
     assert_equals(measure.startTime, 12);
     t.done();
   }, "L3 measure API returns a measure object.");
+
+  async_test(function (t) {
+    self.performance.clearMarks();
+    const mark = self.performance.mark("mark1", { startTime: 34 });
+    assert_equals(mark.startTime, 34);
+    t.done();
+  }, "L3 mark API returns a mark object.");
 </script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt
index 36a4506db..eb650196 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-expected.txt
@@ -513,13 +513,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-FAIL Parsing: <test-a.html> against <a> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash.html> against <a/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash-slash.html> against <a//> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got ""
+FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got ""
+FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got ""
 FAIL Parsing: <test-a-colon.html> against <a:> assert_equals: failure should set href to input expected "test-a-colon.html" but got ""
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash.html> against <a:/>
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got ""
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash-b.html> against <a:/b>
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "a://b"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
index 36a4506db..eb650196 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/a-element-xhtml-expected.txt
@@ -513,13 +513,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-FAIL Parsing: <test-a.html> against <a> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash.html> against <a/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash-slash.html> against <a//> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got ""
+FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got ""
+FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got ""
 FAIL Parsing: <test-a-colon.html> against <a:> assert_equals: failure should set href to input expected "test-a-colon.html" but got ""
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash.html> against <a:/>
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got ""
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash-b.html> against <a:/b>
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "a://b"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/failure-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/failure-expected.txt
index 2ec1c09..8b80809 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/failure-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/failure-expected.txt
@@ -1,250 +1,317 @@
 This is a testharness.js-based test.
-Found 246 tests; 101 PASS, 145 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 313 tests; 142 PASS, 171 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
+PASS URL's constructor's base argument: file://example:1/ should throw
 FAIL URL's href: file://example:1/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example:1/ should throw
 PASS sendBeacon(): file://example:1/ should throw
 FAIL Location's href: file://example:1/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example:1/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example:1/ should throw
+PASS URL's constructor's base argument: file://example:test/ should throw
 FAIL URL's href: file://example:test/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example:test/ should throw
 PASS sendBeacon(): file://example:test/ should throw
 FAIL Location's href: file://example:test/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example:test/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example:test/ should throw
+PASS URL's constructor's base argument: file://example%/ should throw
 FAIL URL's href: file://example%/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example%/ should throw
 PASS sendBeacon(): file://example%/ should throw
 FAIL Location's href: file://example%/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example%/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example%/ should throw
+PASS URL's constructor's base argument: file://[example]/ should throw
 FAIL URL's href: file://[example]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://[example]/ should throw
 PASS sendBeacon(): file://[example]/ should throw
 FAIL Location's href: file://[example]/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://[example]/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://[example]/ should throw
+PASS URL's constructor's base argument: http://user:pass@/ should throw
 FAIL URL's href: http://user:pass@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://user:pass@/ should throw
 PASS sendBeacon(): http://user:pass@/ should throw
 FAIL Location's href: http://user:pass@/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://user:pass@/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://user:pass@/ should throw
+PASS URL's constructor's base argument: http://foo:-80/ should throw
 FAIL URL's href: http://foo:-80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://foo:-80/ should throw
 PASS sendBeacon(): http://foo:-80/ should throw
 FAIL Location's href: http://foo:-80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://foo:-80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://foo:-80/ should throw
+PASS URL's constructor's base argument: http:/:@/www.example.com should throw
 FAIL URL's href: http:/:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/:@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/:@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/:@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://user@/www.example.com should throw
 FAIL URL's href: http://user@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://user@/www.example.com should throw
 PASS sendBeacon(): http://user@/www.example.com should throw
 FAIL Location's href: http://user@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://user@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://user@/www.example.com should throw
+PASS URL's constructor's base argument: http:@/www.example.com should throw
 FAIL URL's href: http:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/@/www.example.com should throw
 FAIL URL's href: http:/@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://@/www.example.com should throw
 FAIL URL's href: http://@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://@/www.example.com should throw
 PASS sendBeacon(): http://@/www.example.com should throw
 FAIL Location's href: http://@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://@/www.example.com should throw
+PASS URL's constructor's base argument: https:@/www.example.com should throw
 FAIL URL's href: https:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https:@/www.example.com should throw
 PASS sendBeacon(): https:@/www.example.com should throw
 FAIL Location's href: https:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https:@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https:@/www.example.com should throw
+PASS URL's constructor's base argument: http:a:b@/www.example.com should throw
 FAIL URL's href: http:a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:a:b@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:a:b@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:a:b@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/a:b@/www.example.com should throw
 FAIL URL's href: http:/a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/a:b@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/a:b@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/a:b@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://a:b@/www.example.com should throw
 FAIL URL's href: http://a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://a:b@/www.example.com should throw
 PASS sendBeacon(): http://a:b@/www.example.com should throw
 FAIL Location's href: http://a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://a:b@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://a:b@/www.example.com should throw
+PASS URL's constructor's base argument: http::@/www.example.com should throw
 FAIL URL's href: http::@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http::@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http::@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http::@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http::@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:@:www.example.com should throw
 FAIL URL's href: http:@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:@:www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:@:www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:@:www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/@:www.example.com should throw
 FAIL URL's href: http:/@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/@:www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/@:www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/@:www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://@:www.example.com should throw
 FAIL URL's href: http://@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://@:www.example.com should throw
 PASS sendBeacon(): http://@:www.example.com should throw
 FAIL Location's href: http://@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://@:www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://@:www.example.com should throw
+PASS URL's constructor's base argument: https://� should throw
 FAIL URL's href: https://� should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://� should throw
 PASS sendBeacon(): https://� should throw
 FAIL Location's href: https://� should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://�' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://� should throw
+PASS URL's constructor's base argument: https://%EF%BF%BD should throw
 FAIL URL's href: https://%EF%BF%BD should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://%EF%BF%BD should throw
 PASS sendBeacon(): https://%EF%BF%BD should throw
 FAIL Location's href: https://%EF%BF%BD should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://%EF%BF%BD' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://%EF%BF%BD should throw
+FAIL URL's constructor's base argument: https://x x:12 should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: https://x x:12 should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: https://x x:12 should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): https://x x:12 should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: https://x x:12 should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): https://x x:12 should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://[www.google.com]/ should throw
 FAIL URL's href: http://[www.google.com]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://[www.google.com]/ should throw
 PASS sendBeacon(): http://[www.google.com]/ should throw
 FAIL Location's href: http://[www.google.com]/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://[www.google.com]/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://[www.google.com]/ should throw
+FAIL URL's constructor's base argument: sc://\0/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://\0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://\0/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://\0/ should throw
 FAIL Location's href: sc://\0/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://\0/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc:// / should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc:// / should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc:// / should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc:// / should throw
 FAIL Location's href: sc:// / should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc:// / should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://@/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://@/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://@/ should throw
 FAIL Location's href: sc://@/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://@/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://te@s:t@/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://te@s:t@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://te@s:t@/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://te@s:t@/ should throw
 FAIL Location's href: sc://te@s:t@/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://te@s:t@/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://:/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://:/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://:/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://:/ should throw
 FAIL Location's href: sc://:/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://:/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://:12/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://:12/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://:12/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://:12/ should throw
 FAIL Location's href: sc://:12/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://:12/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://[/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://[/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://[/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://[/ should throw
 FAIL Location's href: sc://[/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://[/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://\/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://\/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://\/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://\/ should throw
 FAIL Location's href: sc://\/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://\/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://]/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://]/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://]/ should throw
 FAIL Location's href: sc://]/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://]/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: ftp://example.com%80/ should throw
 FAIL URL's href: ftp://example.com%80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: ftp://example.com%80/ should throw
 PASS sendBeacon(): ftp://example.com%80/ should throw
 FAIL Location's href: ftp://example.com%80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'ftp://example.com%80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): ftp://example.com%80/ should throw
+PASS URL's constructor's base argument: ftp://example.com%A0/ should throw
 FAIL URL's href: ftp://example.com%A0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: ftp://example.com%A0/ should throw
 PASS sendBeacon(): ftp://example.com%A0/ should throw
 FAIL Location's href: ftp://example.com%A0/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'ftp://example.com%A0/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): ftp://example.com%A0/ should throw
+PASS URL's constructor's base argument: https://example.com%80/ should throw
 FAIL URL's href: https://example.com%80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://example.com%80/ should throw
 PASS sendBeacon(): https://example.com%80/ should throw
 FAIL Location's href: https://example.com%80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://example.com%80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://example.com%80/ should throw
+PASS URL's constructor's base argument: https://example.com%A0/ should throw
 FAIL URL's href: https://example.com%A0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://example.com%A0/ should throw
 PASS sendBeacon(): https://example.com%A0/ should throw
 FAIL Location's href: https://example.com%A0/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://example.com%A0/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://example.com%A0/ should throw
+PASS URL's constructor's base argument: https://0x100000000/test should throw
 FAIL URL's href: https://0x100000000/test should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://0x100000000/test should throw
 PASS sendBeacon(): https://0x100000000/test should throw
 FAIL Location's href: https://0x100000000/test should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://0x100000000/test' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://0x100000000/test should throw
+PASS URL's constructor's base argument: https://256.0.0.1/test should throw
 FAIL URL's href: https://256.0.0.1/test should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://256.0.0.1/test should throw
 PASS sendBeacon(): https://256.0.0.1/test should throw
 FAIL Location's href: https://256.0.0.1/test should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://256.0.0.1/test' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://256.0.0.1/test should throw
+PASS URL's constructor's base argument: https://[0::0::0] should throw
 FAIL URL's href: https://[0::0::0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0::0::0] should throw
 PASS sendBeacon(): https://[0::0::0] should throw
 FAIL Location's href: https://[0::0::0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0::0::0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0::0::0] should throw
+PASS URL's constructor's base argument: https://[0:.0] should throw
 FAIL URL's href: https://[0:.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:.0] should throw
 PASS sendBeacon(): https://[0:.0] should throw
 FAIL Location's href: https://[0:.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:.0] should throw
+PASS URL's constructor's base argument: https://[0:0:] should throw
 FAIL URL's href: https://[0:0:] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:0:] should throw
 PASS sendBeacon(): https://[0:0:] should throw
 FAIL Location's href: https://[0:0:] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:0:]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:0:] should throw
+PASS URL's constructor's base argument: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 FAIL URL's href: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 PASS sendBeacon(): https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 FAIL Location's href: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1:2:3:4:5:6:7.0.0.0.1]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
+PASS URL's constructor's base argument: https://[0:1.00.0.0.0] should throw
 FAIL URL's href: https://[0:1.00.0.0.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.00.0.0.0] should throw
 PASS sendBeacon(): https://[0:1.00.0.0.0] should throw
 FAIL Location's href: https://[0:1.00.0.0.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.00.0.0.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.00.0.0.0] should throw
+PASS URL's constructor's base argument: https://[0:1.290.0.0.0] should throw
 FAIL URL's href: https://[0:1.290.0.0.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.290.0.0.0] should throw
 PASS sendBeacon(): https://[0:1.290.0.0.0] should throw
 FAIL Location's href: https://[0:1.290.0.0.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.290.0.0.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.290.0.0.0] should throw
+PASS URL's constructor's base argument: https://[0:1.23.23] should throw
 FAIL URL's href: https://[0:1.23.23] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.23.23] should throw
 PASS sendBeacon(): https://[0:1.23.23] should throw
 FAIL Location's href: https://[0:1.23.23] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.23.23]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.23.23] should throw
+PASS URL's constructor's base argument: http://? should throw
 FAIL URL's href: http://? should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://? should throw
 PASS sendBeacon(): http://? should throw
 FAIL Location's href: http://? should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://?' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://? should throw
+PASS URL's constructor's base argument: http://# should throw
 FAIL URL's href: http://# should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://# should throw
 PASS sendBeacon(): http://# should throw
 FAIL Location's href: http://# should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://#' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://# should throw
+FAIL URL's constructor's base argument: non-special://[:80/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: non-special://[:80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: non-special://[:80/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): non-special://[:80/ should throw
 FAIL Location's href: non-special://[:80/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): non-special://[:80/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://[::127.0.0.0.1] should throw
 FAIL URL's href: http://[::127.0.0.0.1] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://[::127.0.0.0.1] should throw
 PASS sendBeacon(): http://[::127.0.0.0.1] should throw
 FAIL Location's href: http://[::127.0.0.0.1] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://[::127.0.0.0.1]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://[::127.0.0.0.1] should throw
+PASS URL's constructor's base argument: a should throw
+FAIL URL's href: a should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: a/ should throw
+FAIL URL's href: a/ should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a/ should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: a// should throw
+FAIL URL's href: a// should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a// should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a// should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a// should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a// should throw assert_throws: function "() => self.open(test.input).close()" did not throw
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt
index 201e4a9..7e91ddd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/url/url-constructor-expected.txt
@@ -559,13 +559,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-PASS Parsing: <test-a.html> against <a>
-PASS Parsing: <test-a-slash.html> against <a/>
-PASS Parsing: <test-a-slash-slash.html> against <a//>
+PASS Parsing: <a> against <about:blank>
+PASS Parsing: <a/> against <about:blank>
+PASS Parsing: <a//> against <about:blank>
 PASS Parsing: <test-a-colon.html> against <a:>
+PASS Parsing: <test-a-colon-b.html> against <a:b>
 PASS Parsing: <test-a-colon-slash.html> against <a:/>
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> Failed to construct 'URL': Invalid URL
-PASS Parsing: <test-a-colon-b.html> against <a:b>
 PASS Parsing: <test-a-colon-slash-b.html> against <a:/b>
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> Failed to construct 'URL': Invalid URL
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt
index 36a4506db..eb650196 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-expected.txt
@@ -513,13 +513,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-FAIL Parsing: <test-a.html> against <a> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash.html> against <a/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash-slash.html> against <a//> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got ""
+FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got ""
+FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got ""
 FAIL Parsing: <test-a-colon.html> against <a:> assert_equals: failure should set href to input expected "test-a-colon.html" but got ""
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash.html> against <a:/>
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got ""
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash-b.html> against <a:/b>
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "a://b"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
index 36a4506db..eb650196 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/a-element-xhtml-expected.txt
@@ -513,13 +513,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-FAIL Parsing: <test-a.html> against <a> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash.html> against <a/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash-slash.html> against <a//> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got ""
+FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got ""
+FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got ""
 FAIL Parsing: <test-a-colon.html> against <a:> assert_equals: failure should set href to input expected "test-a-colon.html" but got ""
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash.html> against <a:/>
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got ""
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_equals: failure should set href to input expected "test-a-colon-b.html" but got ""
 PASS Parsing: <test-a-colon-slash-b.html> against <a:/b>
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "a://b"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/failure-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/failure-expected.txt
index 2ec1c09..8b80809 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/failure-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/failure-expected.txt
@@ -1,250 +1,317 @@
 This is a testharness.js-based test.
-Found 246 tests; 101 PASS, 145 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 313 tests; 142 PASS, 171 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
+PASS URL's constructor's base argument: file://example:1/ should throw
 FAIL URL's href: file://example:1/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example:1/ should throw
 PASS sendBeacon(): file://example:1/ should throw
 FAIL Location's href: file://example:1/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example:1/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example:1/ should throw
+PASS URL's constructor's base argument: file://example:test/ should throw
 FAIL URL's href: file://example:test/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example:test/ should throw
 PASS sendBeacon(): file://example:test/ should throw
 FAIL Location's href: file://example:test/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example:test/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example:test/ should throw
+PASS URL's constructor's base argument: file://example%/ should throw
 FAIL URL's href: file://example%/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example%/ should throw
 PASS sendBeacon(): file://example%/ should throw
 FAIL Location's href: file://example%/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example%/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example%/ should throw
+PASS URL's constructor's base argument: file://[example]/ should throw
 FAIL URL's href: file://[example]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://[example]/ should throw
 PASS sendBeacon(): file://[example]/ should throw
 FAIL Location's href: file://[example]/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://[example]/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://[example]/ should throw
+PASS URL's constructor's base argument: http://user:pass@/ should throw
 FAIL URL's href: http://user:pass@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://user:pass@/ should throw
 PASS sendBeacon(): http://user:pass@/ should throw
 FAIL Location's href: http://user:pass@/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://user:pass@/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://user:pass@/ should throw
+PASS URL's constructor's base argument: http://foo:-80/ should throw
 FAIL URL's href: http://foo:-80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://foo:-80/ should throw
 PASS sendBeacon(): http://foo:-80/ should throw
 FAIL Location's href: http://foo:-80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://foo:-80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://foo:-80/ should throw
+PASS URL's constructor's base argument: http:/:@/www.example.com should throw
 FAIL URL's href: http:/:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/:@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/:@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/:@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://user@/www.example.com should throw
 FAIL URL's href: http://user@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://user@/www.example.com should throw
 PASS sendBeacon(): http://user@/www.example.com should throw
 FAIL Location's href: http://user@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://user@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://user@/www.example.com should throw
+PASS URL's constructor's base argument: http:@/www.example.com should throw
 FAIL URL's href: http:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/@/www.example.com should throw
 FAIL URL's href: http:/@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://@/www.example.com should throw
 FAIL URL's href: http://@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://@/www.example.com should throw
 PASS sendBeacon(): http://@/www.example.com should throw
 FAIL Location's href: http://@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://@/www.example.com should throw
+PASS URL's constructor's base argument: https:@/www.example.com should throw
 FAIL URL's href: https:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https:@/www.example.com should throw
 PASS sendBeacon(): https:@/www.example.com should throw
 FAIL Location's href: https:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https:@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https:@/www.example.com should throw
+PASS URL's constructor's base argument: http:a:b@/www.example.com should throw
 FAIL URL's href: http:a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:a:b@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:a:b@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:a:b@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/a:b@/www.example.com should throw
 FAIL URL's href: http:/a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/a:b@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/a:b@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/a:b@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://a:b@/www.example.com should throw
 FAIL URL's href: http://a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://a:b@/www.example.com should throw
 PASS sendBeacon(): http://a:b@/www.example.com should throw
 FAIL Location's href: http://a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://a:b@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://a:b@/www.example.com should throw
+PASS URL's constructor's base argument: http::@/www.example.com should throw
 FAIL URL's href: http::@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http::@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http::@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http::@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http::@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:@:www.example.com should throw
 FAIL URL's href: http:@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:@:www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:@:www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:@:www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/@:www.example.com should throw
 FAIL URL's href: http:/@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/@:www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/@:www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/@:www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://@:www.example.com should throw
 FAIL URL's href: http://@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://@:www.example.com should throw
 PASS sendBeacon(): http://@:www.example.com should throw
 FAIL Location's href: http://@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://@:www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://@:www.example.com should throw
+PASS URL's constructor's base argument: https://� should throw
 FAIL URL's href: https://� should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://� should throw
 PASS sendBeacon(): https://� should throw
 FAIL Location's href: https://� should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://�' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://� should throw
+PASS URL's constructor's base argument: https://%EF%BF%BD should throw
 FAIL URL's href: https://%EF%BF%BD should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://%EF%BF%BD should throw
 PASS sendBeacon(): https://%EF%BF%BD should throw
 FAIL Location's href: https://%EF%BF%BD should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://%EF%BF%BD' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://%EF%BF%BD should throw
+FAIL URL's constructor's base argument: https://x x:12 should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: https://x x:12 should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: https://x x:12 should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): https://x x:12 should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: https://x x:12 should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): https://x x:12 should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://[www.google.com]/ should throw
 FAIL URL's href: http://[www.google.com]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://[www.google.com]/ should throw
 PASS sendBeacon(): http://[www.google.com]/ should throw
 FAIL Location's href: http://[www.google.com]/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://[www.google.com]/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://[www.google.com]/ should throw
+FAIL URL's constructor's base argument: sc://\0/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://\0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://\0/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://\0/ should throw
 FAIL Location's href: sc://\0/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://\0/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc:// / should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc:// / should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc:// / should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc:// / should throw
 FAIL Location's href: sc:// / should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc:// / should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://@/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://@/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://@/ should throw
 FAIL Location's href: sc://@/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://@/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://te@s:t@/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://te@s:t@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://te@s:t@/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://te@s:t@/ should throw
 FAIL Location's href: sc://te@s:t@/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://te@s:t@/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://:/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://:/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://:/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://:/ should throw
 FAIL Location's href: sc://:/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://:/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://:12/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://:12/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://:12/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://:12/ should throw
 FAIL Location's href: sc://:12/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://:12/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://[/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://[/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://[/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://[/ should throw
 FAIL Location's href: sc://[/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://[/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://\/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://\/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://\/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://\/ should throw
 FAIL Location's href: sc://\/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://\/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://]/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://]/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://]/ should throw
 FAIL Location's href: sc://]/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://]/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: ftp://example.com%80/ should throw
 FAIL URL's href: ftp://example.com%80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: ftp://example.com%80/ should throw
 PASS sendBeacon(): ftp://example.com%80/ should throw
 FAIL Location's href: ftp://example.com%80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'ftp://example.com%80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): ftp://example.com%80/ should throw
+PASS URL's constructor's base argument: ftp://example.com%A0/ should throw
 FAIL URL's href: ftp://example.com%A0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: ftp://example.com%A0/ should throw
 PASS sendBeacon(): ftp://example.com%A0/ should throw
 FAIL Location's href: ftp://example.com%A0/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'ftp://example.com%A0/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): ftp://example.com%A0/ should throw
+PASS URL's constructor's base argument: https://example.com%80/ should throw
 FAIL URL's href: https://example.com%80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://example.com%80/ should throw
 PASS sendBeacon(): https://example.com%80/ should throw
 FAIL Location's href: https://example.com%80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://example.com%80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://example.com%80/ should throw
+PASS URL's constructor's base argument: https://example.com%A0/ should throw
 FAIL URL's href: https://example.com%A0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://example.com%A0/ should throw
 PASS sendBeacon(): https://example.com%A0/ should throw
 FAIL Location's href: https://example.com%A0/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://example.com%A0/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://example.com%A0/ should throw
+PASS URL's constructor's base argument: https://0x100000000/test should throw
 FAIL URL's href: https://0x100000000/test should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://0x100000000/test should throw
 PASS sendBeacon(): https://0x100000000/test should throw
 FAIL Location's href: https://0x100000000/test should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://0x100000000/test' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://0x100000000/test should throw
+PASS URL's constructor's base argument: https://256.0.0.1/test should throw
 FAIL URL's href: https://256.0.0.1/test should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://256.0.0.1/test should throw
 PASS sendBeacon(): https://256.0.0.1/test should throw
 FAIL Location's href: https://256.0.0.1/test should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://256.0.0.1/test' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://256.0.0.1/test should throw
+PASS URL's constructor's base argument: https://[0::0::0] should throw
 FAIL URL's href: https://[0::0::0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0::0::0] should throw
 PASS sendBeacon(): https://[0::0::0] should throw
 FAIL Location's href: https://[0::0::0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0::0::0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0::0::0] should throw
+PASS URL's constructor's base argument: https://[0:.0] should throw
 FAIL URL's href: https://[0:.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:.0] should throw
 PASS sendBeacon(): https://[0:.0] should throw
 FAIL Location's href: https://[0:.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:.0] should throw
+PASS URL's constructor's base argument: https://[0:0:] should throw
 FAIL URL's href: https://[0:0:] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:0:] should throw
 PASS sendBeacon(): https://[0:0:] should throw
 FAIL Location's href: https://[0:0:] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:0:]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:0:] should throw
+PASS URL's constructor's base argument: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 FAIL URL's href: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 PASS sendBeacon(): https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 FAIL Location's href: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1:2:3:4:5:6:7.0.0.0.1]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
+PASS URL's constructor's base argument: https://[0:1.00.0.0.0] should throw
 FAIL URL's href: https://[0:1.00.0.0.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.00.0.0.0] should throw
 PASS sendBeacon(): https://[0:1.00.0.0.0] should throw
 FAIL Location's href: https://[0:1.00.0.0.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.00.0.0.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.00.0.0.0] should throw
+PASS URL's constructor's base argument: https://[0:1.290.0.0.0] should throw
 FAIL URL's href: https://[0:1.290.0.0.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.290.0.0.0] should throw
 PASS sendBeacon(): https://[0:1.290.0.0.0] should throw
 FAIL Location's href: https://[0:1.290.0.0.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.290.0.0.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.290.0.0.0] should throw
+PASS URL's constructor's base argument: https://[0:1.23.23] should throw
 FAIL URL's href: https://[0:1.23.23] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.23.23] should throw
 PASS sendBeacon(): https://[0:1.23.23] should throw
 FAIL Location's href: https://[0:1.23.23] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.23.23]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.23.23] should throw
+PASS URL's constructor's base argument: http://? should throw
 FAIL URL's href: http://? should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://? should throw
 PASS sendBeacon(): http://? should throw
 FAIL Location's href: http://? should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://?' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://? should throw
+PASS URL's constructor's base argument: http://# should throw
 FAIL URL's href: http://# should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://# should throw
 PASS sendBeacon(): http://# should throw
 FAIL Location's href: http://# should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://#' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://# should throw
+FAIL URL's constructor's base argument: non-special://[:80/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: non-special://[:80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: non-special://[:80/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): non-special://[:80/ should throw
 FAIL Location's href: non-special://[:80/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): non-special://[:80/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://[::127.0.0.0.1] should throw
 FAIL URL's href: http://[::127.0.0.0.1] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://[::127.0.0.0.1] should throw
 PASS sendBeacon(): http://[::127.0.0.0.1] should throw
 FAIL Location's href: http://[::127.0.0.0.1] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://[::127.0.0.0.1]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://[::127.0.0.0.1] should throw
+PASS URL's constructor's base argument: a should throw
+FAIL URL's href: a should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: a/ should throw
+FAIL URL's href: a/ should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a/ should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: a// should throw
+FAIL URL's href: a// should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a// should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a// should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a// should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a// should throw assert_throws: function "() => self.open(test.input).close()" did not throw
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt
index 201e4a9..7e91ddd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/url/url-constructor-expected.txt
@@ -559,13 +559,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-PASS Parsing: <test-a.html> against <a>
-PASS Parsing: <test-a-slash.html> against <a/>
-PASS Parsing: <test-a-slash-slash.html> against <a//>
+PASS Parsing: <a> against <about:blank>
+PASS Parsing: <a/> against <about:blank>
+PASS Parsing: <a//> against <about:blank>
 PASS Parsing: <test-a-colon.html> against <a:>
+PASS Parsing: <test-a-colon-b.html> against <a:b>
 PASS Parsing: <test-a-colon-slash.html> against <a:/>
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> Failed to construct 'URL': Invalid URL
-PASS Parsing: <test-a-colon-b.html> against <a:b>
 PASS Parsing: <test-a-colon-slash-b.html> against <a:/b>
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> Failed to construct 'URL': Invalid URL
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt
index 49952f9..006c103 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-expected.txt
@@ -513,13 +513,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-FAIL Parsing: <test-a.html> against <a> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash.html> against <a/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash-slash.html> against <a//> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got ""
+FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got ""
+FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got ""
 FAIL Parsing: <test-a-colon.html> against <a:> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <test-a-colon-slash.html> against <a:/> assert_equals: href expected "a:/test-a-colon-slash.html" but got "file:///A:/test-a-colon-slash.html"
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got "file:///A://test-a-colon-slash-slash.html"
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <test-a-colon-slash-b.html> against <a:/b> assert_equals: href expected "a:/test-a-colon-slash-b.html" but got "file:///A:/test-a-colon-slash-b.html"
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "file:///A://test-a-colon-slash-slash-b.html"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
index 49952f9..006c103 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/a-element-xhtml-expected.txt
@@ -513,13 +513,13 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-FAIL Parsing: <test-a.html> against <a> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash.html> against <a/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <test-a-slash-slash.html> against <a//> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <a> against <about:blank> assert_equals: failure should set href to input expected "a" but got ""
+FAIL Parsing: <a/> against <about:blank> assert_equals: failure should set href to input expected "a/" but got ""
+FAIL Parsing: <a//> against <about:blank> assert_equals: failure should set href to input expected "a//" but got ""
 FAIL Parsing: <test-a-colon.html> against <a:> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <test-a-colon-slash.html> against <a:/> assert_equals: href expected "a:/test-a-colon-slash.html" but got "file:///A:/test-a-colon-slash.html"
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got "file:///A://test-a-colon-slash-slash.html"
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <test-a-colon-slash-b.html> against <a:/b> assert_equals: href expected "a:/test-a-colon-slash-b.html" but got "file:///A:/test-a-colon-slash-b.html"
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "file:///A://test-a-colon-slash-slash-b.html"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/failure-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/failure-expected.txt
index 4a0ed3e..ce03431 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/failure-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/failure-expected.txt
@@ -1,250 +1,317 @@
 This is a testharness.js-based test.
-Found 246 tests; 102 PASS, 144 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 313 tests; 143 PASS, 170 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
+PASS URL's constructor's base argument: file://example:1/ should throw
 FAIL URL's href: file://example:1/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example:1/ should throw
 PASS sendBeacon(): file://example:1/ should throw
 FAIL Location's href: file://example:1/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example:1/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example:1/ should throw
+PASS URL's constructor's base argument: file://example:test/ should throw
 FAIL URL's href: file://example:test/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example:test/ should throw
 PASS sendBeacon(): file://example:test/ should throw
 FAIL Location's href: file://example:test/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example:test/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example:test/ should throw
+PASS URL's constructor's base argument: file://example%/ should throw
 FAIL URL's href: file://example%/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://example%/ should throw
 PASS sendBeacon(): file://example%/ should throw
 FAIL Location's href: file://example%/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://example%/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://example%/ should throw
+PASS URL's constructor's base argument: file://[example]/ should throw
 FAIL URL's href: file://[example]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: file://[example]/ should throw
 PASS sendBeacon(): file://[example]/ should throw
 FAIL Location's href: file://[example]/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'file://[example]/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): file://[example]/ should throw
+PASS URL's constructor's base argument: http://user:pass@/ should throw
 FAIL URL's href: http://user:pass@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://user:pass@/ should throw
 PASS sendBeacon(): http://user:pass@/ should throw
 FAIL Location's href: http://user:pass@/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://user:pass@/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://user:pass@/ should throw
+PASS URL's constructor's base argument: http://foo:-80/ should throw
 FAIL URL's href: http://foo:-80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://foo:-80/ should throw
 PASS sendBeacon(): http://foo:-80/ should throw
 FAIL Location's href: http://foo:-80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://foo:-80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://foo:-80/ should throw
+PASS URL's constructor's base argument: http:/:@/www.example.com should throw
 FAIL URL's href: http:/:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/:@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/:@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/:@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://user@/www.example.com should throw
 FAIL URL's href: http://user@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://user@/www.example.com should throw
 PASS sendBeacon(): http://user@/www.example.com should throw
 FAIL Location's href: http://user@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://user@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://user@/www.example.com should throw
+PASS URL's constructor's base argument: http:@/www.example.com should throw
 FAIL URL's href: http:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/@/www.example.com should throw
 FAIL URL's href: http:/@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://@/www.example.com should throw
 FAIL URL's href: http://@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://@/www.example.com should throw
 PASS sendBeacon(): http://@/www.example.com should throw
 FAIL Location's href: http://@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://@/www.example.com should throw
+PASS URL's constructor's base argument: https:@/www.example.com should throw
 FAIL URL's href: https:@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https:@/www.example.com should throw
 PASS sendBeacon(): https:@/www.example.com should throw
 FAIL Location's href: https:@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https:@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https:@/www.example.com should throw
+PASS URL's constructor's base argument: http:a:b@/www.example.com should throw
 FAIL URL's href: http:a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:a:b@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): http:a:b@/www.example.com should throw
 FAIL Location's href: http:a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:a:b@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/a:b@/www.example.com should throw
 FAIL URL's href: http:/a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/a:b@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/a:b@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/a:b@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://a:b@/www.example.com should throw
 FAIL URL's href: http://a:b@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://a:b@/www.example.com should throw
 PASS sendBeacon(): http://a:b@/www.example.com should throw
 FAIL Location's href: http://a:b@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://a:b@/www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://a:b@/www.example.com should throw
+PASS URL's constructor's base argument: http::@/www.example.com should throw
 FAIL URL's href: http::@/www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http::@/www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http::@/www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http::@/www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http::@/www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:@:www.example.com should throw
 FAIL URL's href: http:@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:@:www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:@:www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:@:www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http:/@:www.example.com should throw
 FAIL URL's href: http:/@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: http:/@:www.example.com should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): http:/@:www.example.com should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: http:/@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): http:/@:www.example.com should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://@:www.example.com should throw
 FAIL URL's href: http://@:www.example.com should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://@:www.example.com should throw
 PASS sendBeacon(): http://@:www.example.com should throw
 FAIL Location's href: http://@:www.example.com should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://@:www.example.com' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://@:www.example.com should throw
+PASS URL's constructor's base argument: https://� should throw
 FAIL URL's href: https://� should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://� should throw
 PASS sendBeacon(): https://� should throw
 FAIL Location's href: https://� should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://�' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://� should throw
+PASS URL's constructor's base argument: https://%EF%BF%BD should throw
 FAIL URL's href: https://%EF%BF%BD should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://%EF%BF%BD should throw
 PASS sendBeacon(): https://%EF%BF%BD should throw
 FAIL Location's href: https://%EF%BF%BD should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://%EF%BF%BD' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://%EF%BF%BD should throw
+FAIL URL's constructor's base argument: https://x x:12 should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: https://x x:12 should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: https://x x:12 should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 FAIL sendBeacon(): https://x x:12 should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
 FAIL Location's href: https://x x:12 should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): https://x x:12 should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://[www.google.com]/ should throw
 FAIL URL's href: http://[www.google.com]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://[www.google.com]/ should throw
 PASS sendBeacon(): http://[www.google.com]/ should throw
 FAIL Location's href: http://[www.google.com]/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://[www.google.com]/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://[www.google.com]/ should throw
+FAIL URL's constructor's base argument: sc://\0/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://\0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://\0/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://\0/ should throw
 FAIL Location's href: sc://\0/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://\0/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc:// / should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc:// / should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc:// / should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc:// / should throw
 FAIL Location's href: sc:// / should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc:// / should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://@/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://@/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://@/ should throw
 FAIL Location's href: sc://@/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://@/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://te@s:t@/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://te@s:t@/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://te@s:t@/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://te@s:t@/ should throw
 FAIL Location's href: sc://te@s:t@/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://te@s:t@/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://:/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://:/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://:/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://:/ should throw
 FAIL Location's href: sc://:/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://:/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://:12/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://:12/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://:12/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://:12/ should throw
 FAIL Location's href: sc://:12/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://:12/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://[/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://[/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://[/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://[/ should throw
 FAIL Location's href: sc://[/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://[/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://\/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://\/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://\/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://\/ should throw
 FAIL Location's href: sc://\/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://\/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+FAIL URL's constructor's base argument: sc://]/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: sc://]/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: sc://]/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): sc://]/ should throw
 FAIL Location's href: sc://]/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): sc://]/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: ftp://example.com%80/ should throw
 FAIL URL's href: ftp://example.com%80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: ftp://example.com%80/ should throw
 PASS sendBeacon(): ftp://example.com%80/ should throw
 FAIL Location's href: ftp://example.com%80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'ftp://example.com%80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): ftp://example.com%80/ should throw
+PASS URL's constructor's base argument: ftp://example.com%A0/ should throw
 FAIL URL's href: ftp://example.com%A0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: ftp://example.com%A0/ should throw
 PASS sendBeacon(): ftp://example.com%A0/ should throw
 FAIL Location's href: ftp://example.com%A0/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'ftp://example.com%A0/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): ftp://example.com%A0/ should throw
+PASS URL's constructor's base argument: https://example.com%80/ should throw
 FAIL URL's href: https://example.com%80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://example.com%80/ should throw
 PASS sendBeacon(): https://example.com%80/ should throw
 FAIL Location's href: https://example.com%80/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://example.com%80/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://example.com%80/ should throw
+PASS URL's constructor's base argument: https://example.com%A0/ should throw
 FAIL URL's href: https://example.com%A0/ should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://example.com%A0/ should throw
 PASS sendBeacon(): https://example.com%A0/ should throw
 FAIL Location's href: https://example.com%A0/ should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://example.com%A0/' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://example.com%A0/ should throw
+PASS URL's constructor's base argument: https://0x100000000/test should throw
 FAIL URL's href: https://0x100000000/test should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://0x100000000/test should throw
 PASS sendBeacon(): https://0x100000000/test should throw
 FAIL Location's href: https://0x100000000/test should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://0x100000000/test' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://0x100000000/test should throw
+PASS URL's constructor's base argument: https://256.0.0.1/test should throw
 FAIL URL's href: https://256.0.0.1/test should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://256.0.0.1/test should throw
 PASS sendBeacon(): https://256.0.0.1/test should throw
 FAIL Location's href: https://256.0.0.1/test should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://256.0.0.1/test' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://256.0.0.1/test should throw
+PASS URL's constructor's base argument: https://[0::0::0] should throw
 FAIL URL's href: https://[0::0::0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0::0::0] should throw
 PASS sendBeacon(): https://[0::0::0] should throw
 FAIL Location's href: https://[0::0::0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0::0::0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0::0::0] should throw
+PASS URL's constructor's base argument: https://[0:.0] should throw
 FAIL URL's href: https://[0:.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:.0] should throw
 PASS sendBeacon(): https://[0:.0] should throw
 FAIL Location's href: https://[0:.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:.0] should throw
+PASS URL's constructor's base argument: https://[0:0:] should throw
 FAIL URL's href: https://[0:0:] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:0:] should throw
 PASS sendBeacon(): https://[0:0:] should throw
 FAIL Location's href: https://[0:0:] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:0:]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:0:] should throw
+PASS URL's constructor's base argument: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 FAIL URL's href: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 PASS sendBeacon(): https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
 FAIL Location's href: https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1:2:3:4:5:6:7.0.0.0.1]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1:2:3:4:5:6:7.0.0.0.1] should throw
+PASS URL's constructor's base argument: https://[0:1.00.0.0.0] should throw
 FAIL URL's href: https://[0:1.00.0.0.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.00.0.0.0] should throw
 PASS sendBeacon(): https://[0:1.00.0.0.0] should throw
 FAIL Location's href: https://[0:1.00.0.0.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.00.0.0.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.00.0.0.0] should throw
+PASS URL's constructor's base argument: https://[0:1.290.0.0.0] should throw
 FAIL URL's href: https://[0:1.290.0.0.0] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.290.0.0.0] should throw
 PASS sendBeacon(): https://[0:1.290.0.0.0] should throw
 FAIL Location's href: https://[0:1.290.0.0.0] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.290.0.0.0]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.290.0.0.0] should throw
+PASS URL's constructor's base argument: https://[0:1.23.23] should throw
 FAIL URL's href: https://[0:1.23.23] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: https://[0:1.23.23] should throw
 PASS sendBeacon(): https://[0:1.23.23] should throw
 FAIL Location's href: https://[0:1.23.23] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'https://[0:1.23.23]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): https://[0:1.23.23] should throw
+PASS URL's constructor's base argument: http://? should throw
 FAIL URL's href: http://? should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://? should throw
 PASS sendBeacon(): http://? should throw
 FAIL Location's href: http://? should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://?' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://? should throw
+PASS URL's constructor's base argument: http://# should throw
 FAIL URL's href: http://# should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://# should throw
 PASS sendBeacon(): http://# should throw
 FAIL Location's href: http://# should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://#' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://# should throw
+FAIL URL's constructor's base argument: non-special://[:80/ should throw assert_throws: function "() => new URL("about:blank", test.input)" did not throw
 FAIL URL's href: non-special://[:80/ should throw assert_throws: function "() => url.href = test.input" did not throw
 FAIL XHR: non-special://[:80/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
 PASS sendBeacon(): non-special://[:80/ should throw
 FAIL Location's href: non-special://[:80/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
 FAIL window.open(): non-special://[:80/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: http://[::127.0.0.0.1] should throw
 FAIL URL's href: http://[::127.0.0.0.1] should throw assert_throws: function "() => url.href = test.input" did not throw
 PASS XHR: http://[::127.0.0.0.1] should throw
 PASS sendBeacon(): http://[::127.0.0.0.1] should throw
 FAIL Location's href: http://[::127.0.0.0.1] should throw assert_throws: function "() => self[0].location = test.input" threw object "SyntaxError: Failed to set the 'href' property on 'Location': 'http://[::127.0.0.0.1]' is not a valid URL." ("SyntaxError") expected object "TypeError" ("TypeError")
 PASS window.open(): http://[::127.0.0.0.1] should throw
+PASS URL's constructor's base argument: a should throw
+FAIL URL's href: a should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: a/ should throw
+FAIL URL's href: a/ should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a/ should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a/ should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a/ should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a/ should throw assert_throws: function "() => self.open(test.input).close()" did not throw
+PASS URL's constructor's base argument: a// should throw
+FAIL URL's href: a// should throw assert_throws: function "() => url.href = test.input" did not throw
+FAIL XHR: a// should throw assert_throws: function "() => client.open("GET", test.input)" did not throw
+FAIL sendBeacon(): a// should throw assert_throws: function "() => self.navigator.sendBeacon(test.input)" did not throw
+FAIL Location's href: a// should throw assert_throws: function "() => self[0].location = test.input" did not throw
+FAIL window.open(): a// should throw assert_throws: function "() => self.open(test.input).close()" did not throw
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt
index fb3734e..889525ee 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/url/url-constructor-expected.txt
@@ -559,17 +559,17 @@
 PASS Parsing: <http://example.org/test?%GH> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%EF> against <about:blank>
 PASS Parsing: <http://example.org/test?a#%GH> against <about:blank>
-PASS Parsing: <test-a.html> against <a>
-PASS Parsing: <test-a-slash.html> against <a/>
-PASS Parsing: <test-a-slash-slash.html> against <a//>
+PASS Parsing: <a> against <about:blank>
+PASS Parsing: <a/> against <about:blank>
+PASS Parsing: <a//> against <about:blank>
 FAIL Parsing: <test-a-colon.html> against <a:> assert_throws: function "function() {
           bURL(expected.input, expected.base)
         }" did not throw
+FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_throws: function "function() {
+          bURL(expected.input, expected.base)
+        }" did not throw
 FAIL Parsing: <test-a-colon-slash.html> against <a:/> assert_equals: href expected "a:/test-a-colon-slash.html" but got "file:///A:/test-a-colon-slash.html"
 FAIL Parsing: <test-a-colon-slash-slash.html> against <a://> assert_equals: href expected "a:///test-a-colon-slash-slash.html" but got "file:///A://test-a-colon-slash-slash.html"
-FAIL Parsing: <test-a-colon-b.html> against <a:b> assert_throws: function "function() {
-          bURL(expected.input, expected.base)
-        }" did not throw
 FAIL Parsing: <test-a-colon-slash-b.html> against <a:/b> assert_equals: href expected "a:/test-a-colon-slash-b.html" but got "file:///A:/test-a-colon-slash-b.html"
 FAIL Parsing: <test-a-colon-slash-slash-b.html> against <a://b> assert_equals: href expected "a://b/test-a-colon-slash-slash-b.html" but got "file:///A://test-a-colon-slash-slash-b.html"
 PASS Parsing: <http://example.org/test?a#b\0c> against <about:blank>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 9e62dca..1aa0a33 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -821,6 +821,7 @@
     getter pushManager
     getter scope
     getter sync
+    getter updateViaCache
     getter waiting
     method constructor
     method getNotifications
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 787cdf3..c8aba4d 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -788,6 +788,7 @@
 [Worker]     getter pushManager
 [Worker]     getter scope
 [Worker]     getter sync
+[Worker]     getter updateViaCache
 [Worker]     getter waiting
 [Worker]     method constructor
 [Worker]     method getNotifications
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 23d052d..8c758ffd 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -6067,6 +6067,7 @@
     getter pushManager
     getter scope
     getter sync
+    getter updateViaCache
     getter waiting
     method constructor
     method getNotifications
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index 653b881..afc3a91 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -783,6 +783,7 @@
 [Worker]     getter pushManager
 [Worker]     getter scope
 [Worker]     getter sync
+[Worker]     getter updateViaCache
 [Worker]     getter waiting
 [Worker]     method constructor
 [Worker]     method getNotifications
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 48c0839..f2aacce 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -51,11 +51,6 @@
 }
 
 config("blink_headers_config") {
-  include_dirs = [
-    "..",
-    "$root_gen_dir/third_party/blink",
-  ]
-
   # Allow :blink_headers to include v8.h without linking to it.
   configs = [ "//v8:external_config" ]
 }
diff --git a/third_party/blink/renderer/BUILD.gn b/third_party/blink/renderer/BUILD.gn
index 4b32bb2..2b61563 100644
--- a/third_party/blink/renderer/BUILD.gn
+++ b/third_party/blink/renderer/BUILD.gn
@@ -77,13 +77,6 @@
 # config -----------------------------------------------------------------------
 
 config("config") {
-  include_dirs = [
-    ".",
-    "..",
-    "$root_gen_dir/third_party/blink/renderer",
-    "$root_gen_dir/third_party/blink",
-  ]
-
   cflags = []
   defines = []
 
diff --git a/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py b/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py
index 4065a30..c314fe6 100755
--- a/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py
+++ b/third_party/blink/renderer/bindings/scripts/aggregate_generated_bindings.py
@@ -103,8 +103,8 @@
               '#define NO_IMPLICIT_ATOMICSTRING\n\n']
 
     basenames.sort()
-    output.extend('#include "bindings/%s/v8/v8_%s.cc"\n' % (component, to_snake_case(basename))
-                  for basename in basenames)
+    output.extend('#include "third_party/blink/renderer/bindings/%s/v8/v8_%s.cc"\n' %
+                  (component, to_snake_case(basename)) for basename in basenames)
     return ''.join(output)
 
 
diff --git a/third_party/blink/renderer/bindings/scripts/code_generator.py b/third_party/blink/renderer/bindings/scripts/code_generator.py
index 99639dea..df063fa 100644
--- a/third_party/blink/renderer/bindings/scripts/code_generator.py
+++ b/third_party/blink/renderer/bindings/scripts/code_generator.py
@@ -108,14 +108,14 @@
 _BLINK_RELATIVE_PATH_PREFIXES = ('bindings/', 'core/', 'modules/', 'platform/')
 
 def normalize_and_sort_includes(include_paths):
-    normalized_include_paths = []
+    normalized_include_paths = set()
     for include_path in include_paths:
         match = re.search(r'/gen/(third_party/blink/.*)$', posixpath.abspath(include_path))
         if match:
             include_path = match.group(1)
         elif include_path.startswith(_BLINK_RELATIVE_PATH_PREFIXES):
             include_path = 'third_party/blink/renderer/' + include_path
-        normalized_include_paths.append(include_path)
+        normalized_include_paths.add(include_path)
     return sorted(normalized_include_paths)
 
 
@@ -150,24 +150,23 @@
         IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_interfaces'])
         set_component_dirs(interfaces_info['component_dirs'])
 
-    def render_template(self, include_paths, header_template, cpp_template,
-                        template_context, component=None):
-        template_context['code_generator'] = self.generator_name
+    def render_templates(self, include_paths, header_template, cpp_template,
+                         context, component=None):
+        context['code_generator'] = self.generator_name
 
         # Add includes for any dependencies
-        template_context['header_includes'] = normalize_and_sort_includes(
-            template_context['header_includes'])
-
         for include_path in include_paths:
             if component:
                 dependency = idl_filename_to_component(include_path)
                 assert is_valid_component_dependency(component, dependency)
             includes.add(include_path)
 
-        template_context['cpp_includes'] = normalize_and_sort_includes(includes)
+        cpp_includes = set(context.get('cpp_includes', []))
+        context['cpp_includes'] = normalize_and_sort_includes(cpp_includes | includes)
+        context['header_includes'] = normalize_and_sort_includes(context['header_includes'])
 
-        header_text = render_template(header_template, template_context)
-        cpp_text = render_template(cpp_template, template_context)
+        header_text = render_template(header_template, context)
+        cpp_text = render_template(cpp_template, context)
         return header_text, cpp_text
 
     def generate_code(self, definitions, definition_name):
diff --git a/third_party/blink/renderer/bindings/scripts/code_generator_v8.py b/third_party/blink/renderer/bindings/scripts/code_generator_v8.py
index 434389d..5b343669 100644
--- a/third_party/blink/renderer/bindings/scripts/code_generator_v8.py
+++ b/third_party/blink/renderer/bindings/scripts/code_generator_v8.py
@@ -48,7 +48,7 @@
 import os
 import posixpath
 
-from code_generator import CodeGeneratorBase, render_template, normalize_and_sort_includes
+from code_generator import CodeGeneratorBase
 from idl_definitions import Visitor
 from idl_types import IdlType
 import v8_callback_function
@@ -220,7 +220,7 @@
         template_context['this_include_header_path'] = posixpath.basename(header_path)
         header_template = self.jinja_env.get_template(header_template_filename)
         cpp_template = self.jinja_env.get_template(cpp_template_filename)
-        header_text, cpp_text = self.render_template(
+        header_text, cpp_text = self.render_templates(
             include_paths, header_template, cpp_template, template_context,
             component)
         return (
@@ -245,7 +245,7 @@
             template_context['exported'] = self.info_provider.specifier_for_export
         header_path, cpp_path = self.output_paths(dictionary_name)
         template_context['this_include_header_path'] = posixpath.basename(header_path)
-        header_text, cpp_text = self.render_template(
+        header_text, cpp_text = self.render_templates(
             include_paths, header_template, cpp_template, template_context)
         return (
             (header_path, header_text),
@@ -284,7 +284,7 @@
             interface_info.get('additional_header_includes', []))
         header_path, cpp_path = self.output_paths(definition_name, interface_info)
         template_context['this_include_header_path'] = posixpath.basename(header_path)
-        header_text, cpp_text = self.render_template(
+        header_text, cpp_text = self.render_templates(
             include_paths, header_template, cpp_template, template_context)
         return (
             (header_path, header_text),
@@ -310,6 +310,7 @@
             self.typedefs[name] = typedef.idl_type
 
     def _generate_container_code(self, union_type):
+        includes.clear()
         union_type = union_type.resolve_typedefs(self.typedefs)
         header_template = self.jinja_env.get_template('union_container.h.tmpl')
         cpp_template = self.jinja_env.get_template('union_container.cpp.tmpl')
@@ -317,18 +318,13 @@
             union_type, self.info_provider)
         template_context['header_includes'].append(
             self.info_provider.include_path_for_export)
-        template_context['header_includes'] = normalize_and_sort_includes(
-            template_context['header_includes'])
-        template_context['cpp_includes'] = normalize_and_sort_includes(
-            template_context['cpp_includes'])
-        template_context['code_generator'] = self.generator_name
         template_context['exported'] = self.info_provider.specifier_for_export
         snake_base_name = to_snake_case(shorten_union_name(union_type))
         template_context['this_include_header_path'] = snake_base_name + '.h'
-        header_text = render_template(header_template, template_context)
-        cpp_text = render_template(cpp_template, template_context)
         header_path = posixpath.join(self.output_dir, '%s.h' % snake_base_name)
         cpp_path = posixpath.join(self.output_dir, '%s.cc' % snake_base_name)
+        header_text, cpp_text = self.render_templates(
+            [], header_template, cpp_template, template_context)
         return (
             (header_path, header_text),
             (cpp_path, cpp_text),
@@ -385,13 +381,9 @@
                 template_context['header_includes'].append(
                     self.info_provider.include_path_for_union_types(argument.idl_type))
 
-        template_context['header_includes'] = normalize_and_sort_includes(
-            template_context['header_includes'])
-        template_context['cpp_includes'] = normalize_and_sort_includes(
-            template_context['cpp_includes'])
         template_context['code_generator'] = MODULE_PYNAME
-        header_text = render_template(header_template, template_context)
-        cpp_text = render_template(cpp_template, template_context)
+        header_text, cpp_text = self.render_templates(
+            [], header_template, cpp_template, template_context)
         snake_base_name = to_snake_case('V8%s' % callback_function.name)
         header_path = posixpath.join(self.output_dir, '%s.h' % snake_base_name)
         cpp_path = posixpath.join(self.output_dir, '%s.cc' % snake_base_name)
diff --git a/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py b/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py
index d3f9f4a..dd1b8541 100755
--- a/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py
+++ b/third_party/blink/renderer/bindings/scripts/generate_init_partial_interfaces.py
@@ -93,7 +93,7 @@
                        for meta_data in meta_data_list]
     interface_names.sort()
 
-    includes = ['#include "bindings/modules/v8/%s.h"' %
+    includes = ['#include "third_party/blink/renderer/bindings/modules/v8/%s.h"' %
                 build_basename(interface_name)
                 for interface_name in interface_names]
     initialize_calls = ['  %s::initialize();' % interface_name
diff --git a/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py b/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py
index f2bbdf6..5eaa524 100644
--- a/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py
+++ b/third_party/blink/renderer/bindings/scripts/generate_v8_context_snapshot_external_references.py
@@ -19,14 +19,14 @@
 
 
 INCLUDES = frozenset([
-    'bindings/core/v8/generated_code_helper.h',
-    'bindings/core/v8/v8_html_document.h',
-    'bindings/core/v8/v8_initializer.h',
-    'bindings/core/v8/v8_window.h',
-    'platform/bindings/dom_wrapper_world.h',
-    'platform/bindings/v8_object_constructor.h',
-    'platform/bindings/v8_per_isolate_data.h',
-    'platform/bindings/v8_private_property.h',
+    'third_party/blink/renderer/bindings/core/v8/generated_code_helper.h',
+    'third_party/blink/renderer/bindings/core/v8/v8_html_document.h',
+    'third_party/blink/renderer/bindings/core/v8/v8_initializer.h',
+    'third_party/blink/renderer/bindings/core/v8/v8_window.h',
+    'third_party/blink/renderer/platform/bindings/dom_wrapper_world.h',
+    'third_party/blink/renderer/platform/bindings/v8_object_constructor.h',
+    'third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h',
+    'third_party/blink/renderer/platform/bindings/v8_private_property.h',
     'v8/include/v8.h'])
 
 TEMPLATE_FILE = 'external_reference_table.cpp.tmpl'
@@ -184,7 +184,8 @@
         context = context_builder.create_interface_context(interface, interfaces)
         name = '%s%s' % (interface.name, 'Partial' if interface.is_partial else '')
         self._interface_contexts[name] = context
-        include_file = 'bindings/%s/v8/%s.h' % (component, utilities.to_snake_case(context['v8_name']))
+        include_file = 'third_party/blink/renderer/bindings/%s/v8/%s.h' % (
+            component, utilities.to_snake_case(context['v8_name']))
         self._include_files.add(include_file)
 
     # Gathers all interface-dependent information and returns as a Jinja template context.
@@ -192,7 +193,7 @@
         interfaces = []
         for name in sorted(self._interface_contexts):
             interfaces.append(self._interface_contexts[name])
-        header_path = 'bindings/modules/v8/v8_context_snapshot_external_references.h'
+        header_path = 'third_party/blink/renderer/bindings/modules/v8/v8_context_snapshot_external_references.h'
         include_files = list(self._include_files)
         return {
             'class': 'V8ContextSnapshotExternalReferences',
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 13eb3dc6..ae1b1fa 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -41,10 +41,7 @@
 }
 
 config("core_include_dirs") {
-  include_dirs = [
-    "..",
-    "$root_gen_dir/third_party/blink/renderer",
-  ]
+  include_dirs = []
   if (is_android && use_openmax_dl_fft) {
     include_dirs += [ "//third_party/openmax_dl" ]
   }
@@ -1580,7 +1577,6 @@
     ":core_include_dirs",
     "//tools/v8_context_snapshot:use_v8_context_snapshot",
   ]
-  include_dirs = [ "$root_gen_dir/third_party/blink/renderer" ]
 
   cflags = []
   defines = []
diff --git a/third_party/blink/renderer/core/editing/frame_selection.h b/third_party/blink/renderer/core/editing/frame_selection.h
index fd951d2..301e07e 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.h
+++ b/third_party/blink/renderer/core/editing/frame_selection.h
@@ -65,25 +65,33 @@
 
 enum class HandleVisibility { kNotVisible, kVisible };
 
+enum class SelectLineBreak { kNotSelected, kSelected };
+
 // This is return type of ComputeLayoutSelectionStatus(paintfragment).
 // This structure represents how the fragment is selected.
 // |start|, |end| : Selection start/end offset. This offset is based on
 //   the text of NGInlineNode of a parent block thus
 //   |fragemnt.StartOffset <= start <= end <= fragment.EndOffset|.
 // |start| == |end| means this fragment is not selected.
+// |line_break| : This value represents If this fragment is selected and
+// selection wraps line break.
 struct LayoutSelectionStatus {
   STACK_ALLOCATED();
 
-  LayoutSelectionStatus(unsigned passed_start, unsigned passed_end)
-      : start(passed_start), end(passed_end) {
+  LayoutSelectionStatus(unsigned passed_start,
+                        unsigned passed_end,
+                        SelectLineBreak passed_line_break)
+      : start(passed_start), end(passed_end), line_break(passed_line_break) {
     DCHECK_LE(start, end);
   }
   bool operator==(const LayoutSelectionStatus& other) const {
-    return start == other.start && end == other.end;
+    return start == other.start && end == other.end &&
+           line_break == other.line_break;
   }
 
   unsigned start;
   unsigned end;
+  SelectLineBreak line_break;
 };
 
 class CORE_EXPORT FrameSelection final
diff --git a/third_party/blink/renderer/core/editing/layout_selection.cc b/third_party/blink/renderer/core/editing/layout_selection.cc
index e4a12e5..84892c4 100644
--- a/third_party/blink/renderer/core/editing/layout_selection.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
@@ -658,6 +659,26 @@
                   text_fragment.EndOffset());
 }
 
+static bool IsBeforeLineBreak(const NGPaintFragment& fragment) {
+  // TODO(yoichio): InlineBlock should not be container line box.
+  // See paint/selection/text-selection-inline-block.html.
+  const NGPaintFragment* container_line_box = fragment.ContainerLineBox();
+  DCHECK(container_line_box);
+  const NGPhysicalLineBoxFragment& physical_line_box =
+      ToNGPhysicalLineBoxFragment(container_line_box->PhysicalFragment());
+  const NGPhysicalFragment* last_leaf_not_linebreak =
+      physical_line_box.LastLogicalLeafIgnoringLineBreak();
+  DCHECK(last_leaf_not_linebreak);
+  if (&fragment.PhysicalFragment() != last_leaf_not_linebreak)
+    return false;
+  // Even If |fragment| is before linebreak, if its direction differs to line
+  // direction, we don't paint line break. See
+  // paint/selection/text-selection-newline-mixed-ltr-rtl.html.
+  const ShapeResult* shape_result =
+      ToNGPhysicalTextFragment(fragment.PhysicalFragment()).TextShapeResult();
+  return physical_line_box.BaseDirection() == shape_result->Direction();
+}
+
 LayoutSelectionStatus LayoutSelection::ComputeSelectionStatus(
     const NGPaintFragment& fragment) const {
   const NGPhysicalTextFragment& text_fragment =
@@ -670,31 +691,47 @@
   switch (text_fragment.GetLayoutObject()->GetSelectionState()) {
     case SelectionState::kStart: {
       DCHECK(SelectionStart().has_value());
-      unsigned start_in_block = SelectionStart().value_or(0);
+      const unsigned start_in_block = SelectionStart().value_or(0);
+      const bool is_continuous = start_in_block <= text_fragment.EndOffset();
       return {ClampOffset(start_in_block, text_fragment),
-              text_fragment.EndOffset()};
+              text_fragment.EndOffset(),
+              (is_continuous && IsBeforeLineBreak(fragment))
+                  ? SelectLineBreak::kSelected
+                  : SelectLineBreak::kNotSelected};
     }
     case SelectionState::kEnd: {
       DCHECK(SelectionEnd().has_value());
-      unsigned end_in_block =
+      const unsigned end_in_block =
           SelectionEnd().value_or(text_fragment.EndOffset());
-      return {text_fragment.StartOffset(),
-              ClampOffset(end_in_block, text_fragment)};
+      const unsigned end_in_fragment = ClampOffset(end_in_block, text_fragment);
+      const bool is_continuous = text_fragment.EndOffset() < end_in_block;
+      return {text_fragment.StartOffset(), end_in_fragment,
+              (is_continuous && IsBeforeLineBreak(fragment))
+                  ? SelectLineBreak::kSelected
+                  : SelectLineBreak::kNotSelected};
     }
     case SelectionState::kStartAndEnd: {
       DCHECK(SelectionStart().has_value());
       DCHECK(SelectionEnd().has_value());
-      unsigned start_in_block = SelectionStart().value_or(0);
-      unsigned end_in_block =
+      const unsigned start_in_block = SelectionStart().value_or(0);
+      const unsigned end_in_block =
           SelectionEnd().value_or(text_fragment.EndOffset());
-      return {ClampOffset(start_in_block, text_fragment),
-              ClampOffset(end_in_block, text_fragment)};
+      const unsigned end_in_fragment = ClampOffset(end_in_block, text_fragment);
+      const bool is_continuous = start_in_block <= text_fragment.EndOffset() &&
+                                 text_fragment.EndOffset() < end_in_block;
+      return {ClampOffset(start_in_block, text_fragment), end_in_fragment,
+              (is_continuous && IsBeforeLineBreak(fragment))
+                  ? SelectLineBreak::kSelected
+                  : SelectLineBreak::kNotSelected};
     }
-    case SelectionState::kInside:
-      return {text_fragment.StartOffset(), text_fragment.EndOffset()};
+    case SelectionState::kInside: {
+      return {text_fragment.StartOffset(), text_fragment.EndOffset(),
+              IsBeforeLineBreak(fragment) ? SelectLineBreak::kSelected
+                                          : SelectLineBreak::kNotSelected};
+    }
     default:
       // This block is not included in selection.
-      return {0, 0};
+      return {0, 0, SelectLineBreak::kNotSelected};
   }
 }
 
diff --git a/third_party/blink/renderer/core/editing/layout_selection_test.cc b/third_party/blink/renderer/core/editing/layout_selection_test.cc
index 70e33530..b11f28d9 100644
--- a/third_party/blink/renderer/core/editing/layout_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection_test.cc
@@ -686,21 +686,6 @@
   TEST_NO_NEXT_LAYOUT_OBJECT();
 }
 
-class NGLayoutSelectionTest
-    : public LayoutSelectionTest,
-      private ScopedLayoutNGForTest,
-      private ScopedPaintUnderInvalidationCheckingForTest {
- public:
-  NGLayoutSelectionTest()
-      : ScopedLayoutNGForTest(true),
-        ScopedPaintUnderInvalidationCheckingForTest(true) {}
-};
-
-std::ostream& operator<<(std::ostream& ostream,
-                         const LayoutSelectionStatus& status) {
-  return ostream << status.start << ", " << status.end;
-}
-
 static const NGPaintFragment* FindNGPaintFragmentInternal(
     const NGPaintFragment* paint,
     const LayoutObject* layout_object) {
@@ -727,15 +712,62 @@
   return *paint_fragment;
 }
 
+class NGLayoutSelectionTest
+    : public LayoutSelectionTest,
+      private ScopedLayoutNGForTest,
+      private ScopedPaintUnderInvalidationCheckingForTest {
+ public:
+  NGLayoutSelectionTest()
+      : ScopedLayoutNGForTest(true),
+        ScopedPaintUnderInvalidationCheckingForTest(true) {}
+
+  const Text* GetFirstTextNode() {
+    for (const Node& runner : NodeTraversal::StartsAt(*GetDocument().body())) {
+      if (runner.IsTextNode())
+        return &ToText(runner);
+    }
+    NOTREACHED();
+    return nullptr;
+  }
+
+  bool IsFirstTextLineBreak(const std::string& selection_text) {
+    SetSelectionAndUpdateLayoutSelection(selection_text);
+    const Text* const first_text = GetFirstTextNode();
+    const NGPaintFragment& fragment =
+        GetNGPaintFragment(first_text->GetLayoutObject());
+    const LayoutSelectionStatus& status =
+        Selection().ComputeLayoutSelectionStatus(fragment);
+    return status.line_break == SelectLineBreak::kSelected;
+  }
+
+  LayoutSelectionStatus ComputeLayoutSelectionStatus(const Node& node) {
+    return Selection().ComputeLayoutSelectionStatus(
+        GetNGPaintFragment(node.GetLayoutObject()));
+  }
+
+  void SetSelectionAndUpdateLayoutSelection(const std::string& selection_text) {
+    const SelectionInDOMTree& selection =
+        SetSelectionTextToBody(selection_text);
+    Selection().SetSelectionAndEndTyping(selection);
+    Selection().CommitAppearanceIfNeeded();
+  }
+};
+
+std::ostream& operator<<(std::ostream& ostream,
+                         const LayoutSelectionStatus& status) {
+  const String line_break = (status.line_break == SelectLineBreak::kSelected)
+                                ? "kSelected"
+                                : "kNotSelected";
+  return ostream << status.start << ", " << status.end << ", " << std::boolalpha
+                 << line_break;
+}
+
 TEST_F(NGLayoutSelectionTest, SelectOnOneText) {
 #ifndef NDEBUG
   // This line prohibits compiler optimization removing the debug function.
   PrintLayoutTreeForDebug();
 #endif
-  const SelectionInDOMTree& selection =
-      SetSelectionTextToBody("foo<span>b^a|r</span>");
-  Selection().SetSelectionAndEndTyping(selection);
-  Selection().CommitAppearanceIfNeeded();
+  SetSelectionAndUpdateLayoutSelection("foo<span>b^a|r</span>");
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT("foo", kNone, NotInvalidate);
   TEST_NEXT(IsLayoutInline, kNone, NotInvalidate);
@@ -744,7 +776,7 @@
 
   LayoutObject* const foo =
       GetDocument().body()->firstChild()->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(0u, 0u),
+  EXPECT_EQ(LayoutSelectionStatus(0u, 0u, SelectLineBreak::kNotSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
   LayoutObject* const bar = GetDocument()
                                 .body()
@@ -752,15 +784,13 @@
                                 ->nextSibling()
                                 ->firstChild()
                                 ->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(4u, 5u),
+  EXPECT_EQ(LayoutSelectionStatus(4u, 5u, SelectLineBreak::kNotSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(bar)));
 }
 
 TEST_F(NGLayoutSelectionTest, FirstLetterInAnotherBlockFlow) {
-  const SelectionInDOMTree& selection = SetSelectionTextToBody(
+  SetSelectionAndUpdateLayoutSelection(
       "<style>:first-letter { float: right}</style>^fo|o");
-  Selection().SetSelectionAndEndTyping(selection);
-  Selection().CommitAppearanceIfNeeded();
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutTextFragmentOf("f"), kStart, ShouldInvalidate);
@@ -770,20 +800,17 @@
   const LayoutTextFragment* const foo_f =
       ToLayoutTextFragment(AssociatedLayoutObjectOf(*foo, 0));
   EXPECT_EQ(
-      LayoutSelectionStatus(0u, 1u),
+      LayoutSelectionStatus(0u, 1u, SelectLineBreak::kSelected),
       Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo_f)));
   const LayoutTextFragment* const foo_oo =
       ToLayoutTextFragment(AssociatedLayoutObjectOf(*foo, 1));
   EXPECT_EQ(
-      LayoutSelectionStatus(1u, 2u),
+      LayoutSelectionStatus(1u, 2u, SelectLineBreak::kNotSelected),
       Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo_oo)));
 }
 
 TEST_F(NGLayoutSelectionTest, TwoNGBlockFlows) {
-  const SelectionInDOMTree& selection =
-      SetSelectionTextToBody("<div>f^oo</div><div>ba|r</div>");
-  Selection().SetSelectionAndEndTyping(selection);
-  Selection().CommitAppearanceIfNeeded();
+  SetSelectionAndUpdateLayoutSelection("<div>f^oo</div><div>ba|r</div>");
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT("foo", kStart, ShouldInvalidate);
@@ -792,7 +819,7 @@
   TEST_NO_NEXT_LAYOUT_OBJECT();
   LayoutObject* const foo =
       GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(1u, 3u),
+  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectLineBreak::kSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
   LayoutObject* const bar = GetDocument()
                                 .body()
@@ -800,16 +827,14 @@
                                 ->nextSibling()
                                 ->firstChild()
                                 ->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(0u, 2u),
+  EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectLineBreak::kNotSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(bar)));
 }
 
 TEST_F(NGLayoutSelectionTest, MixedBlockFlowsAsSibling) {
-  const SelectionInDOMTree& selection = SetSelectionTextToBody(
+  SetSelectionAndUpdateLayoutSelection(
       "<div>f^oo</div>"
       "<div contenteditable>ba|r</div>");
-  Selection().SetSelectionAndEndTyping(selection);
-  Selection().CommitAppearanceIfNeeded();
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT("foo", kStart, ShouldInvalidate);
@@ -818,18 +843,16 @@
   TEST_NO_NEXT_LAYOUT_OBJECT();
   LayoutObject* const foo =
       GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(1u, 3u),
+  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectLineBreak::kSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
   EXPECT_EQ(2u, Selection().LayoutSelectionEnd().value());
 }
 
 TEST_F(NGLayoutSelectionTest, MixedBlockFlowsAnscestor) {
   // Both "foo" and "bar" for DIV elements should be legacy LayoutBlock.
-  const SelectionInDOMTree& selection = SetSelectionTextToBody(
+  SetSelectionAndUpdateLayoutSelection(
       "<div contenteditable>f^oo"
       "<div contenteditable=false>ba|r</div></div>");
-  Selection().SetSelectionAndEndTyping(selection);
-  Selection().CommitAppearanceIfNeeded();
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLegacyBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
@@ -841,11 +864,9 @@
 }
 
 TEST_F(NGLayoutSelectionTest, MixedBlockFlowsDecendant) {
-  const SelectionInDOMTree& selection = SetSelectionTextToBody(
+  SetSelectionAndUpdateLayoutSelection(
       "<div contenteditable=false>f^oo"
       "<div contenteditable>ba|r</div></div>");
-  Selection().SetSelectionAndEndTyping(selection);
-  Selection().CommitAppearanceIfNeeded();
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
   TEST_NEXT(IsLayoutNGBlockFlow, kContain, NotInvalidate);
@@ -855,9 +876,39 @@
   TEST_NO_NEXT_LAYOUT_OBJECT();
   LayoutObject* const foo =
       GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(1u, 3u),
+  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectLineBreak::kSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
   EXPECT_EQ(2u, Selection().LayoutSelectionEnd().value());
 }
 
+TEST_F(NGLayoutSelectionTest, LineBreakBasic) {
+  LoadAhem();
+  EXPECT_TRUE(IsFirstTextLineBreak("<div>f^oo<br>ba|r</div>"));
+  EXPECT_TRUE(IsFirstTextLineBreak("<div>^foo<br><br>|</div>"));
+  EXPECT_TRUE(IsFirstTextLineBreak(
+      "<div style='font: Ahem; width: 2em'>f^oo ba|r</div>"));
+  EXPECT_TRUE(IsFirstTextLineBreak("<div>f^oo</div><div>b|ar</div>"));
+  EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo |</div>"));
+  EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo <!--|--></div>"));
+  EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo </div>|"));
+  EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo|</div>"));
+  EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo<!--|--></div>"));
+  EXPECT_FALSE(IsFirstTextLineBreak("<div>f^oo</div>|"));
+  // TODO(yoichio): Fix the test. See LayoutSelection::IsLineBreak.
+  // EXPECT_FALSE(IsFirstTextLineBreak(
+  //    "<div style='display:inline-block'>f^oo</div>bar|"));
+}
+
+TEST_F(NGLayoutSelectionTest, LineBreakImage) {
+  SetSelectionAndUpdateLayoutSelection(
+      "<div>^<img id=img1 width=10px height=10px>foo<br>"
+      "bar<img id=img2 width=10px height=10px>|</div>");
+  Node* const foo =
+      GetDocument().body()->firstChild()->firstChild()->nextSibling();
+  EXPECT_EQ(SelectLineBreak::kSelected,
+            ComputeLayoutSelectionStatus(*foo).line_break);
+  Node* const bar = foo->nextSibling()->nextSibling();
+  EXPECT_EQ(SelectLineBreak::kNotSelected,
+            ComputeLayoutSelectionStatus(*bar).line_break);
+}
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
index 73bd600..afaf615 100644
--- a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
+++ b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
@@ -934,4 +934,24 @@
           .rect);
 }
 
+TEST_P(ParameterizedLocalCaretRectTest, BidiTextWithImage) {
+  LoadAhem();
+  InsertStyleElement(
+      "div { font: 10px/10px Ahem; width: 30px }"
+      "img { width: 10px; height: 10px; vertical-align: bottom }");
+  SetBodyContent("<div dir=rtl>X<img id=image>Y</div>");
+  const Element& image = *GetElementById("image");
+  const LayoutObject* image_layout = image.GetLayoutObject();
+  const LayoutObject* text_before = image.previousSibling()->GetLayoutObject();
+  // TODO(xiaochengh): Should return the same result for legacy and NG
+  EXPECT_EQ(LayoutNGEnabled()
+                ? LocalCaretRect(text_before, LayoutRect(10, 0, 1, 10))
+                : LocalCaretRect(image_layout, LayoutRect(0, 0, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position::BeforeNode(image))));
+  EXPECT_EQ(LocalCaretRect(image_layout, LayoutRect(9, 0, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position::AfterNode(image))));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
index df450b93..11089b4 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
@@ -35,7 +35,7 @@
       fragment.GetLayoutObject()->GetDocument().View();
   LayoutUnit caret_width = frame_view->CaretWidth();
 
-  const bool is_ltr = fragment.Style().Direction() == TextDirection::kLtr;
+  const bool is_ltr = IsLtr(fragment.PhysicalFragment().ResolvedDirection());
   LayoutUnit caret_left;
   if (is_ltr != (position_type == NGCaretPositionType::kBeforeBox)) {
     if (is_horizontal)
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index 10d79eb..9e173ca 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -5,10 +5,42 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
 
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 
 namespace blink {
 
+namespace {
+
+static const NGPhysicalFragment* LastLogicalLeafExceptLinebreakInternal(
+    const NGPhysicalFragment& runner,
+    TextDirection direction) {
+  if (runner.IsText()) {
+    if (ToNGPhysicalTextFragment(runner).IsLineBreak())
+      return nullptr;
+    return &runner;
+  }
+  if (!runner.IsContainer() || runner.IsBlockLayoutRoot())
+    return &runner;
+  const auto& children = ToNGPhysicalContainerFragment(runner).Children();
+  for (size_t i = 0; i < children.size(); i++) {
+    // TODO(xiaochengh): This isn't correct for mixed Bidi. Fix it. Besides, we
+    // should compute and store it during layout.
+    // We want a logical last child in a line.
+    const size_t index =
+        direction == TextDirection::kLtr ? (children.size() - 1 - i) : i;
+    const NGPhysicalFragment* child = children[index].get();
+    DCHECK(child);
+    if (const NGPhysicalFragment* candidate =
+            LastLogicalLeafExceptLinebreakInternal(*child, direction))
+      return candidate;
+  }
+  return nullptr;
+}
+
+}  // namespace
+
 NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment(
     const ComputedStyle& style,
     NGPhysicalSize size,
@@ -80,6 +112,13 @@
   return runner;
 }
 
+const NGPhysicalFragment*
+NGPhysicalLineBoxFragment::LastLogicalLeafIgnoringLineBreak() const {
+  if (Children().IsEmpty())
+    return nullptr;
+  return LastLogicalLeafExceptLinebreakInternal(*this, this->BaseDirection());
+}
+
 bool NGPhysicalLineBoxFragment::HasSoftWrapToNextLine() const {
   DCHECK(BreakToken());
   DCHECK(BreakToken()->IsInlineType());
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
index 02989a09..67f8724d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
@@ -43,6 +43,9 @@
   // nullptr if the line box is empty.
   const NGPhysicalFragment* FirstLogicalLeaf() const;
   const NGPhysicalFragment* LastLogicalLeaf() const;
+  // Returns the last leaf fragment in the line in logical order except line
+  // break. Returns nullptr if such fragment doesn't exist.
+  const NGPhysicalFragment* LastLogicalLeafIgnoringLineBreak() const;
 
   // Whether the content soft-wraps to the next line.
   bool HasSoftWrapToNextLine() const;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
index cd44fd8..331fb87d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
@@ -59,6 +59,7 @@
       "</div>");
   EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
   EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeaf());
+  EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
 }
 
 TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafInRtlText) {
@@ -69,6 +70,7 @@
       "</bdo>");
   EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
   EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeaf());
+  EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
 }
 
 TEST_F(NGPhysicalLineBoxFragmentTest,
@@ -81,6 +83,7 @@
       "</div>");
   EXPECT_TEXT_FRAGMENT("f", GetLineBox()->FirstLogicalLeaf());
   EXPECT_TEXT_FRAGMENT("r", GetLineBox()->LastLogicalLeaf());
+  EXPECT_TEXT_FRAGMENT("r", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
 }
 
 TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithInlineBlock) {
@@ -92,12 +95,26 @@
       "</div>");
   EXPECT_BOX_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
   EXPECT_BOX_FRAGMENT("baz", GetLineBox()->LastLogicalLeaf());
+  EXPECT_BOX_FRAGMENT("baz", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
 }
 
 TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithImages) {
   SetBodyInnerHTML("<div id=root><img id=img1>foo<img id=img2></div>");
   EXPECT_BOX_FRAGMENT("img1", GetLineBox()->FirstLogicalLeaf());
   EXPECT_BOX_FRAGMENT("img2", GetLineBox()->LastLogicalLeaf());
+  EXPECT_BOX_FRAGMENT("img2", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
+}
+
+TEST_F(NGPhysicalLineBoxFragmentTest, LastLogicalLeafSoftWrap) {
+  SetBodyInnerHTML("<div id=root style='width: 2em'>foo bar</div>");
+  EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->LastLogicalLeaf());
+  EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
+}
+
+TEST_F(NGPhysicalLineBoxFragmentTest, LastLogicalLeafHardWrap) {
+  SetBodyInnerHTML("<div id=root>foo<br>bar</div>");
+  EXPECT_TEXT_FRAGMENT("\n", GetLineBox()->LastLogicalLeaf());
+  EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
index 0ace6d2..a92b383 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_text_fragment_painter.cc
@@ -6,6 +6,8 @@
 
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h"
@@ -58,6 +60,35 @@
   return color;
 }
 
+NGPhysicalOffsetRect ExpandedSelectionRectForLineBreakIfNeeded(
+    const NGPhysicalOffsetRect& rect,
+    const NGPaintFragment& paint_fragment,
+    const LayoutSelectionStatus& selection_status) {
+  // Expand paint rect if selection covers multiple lines and
+  // this fragment is at the end of line.
+  if (selection_status.line_break == SelectLineBreak::kNotSelected)
+    return rect;
+  if (paint_fragment.GetLayoutObject()
+          ->EnclosingNGBlockFlow()
+          ->ShouldTruncateOverflowingText())
+    return rect;
+  // Copy from InlineTextBoxPainter.
+  const NGPaintFragment* container_line_box = paint_fragment.ContainerLineBox();
+  DCHECK(container_line_box);
+  const NGPhysicalLineBoxFragment& physical_line_box =
+      ToNGPhysicalLineBoxFragment(container_line_box->PhysicalFragment());
+  const LayoutUnit space_width(paint_fragment.Style().GetFont().SpaceWidth());
+  const NGPhysicalSize expanded_size(rect.size.width + space_width,
+                                     rect.size.height);
+  // TODO(yoichio): Support vertical writing mode.
+  // Consider sharing physical directional algorithm with ng_caret_rect.cc.
+  if (IsLtr(physical_line_box.BaseDirection()))
+    return NGPhysicalOffsetRect(rect.offset, expanded_size);
+  return NGPhysicalOffsetRect(
+      NGPhysicalOffset(rect.offset.left - space_width, rect.offset.top),
+      expanded_size);
+}
+
 }  // namespace
 
 NGTextFragmentPainter::NGTextFragmentPainter(
@@ -84,11 +115,15 @@
     return;
 
   GraphicsContextStateSaver state_saver(context);
-  const NGPhysicalOffsetRect& ng_rect =
+  const NGPhysicalOffsetRect& selection_rect =
       text_fragment.LocalRect(selection_status.start, selection_status.end);
-  LayoutRect selection_rect = ng_rect.ToLayoutRect();
-  selection_rect.MoveBy(box_rect.Location());
-  context.FillRect(FloatRect(selection_rect), color);
+  const NGPhysicalOffsetRect line_break_extended_rect =
+      ExpandedSelectionRectForLineBreakIfNeeded(selection_rect, paint_fragment,
+                                                selection_status);
+  const NGPhysicalOffsetRect global_rect(
+      line_break_extended_rect.offset + NGPhysicalOffset(box_rect.Location()),
+      line_break_extended_rect.size);
+  context.FillRect(global_rect.ToFloatRect(), color);
 }
 
 // This is copied from InlineTextBoxPainter::PaintSelection() but lacks of
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index a1032323..aa1c51c 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/timing/performance_event_timing.h"
 #include "third_party/blink/renderer/core/timing/performance_long_task_timing.h"
+#include "third_party/blink/renderer/core/timing/performance_mark.h"
 #include "third_party/blink/renderer/core/timing/performance_measure.h"
 #include "third_party/blink/renderer/core/timing/performance_measure_options.h"
 #include "third_party/blink/renderer/core/timing/performance_observer.h"
@@ -542,14 +543,14 @@
   NotifyObserversOfEntry(*entry);
 }
 
-void Performance::mark(ScriptState* script_state,
-                       const String& mark_name,
-                       ExceptionState& exception_state) {
+PerformanceMark* Performance::mark(ScriptState* script_state,
+                                   const String& mark_name,
+                                   ExceptionState& exception_state) {
   DoubleOrPerformanceMarkOptions startOrOptions;
-  this->mark(script_state, mark_name, startOrOptions, exception_state);
+  return this->mark(script_state, mark_name, startOrOptions, exception_state);
 }
 
-void Performance::mark(
+PerformanceMark* Performance::mark(
     ScriptState* script_state,
     const String& mark_name,
     DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
@@ -579,9 +580,11 @@
   }
 
   // Pass in a null ScriptValue if the mark's detail doesn't exist.
-  if (PerformanceEntry* entry = user_timing_->Mark(
-          script_state, mark_name, start, detail, exception_state))
-    NotifyObserversOfEntry(*entry);
+  PerformanceMark* performance_mark = user_timing_->Mark(
+      script_state, mark_name, start, detail, exception_state);
+  if (performance_mark)
+    NotifyObserversOfEntry(*performance_mark);
+  return performance_mark;
 }
 
 void Performance::clearMarks(const String& mark_name) {
@@ -759,12 +762,9 @@
   PerformanceMeasure* performance_measure =
       user_timing_->Measure(script_state, measure_name, original_start,
                             original_end, detail, exception_state);
-  if (performance_measure) {
-    PerformanceEntry* entry = performance_measure;
-    NotifyObserversOfEntry(*entry);
-    return performance_measure;
-  }
-  return nullptr;
+  if (performance_measure)
+    NotifyObserversOfEntry(*performance_measure);
+  return performance_measure;
 }
 
 void Performance::clearMeasures(const String& measure_name) {
diff --git a/third_party/blink/renderer/core/timing/performance.h b/third_party/blink/renderer/core/timing/performance.h
index d73a129..e2bbaf83e 100644
--- a/third_party/blink/renderer/core/timing/performance.h
+++ b/third_party/blink/renderer/core/timing/performance.h
@@ -57,6 +57,7 @@
 class MemoryInfo;
 class PerformanceNavigation;
 class PerformanceObserver;
+class PerformanceMark;
 class PerformanceMeasure;
 class PerformanceTiming;
 class ResourceResponse;
@@ -158,12 +159,13 @@
   void setEventTimingBufferMaxSize(unsigned);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(eventtimingbufferfull);
 
-  void mark(ScriptState*, const String& mark_name, ExceptionState&);
+  PerformanceMark* mark(ScriptState*, const String& mark_name, ExceptionState&);
 
-  void mark(ScriptState*,
-            const String& mark_name,
-            DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
-            ExceptionState&);
+  PerformanceMark* mark(
+      ScriptState*,
+      const String& mark_name,
+      DoubleOrPerformanceMarkOptions& start_time_or_mark_options,
+      ExceptionState&);
 
   void clearMarks(const String& mark_name);
 
diff --git a/third_party/blink/renderer/core/timing/performance.idl b/third_party/blink/renderer/core/timing/performance.idl
index 4339862..d74038e 100644
--- a/third_party/blink/renderer/core/timing/performance.idl
+++ b/third_party/blink/renderer/core/timing/performance.idl
@@ -65,7 +65,7 @@
     // User Timing
     // https://w3c.github.io/user-timing/#extensions-performance-interface
     [MeasureAs=UserTiming, CallWith=ScriptState, RaisesException] void mark(DOMString markName);
-    [MeasureAs=UserTiming, CallWith=ScriptState, RuntimeEnabled=CustomUserTiming, RaisesException] void mark(DOMString markName, (DOMHighResTimeStamp or PerformanceMarkOptions) startTimeOrPerformanceMarkOptions);
+    [MeasureAs=UserTiming, CallWith=ScriptState, RuntimeEnabled=CustomUserTiming, RaisesException] PerformanceMark? mark(DOMString markName, (DOMHighResTimeStamp or PerformanceMarkOptions) startTimeOrPerformanceMarkOptions);
     [MeasureAs=UserTiming] void clearMarks(optional DOMString markName = null);
 
     // Doing either of the following requires enabling CustomUserTiming:
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.cc b/third_party/blink/renderer/core/timing/performance_user_timing.cc
index 492cc64..68a478c 100644
--- a/third_party/blink/renderer/core/timing/performance_user_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -99,11 +99,11 @@
     performance_entry_map.erase(name);
 }
 
-PerformanceEntry* UserTiming::Mark(ScriptState* script_state,
-                                   const String& mark_name,
-                                   const DOMHighResTimeStamp& start_time,
-                                   const ScriptValue& detail,
-                                   ExceptionState& exception_state) {
+PerformanceMark* UserTiming::Mark(ScriptState* script_state,
+                                  const String& mark_name,
+                                  const DOMHighResTimeStamp& start_time,
+                                  const ScriptValue& detail,
+                                  ExceptionState& exception_state) {
   if (GetRestrictedKeyMap().Contains(mark_name)) {
     exception_state.ThrowDOMException(
         kSyntaxError, "'" + mark_name +
@@ -113,14 +113,14 @@
   }
 
   TRACE_EVENT_COPY_MARK("blink.user_timing", mark_name.Utf8().data());
-  PerformanceEntry* entry =
+  PerformanceMark* mark =
       PerformanceMark::Create(script_state, mark_name, start_time, detail);
-  InsertPerformanceEntry(marks_map_, *entry);
+  InsertPerformanceEntry(marks_map_, *mark);
   DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram,
                                   user_timing_mark_histogram,
                                   ("PLT.UserTiming_Mark", 0, 600000, 100));
   user_timing_mark_histogram.Count(static_cast<int>(start_time));
-  return entry;
+  return mark;
 }
 
 void UserTiming::ClearMarks(const String& mark_name) {
@@ -202,16 +202,16 @@
       WTF::StringHash::GetHash(measure_name),
       TraceEvent::ToTraceTimestamp(end_time_monotonic));
 
-  PerformanceMeasure* entry = PerformanceMeasure::Create(
+  PerformanceMeasure* measure = PerformanceMeasure::Create(
       script_state, measure_name, start_time, end_time, detail);
-  InsertPerformanceEntry(measures_map_, *entry);
+  InsertPerformanceEntry(measures_map_, *measure);
   if (end_time >= start_time) {
     DEFINE_THREAD_SAFE_STATIC_LOCAL(
         CustomCountHistogram, measure_duration_histogram,
         ("PLT.UserTiming_MeasureDuration", 0, 600000, 100));
     measure_duration_histogram.Count(static_cast<int>(end_time - start_time));
   }
-  return entry;
+  return measure;
 }
 
 void UserTiming::ClearMeasures(const String& measure_name) {
diff --git a/third_party/blink/renderer/core/timing/performance_user_timing.h b/third_party/blink/renderer/core/timing/performance_user_timing.h
index aed6e15..829da54 100644
--- a/third_party/blink/renderer/core/timing/performance_user_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_user_timing.h
@@ -47,11 +47,11 @@
     return new UserTiming(performance);
   }
 
-  PerformanceEntry* Mark(ScriptState*,
-                         const String& mark_name,
-                         const DOMHighResTimeStamp& start_time,
-                         const ScriptValue& detail,
-                         ExceptionState&);
+  PerformanceMark* Mark(ScriptState*,
+                        const String& mark_name,
+                        const DOMHighResTimeStamp& start_time,
+                        const ScriptValue& detail,
+                        ExceptionState&);
   void ClearMarks(const String& mark_name);
 
   PerformanceMeasure* Measure(ScriptState*,
diff --git a/third_party/blink/renderer/modules/exported/BUILD.gn b/third_party/blink/renderer/modules/exported/BUILD.gn
index 0e7590d5..686411e 100644
--- a/third_party/blink/renderer/modules/exported/BUILD.gn
+++ b/third_party/blink/renderer/modules/exported/BUILD.gn
@@ -44,6 +44,4 @@
     "//third_party/blink/renderer:config",
     "//third_party/blink/renderer/core:blink_core_pch",
   ]
-
-  include_dirs = [ "$root_gen_dir/third_party/blink/renderer" ]
 }
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 4c11cc9e..185d207a 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -166,11 +166,6 @@
 import("//build/config/pch.gni")
 
 config("blink_platform_config") {
-  include_dirs = [
-    #"$angle_path/include",
-    "$root_gen_dir/third_party/blink/renderer",
-  ]
-
   configs = [
     "//third_party/blink/renderer:config",
     "//third_party/blink/renderer:inside_blink",
@@ -1978,8 +1973,6 @@
   ]
 
   defines = [ "INSIDE_BLINK" ]
-
-  include_dirs = [ "$root_gen_dir/third_party/blink/renderer" ]
 }
 
 executable("image_decode_bench") {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 1b614e3f..f93e910 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1554,8 +1554,7 @@
 
 void ResourceFetcher::MoveResourceLoaderToNonBlocking(ResourceLoader* loader) {
   DCHECK(loader);
-  // TODO(yoav): Convert CHECK to DCHECK if no crash reports come in.
-  CHECK(loaders_.Contains(loader));
+  DCHECK(loaders_.Contains(loader));
   non_blocking_loaders_.insert(loader);
   loaders_.erase(loader);
 }
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 021f788..42946db5 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -605,6 +605,7 @@
     },
     {
       name: "IncrementalShadowDOM",
+      status: "experimental",
     },
     {
       name: "InertAttribute",
@@ -1146,7 +1147,7 @@
     },
     {
       name: "ServiceWorkerUpdateViaCache",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "SetRootScroller",
diff --git a/ui/accessibility/ax_relative_bounds.cc b/ui/accessibility/ax_relative_bounds.cc
index e41cb3d6..87c3d581 100644
--- a/ui/accessibility/ax_relative_bounds.cc
+++ b/ui/accessibility/ax_relative_bounds.cc
@@ -33,7 +33,7 @@
   return *this;
 }
 
-bool AXRelativeBounds::operator==(const AXRelativeBounds& other) {
+bool AXRelativeBounds::operator==(const AXRelativeBounds& other) const {
   if (offset_container_id != other.offset_container_id)
     return false;
   if (bounds != other.bounds)
@@ -45,7 +45,7 @@
   return *transform == *other.transform;
 }
 
-bool AXRelativeBounds::operator!=(const AXRelativeBounds& other) {
+bool AXRelativeBounds::operator!=(const AXRelativeBounds& other) const {
   return !operator==(other);
 }
 
diff --git a/ui/accessibility/ax_relative_bounds.h b/ui/accessibility/ax_relative_bounds.h
index bb43598..18e92b2 100644
--- a/ui/accessibility/ax_relative_bounds.h
+++ b/ui/accessibility/ax_relative_bounds.h
@@ -39,8 +39,8 @@
 
   AXRelativeBounds(const AXRelativeBounds& other);
   AXRelativeBounds& operator=(AXRelativeBounds other);
-  bool operator!=(const AXRelativeBounds& other);
-  bool operator==(const AXRelativeBounds& other);
+  bool operator!=(const AXRelativeBounds& other) const;
+  bool operator==(const AXRelativeBounds& other) const;
 
   std::string ToString() const;
 
@@ -64,4 +64,4 @@
 
 }  // namespace ui
 
-#endif  // UI_ACCESSIBILITY_AX_NODE_DATA_H_
+#endif  // UI_ACCESSIBILITY_AX_RELATIVE_BOUNDS_H_
diff --git a/ui/base/ime/chromeos/mock_ime_engine_handler.cc b/ui/base/ime/chromeos/mock_ime_engine_handler.cc
index a8db1ae..413bb44 100644
--- a/ui/base/ime/chromeos/mock_ime_engine_handler.cc
+++ b/ui/base/ime/chromeos/mock_ime_engine_handler.cc
@@ -16,7 +16,8 @@
       last_text_input_context_(ui::TEXT_INPUT_TYPE_NONE,
                                ui::TEXT_INPUT_MODE_DEFAULT,
                                ui::TEXT_INPUT_FLAG_NONE,
-                               ui::TextInputClient::FOCUS_REASON_NONE),
+                               ui::TextInputClient::FOCUS_REASON_NONE,
+                               false /* should_do_learning */),
       last_set_surrounding_cursor_pos_(0),
       last_set_surrounding_anchor_pos_(0) {}
 
diff --git a/ui/base/ime/dummy_input_method.cc b/ui/base/ime/dummy_input_method.cc
index a73ec73..2afa00e9 100644
--- a/ui/base/ime/dummy_input_method.cc
+++ b/ui/base/ime/dummy_input_method.cc
@@ -81,6 +81,10 @@
   return false;
 }
 
+bool DummyInputMethod::GetClientShouldDoLearning() {
+  return false;
+}
+
 void DummyInputMethod::ShowImeIfNeeded() {
 }
 
diff --git a/ui/base/ime/dummy_input_method.h b/ui/base/ime/dummy_input_method.h
index 513213d..33743a4 100644
--- a/ui/base/ime/dummy_input_method.h
+++ b/ui/base/ime/dummy_input_method.h
@@ -42,6 +42,7 @@
   int GetTextInputFlags() const override;
   bool CanComposeInline() const override;
   bool IsCandidatePopupOpen() const override;
+  bool GetClientShouldDoLearning() override;
   void ShowImeIfNeeded() override;
 
   void AddObserver(InputMethodObserver* observer) override;
diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc
index 83e3a9d..2d0cb3a 100644
--- a/ui/base/ime/dummy_text_input_client.cc
+++ b/ui/base/ime/dummy_text_input_client.cc
@@ -135,4 +135,8 @@
   return base::EmptyString();
 }
 
+bool DummyTextInputClient::ShouldDoLearning() {
+  return false;
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/dummy_text_input_client.h b/ui/base/ime/dummy_text_input_client.h
index 63b0b35..0eca8ad 100644
--- a/ui/base/ime/dummy_text_input_client.h
+++ b/ui/base/ime/dummy_text_input_client.h
@@ -53,6 +53,7 @@
   bool IsTextEditCommandEnabled(TextEditCommand command) const override;
   void SetTextEditCommandForNextKeyEvent(TextEditCommand command) override;
   const std::string& GetClientSourceInfo() const override;
+  bool ShouldDoLearning() override;
 
   int insert_char_count() const { return insert_char_count_; }
   base::char16 last_insert_char() const { return last_insert_char_; }
diff --git a/ui/base/ime/ime_bridge.cc b/ui/base/ime/ime_bridge.cc
index c7539aa..f196d8a 100644
--- a/ui/base/ime/ime_bridge.cc
+++ b/ui/base/ime/ime_bridge.cc
@@ -26,7 +26,8 @@
         current_input_context_(ui::TEXT_INPUT_TYPE_NONE,
                                ui::TEXT_INPUT_MODE_DEFAULT,
                                0,
-                               ui::TextInputClient::FOCUS_REASON_NONE),
+                               ui::TextInputClient::FOCUS_REASON_NONE,
+                               false /* should_do_learning */),
         candidate_window_handler_(nullptr) {}
 #else
   IMEBridgeImpl()
@@ -36,7 +37,8 @@
         current_input_context_(ui::TEXT_INPUT_TYPE_NONE,
                                ui::TEXT_INPUT_MODE_DEFAULT,
                                0,
-                               ui::TextInputClient::FOCUS_REASON_NONE) {}
+                               ui::TextInputClient::FOCUS_REASON_NONE,
+                               false /* should_do_learning */) {}
 #endif
 
   ~IMEBridgeImpl() override {}
diff --git a/ui/base/ime/ime_engine_handler_interface.h b/ui/base/ime/ime_engine_handler_interface.h
index 3a246117..fdca0ee 100644
--- a/ui/base/ime/ime_engine_handler_interface.h
+++ b/ui/base/ime/ime_engine_handler_interface.h
@@ -38,21 +38,25 @@
     InputContext(TextInputType type_,
                  TextInputMode mode_,
                  int flags_,
-                 TextInputClient::FocusReason focus_reason_)
+                 TextInputClient::FocusReason focus_reason_,
+                 bool should_do_learning_)
         : type(type_),
           mode(mode_),
           flags(flags_),
-          focus_reason(focus_reason_) {}
+          focus_reason(focus_reason_),
+          should_do_learning(should_do_learning_) {}
     InputContext(int id_,
                  TextInputType type_,
                  TextInputMode mode_,
                  int flags_,
-                 TextInputClient::FocusReason focus_reason_)
+                 TextInputClient::FocusReason focus_reason_,
+                 bool should_do_learning_)
         : id(id_),
           type(type_),
           mode(mode_),
           flags(flags_),
-          focus_reason(focus_reason_) {}
+          focus_reason(focus_reason_),
+          should_do_learning(should_do_learning_) {}
     // An attribute of the context id which used for ChromeOS only.
     int id;
     // An attribute of the field defined at
@@ -69,6 +73,9 @@
     // An attribute to indicate how this input field was focused.
     TextInputClient::FocusReason focus_reason =
         TextInputClient::FOCUS_REASON_NONE;
+    // An attribute to indicate whether text entered in this field should be
+    // used to improve typing suggestions for the user.
+    bool should_do_learning = false;
   };
 
   virtual ~IMEEngineHandlerInterface() {}
diff --git a/ui/base/ime/input_method.h b/ui/base/ime/input_method.h
index eb7bb92..c1ad7f20 100644
--- a/ui/base/ime/input_method.h
+++ b/ui/base/ime/input_method.h
@@ -158,6 +158,10 @@
   // of IME popups is not supported.
   virtual bool IsCandidatePopupOpen() const = 0;
 
+  // Check whether text entered into the focused text input client should be
+  // used to improve typing suggestions for the user.
+  virtual bool GetClientShouldDoLearning() = 0;
+
   // Displays an on screen keyboard if enabled.
   virtual void ShowImeIfNeeded() = 0;
 
diff --git a/ui/base/ime/input_method_auralinux.cc b/ui/base/ime/input_method_auralinux.cc
index 696ca681..6997920 100644
--- a/ui/base/ime/input_method_auralinux.cc
+++ b/ui/base/ime/input_method_auralinux.cc
@@ -250,7 +250,7 @@
 
   ui::IMEEngineHandlerInterface::InputContext context(
       GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-      ui::TextInputClient::FOCUS_REASON_OTHER);
+      ui::TextInputClient::FOCUS_REASON_OTHER, GetClientShouldDoLearning());
   ui::IMEBridge::Get()->SetCurrentInputContext(context);
 
   ui::IMEEngineHandlerInterface* engine = GetEngine();
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index e3805d9..f01fdd1 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -121,6 +121,11 @@
   return client ? client->CanComposeInline() : true;
 }
 
+bool InputMethodBase::GetClientShouldDoLearning() {
+  TextInputClient* client = GetTextInputClient();
+  return client && client->ShouldDoLearning();
+}
+
 void InputMethodBase::ShowImeIfNeeded() {
   for (InputMethodObserver& observer : observer_list_)
     observer.OnShowImeIfNeeded();
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h
index 6896502..e996e6d 100644
--- a/ui/base/ime/input_method_base.h
+++ b/ui/base/ime/input_method_base.h
@@ -62,6 +62,7 @@
   TextInputMode GetTextInputMode() const override;
   int GetTextInputFlags() const override;
   bool CanComposeInline() const override;
+  bool GetClientShouldDoLearning() override;
   void ShowImeIfNeeded() override;
 
   void AddObserver(InputMethodObserver* observer) override;
diff --git a/ui/base/ime/input_method_chromeos.cc b/ui/base/ime/input_method_chromeos.cc
index 01a00a0..3f894845 100644
--- a/ui/base/ime/input_method_chromeos.cc
+++ b/ui/base/ime/input_method_chromeos.cc
@@ -193,7 +193,7 @@
     engine->FocusOut();
     ui::IMEEngineHandlerInterface::InputContext context(
         GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-        GetClientFocusReason());
+        GetClientFocusReason(), GetClientShouldDoLearning());
     engine->FocusIn(context);
   }
 
@@ -310,7 +310,7 @@
   if (GetEngine()) {
     ui::IMEEngineHandlerInterface::InputContext context(
         GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-        GetClientFocusReason());
+        GetClientFocusReason(), GetClientShouldDoLearning());
     GetEngine()->FocusIn(context);
   }
 }
@@ -355,7 +355,7 @@
 
   ui::IMEEngineHandlerInterface::InputContext context(
       GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-      GetClientFocusReason());
+      GetClientFocusReason(), GetClientShouldDoLearning());
   ui::IMEBridge::Get()->SetCurrentInputContext(context);
 
   if (!IsTextInputTypeNone())
diff --git a/ui/base/ime/input_method_win.cc b/ui/base/ime/input_method_win.cc
index 8509b095..c42abc2 100644
--- a/ui/base/ime/input_method_win.cc
+++ b/ui/base/ime/input_method_win.cc
@@ -497,7 +497,7 @@
       ui::IMEBridge::Get()->GetCurrentInputContext().type;
   ui::IMEEngineHandlerInterface::InputContext context(
       GetTextInputType(), GetTextInputMode(), GetTextInputFlags(),
-      ui::TextInputClient::FOCUS_REASON_OTHER);
+      ui::TextInputClient::FOCUS_REASON_OTHER, GetClientShouldDoLearning());
   ui::IMEBridge::Get()->SetCurrentInputContext(context);
 
   ui::IMEEngineHandlerInterface* engine = GetEngine();
diff --git a/ui/base/ime/mock_input_method.cc b/ui/base/ime/mock_input_method.cc
index d381c50..056a0a1 100644
--- a/ui/base/ime/mock_input_method.cc
+++ b/ui/base/ime/mock_input_method.cc
@@ -105,6 +105,10 @@
   return false;
 }
 
+bool MockInputMethod::GetClientShouldDoLearning() {
+  return false;
+}
+
 void MockInputMethod::ShowImeIfNeeded() {
   for (InputMethodObserver& observer : observer_list_)
     observer.OnShowImeIfNeeded();
diff --git a/ui/base/ime/mock_input_method.h b/ui/base/ime/mock_input_method.h
index ebc0cc01..a932271 100644
--- a/ui/base/ime/mock_input_method.h
+++ b/ui/base/ime/mock_input_method.h
@@ -54,6 +54,7 @@
   int GetTextInputFlags() const override;
   bool CanComposeInline() const override;
   bool IsCandidatePopupOpen() const override;
+  bool GetClientShouldDoLearning() override;
   void ShowImeIfNeeded() override;
   void AddObserver(InputMethodObserver* observer) override;
   void RemoveObserver(InputMethodObserver* observer) override;
diff --git a/ui/base/ime/text_input_client.h b/ui/base/ime/text_input_client.h
index 19e3b74..2f7d4fc 100644
--- a/ui/base/ime/text_input_client.h
+++ b/ui/base/ime/text_input_client.h
@@ -190,6 +190,11 @@
   // Returns a string description of the view hosting the given text input
   // element (ie. the URL for web contents), used for recording metrics.
   virtual const std::string& GetClientSourceInfo() const = 0;
+
+  // Returns whether text entered into this text client should be used to
+  // improve typing suggestions for the user. This should return false for text
+  // fields that are considered 'private' (e.g. in incognito tabs).
+  virtual bool ShouldDoLearning() = 0;
 };
 
 }  // namespace ui
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index 9392429..1f4cf086 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -44,6 +44,7 @@
   MOCK_CONST_METHOD2(GetCompositionCharacterBounds, bool(uint32_t, gfx::Rect*));
   MOCK_CONST_METHOD0(HasCompositionText, bool());
   MOCK_CONST_METHOD0(GetFocusReason, ui::TextInputClient::FocusReason());
+  MOCK_METHOD0(ShouldDoLearning, bool());
   MOCK_CONST_METHOD1(GetTextRange, bool(gfx::Range*));
   MOCK_CONST_METHOD1(GetCompositionTextRange, bool(gfx::Range*));
   MOCK_CONST_METHOD1(GetSelectionRange, bool(gfx::Range*));
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc
index 172dde2b..6590a8e0b 100644
--- a/ui/views/controls/prefix_selector.cc
+++ b/ui/views/controls/prefix_selector.cc
@@ -151,6 +151,12 @@
   return base::EmptyString();
 }
 
+bool PrefixSelector::ShouldDoLearning() {
+  // TODO(https://crbug.com/311180): Implement this method.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return false;
+}
+
 void PrefixSelector::OnTextInput(const base::string16& text) {
   // Small hack to filter out 'tab' and 'enter' input, as the expectation is
   // that they are control characters and will not affect the currently-active
diff --git a/ui/views/controls/prefix_selector.h b/ui/views/controls/prefix_selector.h
index 937da79..e3654eeb 100644
--- a/ui/views/controls/prefix_selector.h
+++ b/ui/views/controls/prefix_selector.h
@@ -61,6 +61,7 @@
   bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
   void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override;
   const std::string& GetClientSourceInfo() const override;
+  bool ShouldDoLearning() override;
 
  private:
   // Invoked when text is typed. Tries to change the selection appropriately.
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 3119ee3..469f5a75 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1768,6 +1768,12 @@
   return base::EmptyString();
 }
 
+bool Textfield::ShouldDoLearning() {
+  // TODO(https://crbug.com/311180): Implement this method.
+  NOTIMPLEMENTED_LOG_ONCE();
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Textfield, protected:
 
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 8834ac08..ee7be5c3 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -359,6 +359,7 @@
   bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override;
   void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override;
   const std::string& GetClientSourceInfo() const override;
+  bool ShouldDoLearning() override;
 
  protected:
   // Inserts or appends a character in response to an IME operation.
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn
index b87727d..664e3c3 100644
--- a/ui/webui/resources/cr_elements/BUILD.gn
+++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -10,11 +10,13 @@
     "chromeos/cr_picture:closure_compile",
     "chromeos/network:closure_compile",
     "cr_action_menu:closure_compile",
+    "cr_checkbox:closure_compile",
     "cr_dialog:closure_compile",
     "cr_drawer:closure_compile",
     "cr_expand_button:closure_compile",
     "cr_link_row:closure_compile",
     "cr_profile_avatar_selector:closure_compile",
+    "cr_radio_button:closure_compile",
     "cr_toast:closure_compile",
     "cr_toggle:closure_compile",
     "policy:closure_compile",
diff --git a/ui/webui/resources/cr_elements/compiled_resources2.gyp b/ui/webui/resources/cr_elements/compiled_resources2.gyp
index 59c868b..fab52d7 100644
--- a/ui/webui/resources/cr_elements/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/compiled_resources2.gyp
@@ -10,11 +10,13 @@
         'chromeos/cr_picture/compiled_resources2.gyp:*',
         'chromeos/network/compiled_resources2.gyp:*',
         'cr_action_menu/compiled_resources2.gyp:*',
+        'cr_checkbox/compiled_resources2.gyp:*',
         'cr_dialog/compiled_resources2.gyp:*',
         'cr_drawer/compiled_resources2.gyp:*',
         'cr_expand_button/compiled_resources2.gyp:*',
         'cr_link_row/compiled_resources2.gyp:*',
         'cr_profile_avatar_selector/compiled_resources2.gyp:*',
+        'cr_radio_button/compiled_resources2.gyp:*',
         'cr_toast/compiled_resources2.gyp:*',
         'cr_toggle/compiled_resources2.gyp:*',
         'policy/compiled_resources2.gyp:*',
diff --git a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
index 6111d535..586d23a2 100644
--- a/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
+++ b/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.html
@@ -1,8 +1,9 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="../shared_vars_css.html">
+
 <!--
 List of customizable styles:
 
@@ -36,7 +37,7 @@
 
       :host([disabled]) {
         cursor: initial;
-        opacity: 0.38;
+        opacity: var(--cr-disabled-opacity);
         pointer-events: none;
       }
 
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn b/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn
new file mode 100644
index 0000000..0525dbb
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn
@@ -0,0 +1,24 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":cr_radio_button",
+  ]
+}
+
+js_library("cr_radio_button") {
+  deps = [
+    ":cr_radio_button_behavior",
+  ]
+}
+
+js_library("cr_radio_button_behavior") {
+  deps = [
+    "//third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
+    "//third_party/polymer/v1_0/components-chromium/paper-behaviors:paper-ripple-behavior-extracted",
+  ]
+}
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/compiled_resources2.gyp b/ui/webui/resources/cr_elements/cr_radio_button/compiled_resources2.gyp
new file mode 100644
index 0000000..d9d1301e
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/compiled_resources2.gyp
@@ -0,0 +1,22 @@
+# 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.
+{
+  'targets': [
+    {
+      'target_name': 'cr_radio_button',
+      'dependencies': [
+        'cr_radio_button_behavior'
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'cr_radio_button_behavior',
+      'dependencies': [
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/compiled_resources2.gyp:iron-a11y-keys-behavior-extracted',
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-behaviors/compiled_resources2.gyp:paper-ripple-behavior-extracted',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+  ],
+}
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button.html b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button.html
new file mode 100644
index 0000000..cedb86e
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button.html
@@ -0,0 +1,23 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="../shared_vars_css.html">
+<link rel="import" href="cr_radio_button_behavior.html">
+<link rel="import" href="cr_radio_button_style_css.html">
+
+<dom-module id="cr-radio-button">
+  <template>
+    <style include="cr-radio-button-style"></style>
+
+    <div class="disc-wrapper">
+      <div class="disc-border"></div>
+      <div class="disc"></div>
+    </div>
+
+    <div id="labelWrapper">
+      <span id="label" hidden$="[[!label]]">[[label]]</span>
+      <slot></slot>
+    </div>
+  </template>
+  <script src="cr_radio_button.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button.js b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button.js
new file mode 100644
index 0000000..3af06db4
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button.js
@@ -0,0 +1,11 @@
+// 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.
+
+Polymer({
+  is: 'cr-radio-button',
+
+  behaviors: [
+    CrRadioButtonBehavior,
+  ],
+});
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.html b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.html
new file mode 100644
index 0000000..5942b35
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.html
@@ -0,0 +1,3 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-behaviors/paper-ripple-behavior.html">
+<script src="cr_radio_button_behavior.js"></script>
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js
new file mode 100644
index 0000000..0aca1c6e
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js
@@ -0,0 +1,112 @@
+// 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.
+
+/**
+ * @fileoverview Behavior for cr-radio-button-like elements.
+ */
+
+/** @polymerBehavior */
+var CrRadioButtonBehaviorImpl = {
+  properties: {
+    checked: {
+      type: Boolean,
+      value: false,
+      reflectToAttribute: true,
+      observer: 'checkedChanged_',
+    },
+
+    disabled: {
+      type: Boolean,
+      value: false,
+      reflectToAttribute: true,
+      observer: 'disabledChanged_',
+    },
+
+    label: {
+      type: String,
+      value: '',  // Allows the hidden$= binding to run without being set.
+    },
+  },
+
+  listeners: {
+    'focus': 'onFocus_',
+    'blur': 'cancelRipple_',
+    'pointerup': 'cancelRipple_',
+  },
+
+  hostAttributes: {
+    'aria-disabled': 'false',
+    'aria-checked': 'false',
+    role: 'radio',
+    tabindex: 0,
+  },
+
+  keyBindings: {
+    // This is mainly for screenreaders, which can perform actions on things
+    // that aren't focused (only focused things get synthetic click/tap events).
+    'enter:keyup': 'onSelectKeyUp_',
+    'space:keyup': 'onSelectKeyUp_',
+  },
+
+  /** @private */
+  checkedChanged_: function() {
+    this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
+  },
+
+  /**
+   * @param {boolean} current
+   * @param {boolean} previous
+   * @private
+   */
+  disabledChanged_: function(current, previous) {
+    if (previous === undefined && !this.disabled)
+      return;
+
+    this.setAttribute('tabindex', this.disabled ? -1 : 0);
+    this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
+  },
+
+  /** @private */
+  onFocus_: function() {
+    this.ensureRipple();
+    this.$$('paper-ripple').holdDown = true;
+  },
+
+  /**
+   * @param {!{detail: {keyboardEvent: !Event}}} e
+   * @private
+   */
+  onSelectKeyUp_: function(e) {
+    // If ripple is disabled, or focus is on a link, don't propagate to the
+    // parent paper-radio-group to avoid incorrect selection.
+    if (this.disabled || e.detail.keyboardEvent.target.tagName == 'A')
+      return;
+
+    this.click();
+  },
+
+  /** @private */
+  cancelRipple_: function() {
+    this.ensureRipple();
+    this.$$('paper-ripple').holdDown = false;
+  },
+
+  // customize the element's ripple
+  _createRipple: function() {
+    this._rippleContainer = this.$$('.disc-wrapper');
+    let ripple = Polymer.PaperRippleBehavior._createRipple();
+    ripple.id = 'ink';
+    ripple.setAttribute('recenters', '');
+    ripple.classList.add('circle', 'toggle-ink');
+    return ripple;
+  },
+};
+
+
+/** @polymerBehavior */
+const CrRadioButtonBehavior = [
+  Polymer.IronA11yKeysBehavior,
+  Polymer.PaperRippleBehavior,
+  CrRadioButtonBehaviorImpl,
+];
\ No newline at end of file
diff --git a/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html
new file mode 100644
index 0000000..7072cc0
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html
@@ -0,0 +1,99 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+<link rel="import" href="../shared_vars_css.html">
+
+<!-- Common radio-button styling for Material Design WebUI. -->
+<dom-module id="cr-radio-button-style">
+  <template>
+    <style>
+      :host {
+        --cr-radio-button-ink-size: 40px;
+        --cr-radio-button-size: 16px;
+        --cr-radio-button-checked-color: var(--google-blue-600);
+
+        --ink-to-circle: calc((var(--cr-radio-button-ink-size) -
+                               var(--cr-radio-button-size)) / 2);
+        align-items: center;
+        display: flex;
+        flex-shrink: 0;
+        min-height: 48px;
+        outline: none;
+      }
+
+      :host([disabled]) {
+        opacity: var(--cr-disabled-opacity);
+        /* Disable pointer events for this whole element, as outer on-tap gets
+         * triggered when clicking/tapping anywhere in :host. */
+        pointer-events: none;
+      }
+
+      :host(:not([disabled])) {
+        cursor: pointer;
+      }
+
+      #labelWrapper {
+        -webkit-margin-start: var(--cr-radio-button-label-spacing, 20px);
+        flex: 1;
+
+        @apply --cr-radio-button-label;
+      }
+
+      #label {
+        color: inherit;
+      }
+
+      .disc-border,
+      .disc,
+      .disc-wrapper,
+      paper-ripple {
+        border-radius: 50%;
+      }
+
+      .disc-wrapper {
+        height: var(--cr-radio-button-ink-size);
+        margin: 0 calc(-1 * var(--ink-to-circle));
+        position: relative;
+        width: var(--cr-radio-button-ink-size);
+      }
+
+      .disc-border,
+      .disc {
+        box-sizing: border-box;
+        height: var(--cr-radio-button-size);
+        left: var(--ink-to-circle);
+        position: absolute;
+        top: var(--ink-to-circle);
+        width: var(--cr-radio-button-size);
+      }
+
+      .disc-border {
+        border: 2px solid var(--google-grey-700);
+      }
+
+      :host([checked]) .disc-border {
+        border-color: var(--cr-radio-button-checked-color);
+      }
+
+      .disc {
+        background-color: transparent;
+        transform: scale(0);
+        transition: border-color 200ms, transform 200ms;
+      }
+
+      :host([checked]) .disc {
+        background-color: var(--cr-radio-button-checked-color);
+        transform: scale(0.5);
+      }
+
+      paper-ripple {
+        --paper-ripple-opacity: 0.1;
+        color: var(--google-grey-900);
+      }
+
+      :host([checked]) paper-ripple {
+        color: var(--google-blue-600);
+      }
+    </style>
+  </template>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html b/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
index 4b3f0bd..7d30684 100644
--- a/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
+++ b/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.html
@@ -14,7 +14,7 @@
 
       :host([disabled]) {
         cursor: initial;
-        opacity: 0.38;
+        opacity: var(--cr-disabled-opacity);
         pointer-events: none;
       }
 
diff --git a/ui/webui/resources/cr_elements/shared_style_css.html b/ui/webui/resources/cr_elements/shared_style_css.html
index 175dc75..28cabebb 100644
--- a/ui/webui/resources/cr_elements/shared_style_css.html
+++ b/ui/webui/resources/cr_elements/shared_style_css.html
@@ -54,11 +54,11 @@
         min-height: 1px;
       }
 
-      [selectable]:focus,
-      [selectable] > :focus {
+      [selectable]:not(paper-radio-group):focus,
+      [selectable]:not(paper-radio-group) > :focus {
         @apply --cr-selectable-focus;
       }
-      [selectable] > * {
+      [selectable]:not(paper-radio-group) > * {
         @apply --cr-actionable;
       }
 
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index 3ffc0b3..ef0dfdb 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -119,6 +119,7 @@
     --cr-container-shadow-max-opacity: 1;
 
     /** MD Refresh Styles */
+    --cr-disabled-opacity: 0.38;
     --google-blue-600: #1A73E8;
     --google-grey-200: #E8EAED;
     --google-grey-400: #BDC1C6;
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index b3b2d42..0c8e879 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -78,6 +78,26 @@
              file="../../webui/resources/cr_elements/cr_link_row/cr_link_row.js"
              type="chrome_html"
              compress="gzip" />
+  <structure name="IDR_CR_ELEMENTS_CR_RADIO_BUTTON_HTML"
+             file="../../webui/resources/cr_elements/cr_radio_button/cr_radio_button.html"
+             type="chrome_html"
+             compress="gzip" />
+  <structure name="IDR_CR_ELEMENTS_CR_RADIO_BUTTON_JS"
+             file="../../webui/resources/cr_elements/cr_radio_button/cr_radio_button.js"
+             type="chrome_html"
+             compress="gzip" />
+  <structure name="IDR_CR_ELEMENTS_CR_RADIO_BUTTON_BEHAVIOR_HTML"
+             file="../../webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.html"
+             type="chrome_html"
+             compress="gzip" />
+  <structure name="IDR_CR_ELEMENTS_CR_RADIO_BUTTON_BEHAVIOR_JS"
+             file="../../webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js"
+             type="chrome_html"
+             compress="gzip" />
+  <structure name="IDR_CR_ELEMENTS_CR_RADIO_BUTTON_STYLE_CSS_HTML"
+             file="../../webui/resources/cr_elements/cr_radio_button/cr_radio_button_style_css.html"
+             type="chrome_html"
+             compress="gzip" />
   <if expr="chromeos">
     <structure name="IDR_CR_ELEMENTS_CHROMEOS_CR_PICTURE_CR_CAMERA_HTML"
                file="../../webui/resources/cr_elements/chromeos/cr_picture/cr_camera.html"