diff --git a/DEPS b/DEPS
index 5382ad0..12845a1 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': '10b9a3e5fedf25be365758a2cec66284b3d3874b',
+  'v8_revision': 'eccd93f7ea3f5dfae67f548489dfce5fcbf0869e',
   # 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.
@@ -96,7 +96,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': 'fa1d11d0530dd5eb7992dd7e599e6b9908afe8c7',
+  'catapult_revision': '1c3f4b92178893dfd439e64740a3aa334fdac21f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 6752881..20e933d 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -380,7 +380,6 @@
     "system/network/network_info.h",
     "system/network/network_list.cc",
     "system/network/network_list.h",
-    "system/network/network_list_delegate.h",
     "system/network/network_list_view_base.cc",
     "system/network/network_list_view_base.h",
     "system/network/network_observer.h",
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc
index 58bc5f6..179914c 100644
--- a/ash/system/network/network_list.cc
+++ b/ash/system/network/network_list.cc
@@ -4,18 +4,29 @@
 
 #include "ash/system/network/network_list.h"
 
-#include <stddef.h>
+#include <memory>
 
+#include "ash/shell.h"
+#include "ash/shell_port.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/network/network_icon.h"
 #include "ash/system/network/network_icon_animation.h"
-#include "ash/system/network/network_list_delegate.h"
+#include "ash/system/network/network_info.h"
+#include "ash/system/network/network_state_list_detailed_view.h"
+#include "ash/system/networking_config_delegate.h"
+#include "ash/system/tray/fixed_sized_image_view.h"
+#include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/system_menu_button.h"
+#include "ash/system/tray/system_tray_controller.h"
+#include "ash/system/tray/system_tray_delegate.h"
+#include "ash/system/tray/throbber_view.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_item_style.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ash/system/tray/tri_view.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "chromeos/dbus/power_manager_client.h"
@@ -26,12 +37,16 @@
 #include "chromeos/network/network_state_handler_observer.h"
 #include "chromeos/network/proxy/ui_proxy_config_service.h"
 #include "components/device_event_log/device_event_log.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/font.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/text_constants.h"
 #include "ui/views/background.h"
+#include "ui/views/border.h"
 #include "ui/views/controls/button/toggle_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -73,6 +88,32 @@
       network->guid(), network->profile_path(), nullptr /* onc_source */);
 }
 
+// TODO(varkha|mohsen): Consolidate with a similar method in
+// BluetoothDetailedView (see https://crbug.com/686924).
+void SetupConnectedItem(HoverHighlightView* container,
+                        const base::string16& text,
+                        const gfx::ImageSkia& image) {
+  container->AddIconAndLabels(
+      image, text,
+      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED));
+  TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION);
+  style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED);
+  style.SetupLabel(container->sub_text_label());
+}
+
+// TODO(varkha|mohsen): Consolidate with a similar method in
+// BluetoothDetailedView (see https://crbug.com/686924).
+void SetupConnectingItem(HoverHighlightView* container,
+                         const base::string16& text,
+                         const gfx::ImageSkia& image) {
+  container->AddIconAndLabels(
+      image, text,
+      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING));
+  ThrobberView* throbber = new ThrobberView;
+  throbber->Start();
+  container->AddRightView(throbber);
+}
+
 }  // namespace
 
 // A header row for sections in network detailed view which contains a title and
@@ -210,9 +251,8 @@
 
 class WifiHeaderRowView : public NetworkListView::SectionHeaderRowView {
  public:
-  explicit WifiHeaderRowView(NetworkListDelegate* network_list_delegate)
+  WifiHeaderRowView()
       : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_WIFI),
-        network_list_delegate_(network_list_delegate),
         join_(nullptr) {}
 
   ~WifiHeaderRowView() override {}
@@ -252,7 +292,10 @@
 
   void ButtonPressed(views::Button* sender, const ui::Event& event) override {
     if (sender == join_) {
-      network_list_delegate_->OnOtherWifiClicked();
+      ShellPort::Get()->RecordUserMetricsAction(
+          UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED);
+      Shell::Get()->system_tray_controller()->ShowNetworkCreate(
+          shill::kTypeWifi);
       return;
     }
     SectionHeaderRowView::ButtonPressed(sender, event);
@@ -271,8 +314,6 @@
   // .30 * .38 opacity for disabled icon.
   static constexpr int kDisabledJoinIconAlpha = 0x1D;
 
-  NetworkListDelegate* network_list_delegate_;
-
   // A button to invoke "Join Wi-Fi network" dialog.
   SystemMenuButton* join_;
 
@@ -283,9 +324,10 @@
 
 // NetworkListView:
 
-NetworkListView::NetworkListView(NetworkListDelegate* delegate)
-    : needs_relayout_(false),
-      delegate_(delegate),
+NetworkListView::NetworkListView(
+    tray::NetworkStateListDetailedView* detailed_view)
+    : NetworkListViewBase(detailed_view),
+      needs_relayout_(false),
       no_wifi_networks_view_(nullptr),
       no_cellular_networks_view_(nullptr),
       cellular_header_view_(nullptr),
@@ -294,9 +336,7 @@
       cellular_separator_view_(nullptr),
       tether_separator_view_(nullptr),
       wifi_separator_view_(nullptr),
-      connection_warning_(nullptr) {
-  CHECK(delegate_);
-}
+      connection_warning_(nullptr) {}
 
 NetworkListView::~NetworkListView() {
   network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this);
@@ -345,9 +385,8 @@
     last_network_info_map_[info->guid] = std::move(info);
 
   network_list_.clear();
-  const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
   for (const auto* network : networks) {
-    if (!pattern.MatchesType(network->type()))
+    if (!NetworkTypePattern::NonVirtual().MatchesType(network->type()))
       continue;
 
     // Do not add Wi-Fi networks that are associated with a Tether network.
@@ -474,7 +513,7 @@
     }
   }
   container()->SizeToPreferredSize();
-  delegate_->RelayoutScrollList();
+  detailed_view()->RelayoutScrollList();
   if (selected_view)
     container()->ScrollRectToVisible(selected_view->bounds());
 }
@@ -505,33 +544,30 @@
       UpdateNetworkChildren(NetworkInfo::Type::UNKNOWN, index);
   index += new_guids->size();
 
-  const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern();
-  if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) {
-    if (handler->IsTechnologyAvailable(NetworkTypePattern::Cellular())) {
-      index = UpdateSectionHeaderRow(
-          NetworkTypePattern::Cellular(),
-          handler->IsTechnologyEnabled(NetworkTypePattern::Cellular()), index,
-          &cellular_header_view_, &cellular_separator_view_);
-    }
-
-    // Cellular initializing.
-    int message_id = network_icon::GetCellularUninitializedMsg();
-    if (!message_id &&
-        handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) &&
-        !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
-      message_id = IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS;
-    }
-    UpdateInfoLabel(message_id, index, &no_cellular_networks_view_);
-    if (message_id)
-      ++index;
-
-    // Add cellular networks.
-    std::unique_ptr<std::set<std::string>> new_cellular_guids =
-        UpdateNetworkChildren(NetworkInfo::Type::CELLULAR, index);
-    index += new_cellular_guids->size();
-    new_guids->insert(new_cellular_guids->begin(), new_cellular_guids->end());
+  if (handler->IsTechnologyAvailable(NetworkTypePattern::Cellular())) {
+    index = UpdateSectionHeaderRow(
+        NetworkTypePattern::Cellular(),
+        handler->IsTechnologyEnabled(NetworkTypePattern::Cellular()), index,
+        &cellular_header_view_, &cellular_separator_view_);
   }
 
+  // Cellular initializing.
+  int cellular_message_id = network_icon::GetCellularUninitializedMsg();
+  if (!cellular_message_id &&
+      handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) &&
+      !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
+    cellular_message_id = IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS;
+  }
+  UpdateInfoLabel(cellular_message_id, index, &no_cellular_networks_view_);
+  if (cellular_message_id)
+    ++index;
+
+  // Add cellular networks.
+  std::unique_ptr<std::set<std::string>> new_cellular_guids =
+      UpdateNetworkChildren(NetworkInfo::Type::CELLULAR, index);
+  index += new_cellular_guids->size();
+  new_guids->insert(new_cellular_guids->begin(), new_cellular_guids->end());
+
   // TODO (hansberry): Audit existing usage of NonVirtual and consider changing
   // it to include Tether. See crbug.com/693647.
   if (handler->IsTechnologyAvailable(NetworkTypePattern::Tether())) {
@@ -541,8 +577,8 @@
         &tether_header_view_, &tether_separator_view_);
 
     // TODO (hansberry): Should a message similar to
-    // IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS be shown if Tether technology
-    // is enabled but no networks are around?
+    // IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS be shown if Tether technology is
+    // enabled but no networks are around?
 
     // Add Tether networks.
     std::unique_ptr<std::set<std::string>> new_tether_guids =
@@ -551,29 +587,27 @@
     new_guids->insert(new_tether_guids->begin(), new_tether_guids->end());
   }
 
-  if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) {
-    index = UpdateSectionHeaderRow(
-        NetworkTypePattern::WiFi(),
-        handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index,
-        &wifi_header_view_, &wifi_separator_view_);
+  index = UpdateSectionHeaderRow(
+      NetworkTypePattern::WiFi(),
+      handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index,
+      &wifi_header_view_, &wifi_separator_view_);
 
-    // "Wifi Enabled / Disabled".
-    int message_id = 0;
-    if (network_list_.empty()) {
-      message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())
-                       ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED
-                       : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
-    }
-    UpdateInfoLabel(message_id, index, &no_wifi_networks_view_);
-    if (message_id)
-      ++index;
-
-    // Add Wi-Fi networks.
-    std::unique_ptr<std::set<std::string>> new_wifi_guids =
-        UpdateNetworkChildren(NetworkInfo::Type::WIFI, index);
-    index += new_wifi_guids->size();
-    new_guids->insert(new_wifi_guids->begin(), new_wifi_guids->end());
+  // "Wifi Enabled / Disabled".
+  int wifi_message_id = 0;
+  if (network_list_.empty()) {
+    wifi_message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi())
+                          ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED
+                          : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED;
   }
+  UpdateInfoLabel(wifi_message_id, index, &no_wifi_networks_view_);
+  if (wifi_message_id)
+    ++index;
+
+  // Add Wi-Fi networks.
+  std::unique_ptr<std::set<std::string>> new_wifi_guids =
+      UpdateNetworkChildren(NetworkInfo::Type::WIFI, index);
+  index += new_wifi_guids->size();
+  new_guids->insert(new_wifi_guids->begin(), new_wifi_guids->end());
 
   // No networks or other messages (fallback).
   if (index == 0) {
@@ -584,6 +618,63 @@
   return new_guids;
 }
 
+HoverHighlightView* NetworkListView::CreateViewForNetwork(
+    const NetworkInfo& info) {
+  HoverHighlightView* container = new HoverHighlightView(detailed_view());
+  if (info.connected)
+    SetupConnectedItem(container, info.label, info.image);
+  else if (info.connecting)
+    SetupConnectingItem(container, info.label, info.image);
+  else
+    container->AddIconAndLabel(info.image, info.label);
+  container->SetTooltipText(info.tooltip);
+  views::View* controlled_icon = CreateControlledByExtensionView(info);
+  if (controlled_icon)
+    container->AddChildView(controlled_icon);
+  return container;
+}
+
+void NetworkListView::UpdateViewForNetwork(HoverHighlightView* view,
+                                           const NetworkInfo& info) {
+  DCHECK(!view->has_children());
+  if (info.connected)
+    SetupConnectedItem(view, info.label, info.image);
+  else if (info.connecting)
+    SetupConnectingItem(view, info.label, info.image);
+  else
+    view->AddIconAndLabel(info.image, info.label);
+  views::View* controlled_icon = CreateControlledByExtensionView(info);
+  view->SetTooltipText(info.tooltip);
+  if (controlled_icon)
+    view->AddChildView(controlled_icon);
+}
+
+views::View* NetworkListView::CreateControlledByExtensionView(
+    const NetworkInfo& info) {
+  NetworkingConfigDelegate* networking_config_delegate =
+      Shell::Get()->system_tray_delegate()->GetNetworkingConfigDelegate();
+  if (!networking_config_delegate)
+    return nullptr;
+  std::unique_ptr<const NetworkingConfigDelegate::ExtensionInfo>
+      extension_info =
+          networking_config_delegate->LookUpExtensionForNetwork(info.guid);
+  if (!extension_info)
+    return nullptr;
+
+  // Get the tooltip text.
+  base::string16 tooltip_text = l10n_util::GetStringFUTF16(
+      IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI,
+      base::UTF8ToUTF16(extension_info->extension_name));
+
+  views::ImageView* controlled_icon =
+      new FixedSizedImageView(kTrayPopupDetailsIconWidth, 0);
+
+  controlled_icon->SetImage(
+      gfx::CreateVectorIcon(kCaptivePortalIcon, kMenuIconColor));
+  controlled_icon->SetTooltipText(tooltip_text);
+  return controlled_icon;
+}
+
 std::unique_ptr<std::set<std::string>> NetworkListView::UpdateNetworkChildren(
     NetworkInfo::Type type,
     int index) {
@@ -598,15 +689,15 @@
 }
 
 void NetworkListView::UpdateNetworkChild(int index, const NetworkInfo* info) {
-  views::View* network_view = nullptr;
+  HoverHighlightView* network_view = nullptr;
   NetworkGuidMap::const_iterator found = network_guid_map_.find(info->guid);
   if (found == network_guid_map_.end()) {
-    network_view = delegate_->CreateViewForNetwork(*info);
+    network_view = CreateViewForNetwork(*info);
   } else {
     network_view = found->second;
     if (NeedUpdateViewForNetwork(*info)) {
       network_view->RemoveAllChildViews(true);
-      delegate_->UpdateViewForNetwork(network_view, *info);
+      UpdateViewForNetwork(network_view, *info);
       network_view->Layout();
       network_view->SchedulePaint();
     }
@@ -643,8 +734,16 @@
   }
   base::string16 text =
       ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
-  if (!label)
-    label = delegate_->CreateInfoLabel();
+  if (!label) {
+    // TODO(mohsen): Update info label to follow MD specs. See
+    // https://crbug.com/687778.
+    label = new views::Label();
+    label->SetBorder(views::CreateEmptyBorder(
+        kTrayPopupPaddingBetweenItems, kTrayPopupPaddingHorizontal,
+        kTrayPopupPaddingBetweenItems, 0));
+    label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0));
+  }
   label->SetText(text);
   PlaceViewAtIndex(label, insertion_index);
   *label_ptr = label;
@@ -661,7 +760,7 @@
     else if (pattern.Equals(NetworkTypePattern::Tether()))
       *view = new TetherHeaderRowView();
     else if (pattern.Equals(NetworkTypePattern::WiFi()))
-      *view = new WifiHeaderRowView(delegate_);
+      *view = new WifiHeaderRowView();
     else
       NOTREACHED();
     (*view)->Init(enabled);
diff --git a/ash/system/network/network_list.h b/ash/system/network/network_list.h
index 94152d74..33790cb 100644
--- a/ash/system/network/network_list.h
+++ b/ash/system/network/network_list.h
@@ -26,9 +26,8 @@
 }
 
 namespace ash {
-
+class HoverHighlightView;
 struct NetworkInfo;
-class NetworkListDelegate;
 class TriView;
 
 // A list of available networks of a given type. This class is used for all
@@ -38,7 +37,7 @@
  public:
   class SectionHeaderRowView;
 
-  explicit NetworkListView(NetworkListDelegate* delegate);
+  explicit NetworkListView(tray::NetworkStateListDetailedView* detailed_view);
   ~NetworkListView() override;
 
   // NetworkListViewBase:
@@ -72,6 +71,18 @@
   // being used.
   TriView* CreateConnectionWarning();
 
+  // Creates and returns a View with the information in |info|.
+  HoverHighlightView* CreateViewForNetwork(const NetworkInfo& info);
+
+  // Updates |view| with the information in |info|. Note that |view| is
+  // guaranteed to be a View returned from |CreateViewForNetwork()|.
+  void UpdateViewForNetwork(HoverHighlightView* view, const NetworkInfo& info);
+
+  // Creates the view of an extra icon appearing next to the network name
+  // indicating that the network is controlled by an extension. If no extension
+  // is registered for this network, returns |nullptr|.
+  views::View* CreateControlledByExtensionView(const NetworkInfo& info);
+
   // Adds or updates child views representing the network connections when
   // |is_wifi| is matching the attribute of a network connection starting at
   // |child_index|. Returns a set of guids for the added network
@@ -112,7 +123,6 @@
   bool NeedUpdateViewForNetwork(const NetworkInfo& info) const;
 
   bool needs_relayout_;
-  NetworkListDelegate* delegate_;
 
   views::Label* no_wifi_networks_view_;
   views::Label* no_cellular_networks_view_;
@@ -131,7 +141,7 @@
   NetworkMap network_map_;
 
   // A map of network guids to their view.
-  using NetworkGuidMap = std::map<std::string, views::View*>;
+  using NetworkGuidMap = std::map<std::string, HoverHighlightView*>;
   NetworkGuidMap network_guid_map_;
 
   // Save a map of network guids to their infos against current |network_list_|.
diff --git a/ash/system/network/network_list_delegate.h b/ash/system/network/network_list_delegate.h
deleted file mode 100644
index a8fb3c2..0000000
--- a/ash/system/network/network_list_delegate.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_SYSTEM_NETWORK_NETWORK_LIST_DELEGATE_H_
-#define ASH_SYSTEM_NETWORK_NETWORK_LIST_DELEGATE_H_
-
-namespace chromeos {
-class NetworkTypePattern;
-}
-
-namespace views {
-class Label;
-class View;
-}
-
-namespace ash {
-
-struct NetworkInfo;
-
-class NetworkListDelegate {
- public:
-  virtual ~NetworkListDelegate() {}
-
-  // Creates and returns a View with the information in |info|.
-  virtual views::View* CreateViewForNetwork(const NetworkInfo& info) = 0;
-
-  // Returns the type of network this list should use.
-  virtual chromeos::NetworkTypePattern GetNetworkTypePattern() const = 0;
-
-  // Updates |view| with the information in |info|. Note that |view| is
-  // guaranteed to be a View returned from |CreateViewForNetwork()|.
-  virtual void UpdateViewForNetwork(views::View* view,
-                                    const NetworkInfo& info) = 0;
-
-  // Creates a Label to be displayed in the list to present some information
-  // (e.g. unavailability of network etc.).
-  virtual views::Label* CreateInfoLabel() = 0;
-
-  // Called when the user clicks on an entry representing a network in the list.
-  virtual void OnNetworkEntryClicked(views::View* sender) = 0;
-
-  // Called when the user clicks on a "Join Other" button.
-  virtual void OnOtherWifiClicked() = 0;
-
-  virtual void RelayoutScrollList() = 0;
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_NETWORK_NETWORK_LIST_DELEGATE_H_
diff --git a/ash/system/network/network_list_view_base.cc b/ash/system/network/network_list_view_base.cc
index a20383b..c4b611a 100644
--- a/ash/system/network/network_list_view_base.cc
+++ b/ash/system/network/network_list_view_base.cc
@@ -4,9 +4,15 @@
 
 #include "ash/system/network/network_list_view_base.h"
 
+#include "base/logging.h"
+
 namespace ash {
 
-NetworkListViewBase::NetworkListViewBase() {}
+NetworkListViewBase::NetworkListViewBase(
+    tray::NetworkStateListDetailedView* detailed_view)
+    : detailed_view_(detailed_view) {
+  DCHECK(detailed_view_);
+}
 
 NetworkListViewBase::~NetworkListViewBase() {}
 
diff --git a/ash/system/network/network_list_view_base.h b/ash/system/network/network_list_view_base.h
index c5eee11..cd37c958 100644
--- a/ash/system/network/network_list_view_base.h
+++ b/ash/system/network/network_list_view_base.h
@@ -14,12 +14,14 @@
 }
 
 namespace ash {
+namespace tray {
+class NetworkStateListDetailedView;
+}
 
 // Base class for a list of available networks (and, in the case of VPNs, the
 // list of available VPN providers).
 class NetworkListViewBase {
  public:
-  NetworkListViewBase();
   virtual ~NetworkListViewBase();
 
   void set_container(views::View* container) { container_ = container; }
@@ -33,9 +35,18 @@
   virtual bool IsNetworkEntry(views::View* view, std::string* guid) const = 0;
 
  protected:
-  views::View* container() { return container_; }
+  explicit NetworkListViewBase(
+      tray::NetworkStateListDetailedView* detailed_view);
+
+  tray::NetworkStateListDetailedView* detailed_view() const {
+    return detailed_view_;
+  }
+
+  views::View* container() const { return container_; }
 
  private:
+  tray::NetworkStateListDetailedView* const detailed_view_;
+
   // The container that holds the actual list entries.
   views::View* container_ = nullptr;
 
diff --git a/ash/system/network/network_state_list_detailed_view.cc b/ash/system/network/network_state_list_detailed_view.cc
index 9a01efe..7c9c1cd5 100644
--- a/ash/system/network/network_state_list_detailed_view.cc
+++ b/ash/system/network/network_state_list_detailed_view.cc
@@ -17,19 +17,13 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/network/network_icon.h"
 #include "ash/system/network/network_icon_animation.h"
-#include "ash/system/network/network_info.h"
 #include "ash/system/network/network_list.h"
 #include "ash/system/network/network_list_view_base.h"
 #include "ash/system/network/tray_network_state_observer.h"
 #include "ash/system/network/vpn_list_view.h"
-#include "ash/system/networking_config_delegate.h"
-#include "ash/system/tray/fixed_sized_image_view.h"
-#include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/system_menu_button.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_controller.h"
-#include "ash/system/tray/system_tray_delegate.h"
-#include "ash/system/tray/throbber_view.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_details_view.h"
 #include "ash/system/tray/tray_popup_header_button.h"
@@ -79,30 +73,6 @@
 // Delay between scan requests.
 const int kRequestScanDelaySeconds = 10;
 
-// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc.
-void SetupConnectedItem(HoverHighlightView* container,
-                        const base::string16& text,
-                        const gfx::ImageSkia& image) {
-  container->AddIconAndLabels(
-      image, text,
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED));
-  TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION);
-  style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED);
-  style.SetupLabel(container->sub_text_label());
-}
-
-// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc.
-void SetupConnectingItem(HoverHighlightView* container,
-                         const base::string16& text,
-                         const gfx::ImageSkia& image) {
-  container->AddIconAndLabels(
-      image, text,
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING));
-  ThrobberView* throbber = new ThrobberView;
-  throbber->Start();
-  container->AddRightView(throbber);
-}
-
 }  // namespace
 
 //------------------------------------------------------------------------------
@@ -445,32 +415,6 @@
   return label;
 }
 
-views::View* NetworkStateListDetailedView::CreateControlledByExtensionView(
-    const NetworkInfo& info) {
-  NetworkingConfigDelegate* networking_config_delegate =
-      Shell::Get()->system_tray_delegate()->GetNetworkingConfigDelegate();
-  if (!networking_config_delegate)
-    return nullptr;
-  std::unique_ptr<const NetworkingConfigDelegate::ExtensionInfo>
-      extension_info =
-          networking_config_delegate->LookUpExtensionForNetwork(info.guid);
-  if (!extension_info)
-    return nullptr;
-
-  // Get the tooltip text.
-  base::string16 tooltip_text = l10n_util::GetStringFUTF16(
-      IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI,
-      base::UTF8ToUTF16(extension_info->extension_name));
-
-  views::ImageView* controlled_icon =
-      new FixedSizedImageView(kTrayPopupDetailsIconWidth, 0);
-
-  controlled_icon->SetImage(
-      gfx::CreateVectorIcon(kCaptivePortalIcon, kMenuIconColor));
-  controlled_icon->SetTooltipText(tooltip_text);
-  return controlled_icon;
-}
-
 void NetworkStateListDetailedView::CallRequestScan() {
   VLOG(1) << "Requesting Network Scan.";
   NetworkHandler::Get()->network_state_handler()->RequestScan();
@@ -481,64 +425,10 @@
       base::TimeDelta::FromSeconds(kRequestScanDelaySeconds));
 }
 
-views::View* NetworkStateListDetailedView::CreateViewForNetwork(
-    const NetworkInfo& info) {
-  HoverHighlightView* container = new HoverHighlightView(this);
-  if (info.connected)
-    SetupConnectedItem(container, info.label, info.image);
-  else if (info.connecting)
-    SetupConnectingItem(container, info.label, info.image);
-  else
-    container->AddIconAndLabel(info.image, info.label);
-  container->SetTooltipText(info.tooltip);
-  views::View* controlled_icon = CreateControlledByExtensionView(info);
-  if (controlled_icon)
-    container->AddChildView(controlled_icon);
-  return container;
-}
-
-NetworkTypePattern NetworkStateListDetailedView::GetNetworkTypePattern() const {
-  return list_type_ == LIST_TYPE_VPN ? NetworkTypePattern::VPN()
-                                     : NetworkTypePattern::NonVirtual();
-}
-
-void NetworkStateListDetailedView::UpdateViewForNetwork(
-    views::View* view,
-    const NetworkInfo& info) {
-  HoverHighlightView* container = static_cast<HoverHighlightView*>(view);
-  DCHECK(!container->has_children());
-  if (info.connected)
-    SetupConnectedItem(container, info.label, info.image);
-  else if (info.connecting)
-    SetupConnectingItem(container, info.label, info.image);
-  else
-    container->AddIconAndLabel(info.image, info.label);
-  views::View* controlled_icon = CreateControlledByExtensionView(info);
-  container->SetTooltipText(info.tooltip);
-  if (controlled_icon)
-    view->AddChildView(controlled_icon);
-}
-
-views::Label* NetworkStateListDetailedView::CreateInfoLabel() {
-  views::Label* label = new views::Label();
-  label->SetBorder(views::CreateEmptyBorder(kTrayPopupPaddingBetweenItems,
-                                            kTrayPopupPaddingHorizontal,
-                                            kTrayPopupPaddingBetweenItems, 0));
-  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0));
-  return label;
-}
-
 void NetworkStateListDetailedView::OnNetworkEntryClicked(views::View* sender) {
   HandleViewClicked(sender);
 }
 
-void NetworkStateListDetailedView::OnOtherWifiClicked() {
-  ShellPort::Get()->RecordUserMetricsAction(
-      UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED);
-  Shell::Get()->system_tray_controller()->ShowNetworkCreate(shill::kTypeWifi);
-}
-
 void NetworkStateListDetailedView::RelayoutScrollList() {
   scroller()->Layout();
 }
diff --git a/ash/system/network/network_state_list_detailed_view.h b/ash/system/network/network_state_list_detailed_view.h
index 50d87dc..50e0b41 100644
--- a/ash/system/network/network_state_list_detailed_view.h
+++ b/ash/system/network/network_state_list_detailed_view.h
@@ -9,7 +9,6 @@
 #include <string>
 
 #include "ash/login_status.h"
-#include "ash/system/network/network_list_delegate.h"
 #include "ash/system/tray/tray_details_view.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -17,10 +16,6 @@
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/custom_button.h"
 
-namespace chromeos {
-class NetworkTypePattern;
-}
-
 namespace ash {
 class NetworkListViewBase;
 }
@@ -36,7 +31,6 @@
 
 class NetworkStateListDetailedView
     : public TrayDetailsView,
-      public NetworkListDelegate,
       public base::SupportsWeakPtr<NetworkStateListDetailedView> {
  public:
   enum ListType { LIST_TYPE_NETWORK, LIST_TYPE_VPN };
@@ -52,6 +46,11 @@
   // Manager properties (e.g. technology state) have changed.
   void Update();
 
+  // Called when the user clicks on an entry representing a network in the list.
+  void OnNetworkEntryClicked(views::View* sender);
+
+  void RelayoutScrollList();
+
  private:
   class InfoBubble;
 
@@ -74,24 +73,9 @@
   void OnInfoBubbleDestroyed();
   views::View* CreateNetworkInfoView();
 
-  // Creates the view of an extra icon appearing next to the network name
-  // indicating that the network is controlled by an extension. If no extension
-  // is registered for this network, returns |nullptr|.
-  views::View* CreateControlledByExtensionView(const NetworkInfo& info);
-
   // Periodically request a network scan.
   void CallRequestScan();
 
-  // NetworkListDelegate:
-  views::View* CreateViewForNetwork(const NetworkInfo& info) override;
-  chromeos::NetworkTypePattern GetNetworkTypePattern() const override;
-  void UpdateViewForNetwork(views::View* view,
-                            const NetworkInfo& info) override;
-  views::Label* CreateInfoLabel() override;
-  void OnNetworkEntryClicked(views::View* sender) override;
-  void OnOtherWifiClicked() override;
-  void RelayoutScrollList() override;
-
   // Type of list (all networks or vpn)
   ListType list_type_;
 
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index e4c9df9..e55d64b0 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -16,7 +16,7 @@
 #include "ash/system/network/network_icon.h"
 #include "ash/system/network/network_icon_animation.h"
 #include "ash/system/network/network_icon_animation_observer.h"
-#include "ash/system/network/network_list_delegate.h"
+#include "ash/system/network/network_state_list_detailed_view.h"
 #include "ash/system/network/vpn_list.h"
 #include "ash/system/tray/hover_highlight_view.h"
 #include "ash/system/tray/system_menu_button.h"
@@ -220,7 +220,8 @@
   Layout();
 }
 
-// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc.
+// TODO(varkha|mohsen): Consolidate with a similar method in
+// BluetoothDetailedView. See https://crbug.com/686924.
 void VPNListNetworkEntry::SetupConnectedItem(const base::string16& text,
                                              const gfx::ImageSkia& image) {
   AddIconAndLabels(
@@ -231,7 +232,8 @@
   style.SetupLabel(sub_text_label());
 }
 
-// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc.
+// TODO(varkha|mohsen): Consolidate with a similar method in
+// BluetoothDetailedView. See https://crbug.com/686924.
 void VPNListNetworkEntry::SetupConnectingItem(const base::string16& text,
                                               const gfx::ImageSkia& image) {
   AddIconAndLabels(
@@ -244,7 +246,8 @@
 
 }  // namespace
 
-VPNListView::VPNListView(NetworkListDelegate* delegate) : delegate_(delegate) {
+VPNListView::VPNListView(tray::NetworkStateListDetailedView* detailed_view)
+    : NetworkListViewBase(detailed_view) {
   Shell::Get()->vpn_list()->AddObserver(this);
 }
 
@@ -314,7 +317,7 @@
 
   // Layout the updated list.
   container()->SizeToPreferredSize();
-  delegate_->RelayoutScrollList();
+  detailed_view()->RelayoutScrollList();
 
   if (scroll_to_show_view) {
     // Scroll the list so that |scroll_to_show_view| is in view.
@@ -357,7 +360,7 @@
   // If the user clicked on a network entry, let the |delegate_| trigger a
   // connection attempt (if the network is currently disconnected) or show a
   // configuration dialog (if the network is currently connected or connecting).
-  delegate_->OnNetworkEntryClicked(sender);
+  detailed_view()->OnNetworkEntryClicked(sender);
 }
 
 void VPNListView::AddNetwork(const chromeos::NetworkState* network) {
diff --git a/ash/system/network/vpn_list_view.h b/ash/system/network/vpn_list_view.h
index 2f59d00..23c0009 100644
--- a/ash/system/network/vpn_list_view.h
+++ b/ash/system/network/vpn_list_view.h
@@ -18,15 +18,14 @@
 class NetworkState;
 }
 
-namespace ash {
-class NetworkListDelegate;
-}
-
 namespace views {
 class View;
 }
 
 namespace ash {
+namespace tray {
+class NetworkStateListDetailedView;
+}
 
 // A list of VPN providers and networks that shows VPN providers and networks in
 // a hierarchical layout, allowing the user to see at a glance which provider a
@@ -45,7 +44,7 @@
                     public VpnList::Observer,
                     public ViewClickListener {
  public:
-  explicit VPNListView(NetworkListDelegate* delegate);
+  explicit VPNListView(tray::NetworkStateListDetailedView* detailed_view);
   ~VPNListView() override;
 
   // NetworkListViewBase:
@@ -72,8 +71,6 @@
   void AddProvidersAndNetworks(
       const chromeos::NetworkStateHandler::NetworkStateList& networks);
 
-  NetworkListDelegate* const delegate_;
-
   // A mapping from each VPN provider's list entry to the provider.
   std::map<const views::View* const, VPNProvider> provider_view_map_;
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 41c56ba..333dbe0 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2382,6 +2382,10 @@
      flag_descriptions::kBackgroundVideoTrackOptimizationName,
      flag_descriptions::kBackgroundVideoTrackOptimizationDescription, kOsAll,
      FEATURE_VALUE_TYPE(media::kBackgroundVideoTrackOptimization)},
+    {"enable-new-remote-playback-pipeline",
+     flag_descriptions::kNewRemotePlaybackPipelineName,
+     flag_descriptions::kNewRemotePlaybackPipelineDescription, kOsAll,
+     FEATURE_VALUE_TYPE(media::kNewRemotePlaybackPipeline)},
 #if defined(OS_CHROMEOS)
     {"quick-unlock-pin", flag_descriptions::kQuickUnlockPin,
      flag_descriptions::kQuickUnlockPinDescription, kOsCrOS,
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index f9b4e53..c070dfe3 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -318,7 +319,7 @@
       item->GetUserData(&kSafeBrowsingUserDataKey));
   if (!state) {
     state = new SafeBrowsingState();
-    item->SetUserData(&kSafeBrowsingUserDataKey, state);
+    item->SetUserData(&kSafeBrowsingUserDataKey, base::WrapUnique(state));
   }
   state->CompleteDownload();
 #endif
@@ -339,7 +340,7 @@
                << item->DebugString(false);
       state = new SafeBrowsingState();
       state->set_callback(internal_complete_callback);
-      item->SetUserData(&kSafeBrowsingUserDataKey, state);
+      item->SetUserData(&kSafeBrowsingUserDataKey, base::WrapUnique(state));
       service->CheckClientDownload(
           item,
           base::Bind(&ChromeDownloadManagerDelegate::CheckClientDownloadDone,
diff --git a/chrome/browser/download/download_danger_prompt_browsertest.cc b/chrome/browser/download/download_danger_prompt_browsertest.cc
index ae710e8..82eab21 100644
--- a/chrome/browser/download/download_danger_prompt_browsertest.cc
+++ b/chrome/browser/download/download_danger_prompt_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/download/download_danger_prompt.h"
 #include "chrome/browser/profiles/profile.h"
@@ -156,10 +157,10 @@
     EXPECT_CALL(download_, GetFileNameToReportUser()).WillRepeatedly(Return(
         base::FilePath(FILE_PATH_LITERAL("evil.exe"))));
     EXPECT_CALL(download_, GetDangerType()).WillRepeatedly(Return(danger_type));
-    DownloadProtectionService::DownloadPingToken* token_obj =
-        new DownloadProtectionService::DownloadPingToken(token);
+    auto token_obj =
+        base::MakeUnique<DownloadProtectionService::DownloadPingToken>(token);
     download_.SetUserData(DownloadProtectionService::kDownloadPingTokenKey,
-                          token_obj);
+                          std::move(token_obj));
   }
 
   void SetUpSafeBrowsingReportExpectations(
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc
index 2d73992..ec81704 100644
--- a/chrome/browser/download/download_history.cc
+++ b/chrome/browser/download/download_history.cc
@@ -31,6 +31,7 @@
 #include <utility>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "components/history/content/browser/download_conversions.h"
@@ -77,7 +78,7 @@
   explicit DownloadHistoryData(content::DownloadItem* item)
       : state_(NOT_PERSISTED),
         was_restored_from_history_(false) {
-    item->SetUserData(kKey, this);
+    item->SetUserData(kKey, base::WrapUnique(this));
   }
 
   ~DownloadHistoryData() override {}
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index fc968b64..503527a5 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -6,6 +6,7 @@
 
 #include "base/i18n/number_formatting.h"
 #include "base/i18n/rtl.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
@@ -44,6 +45,8 @@
 // DownloadItem, and the lifetime of the model is shorter than the DownloadItem.
 class DownloadItemModelData : public base::SupportsUserData::Data {
  public:
+  ~DownloadItemModelData() override {}
+
   // Get the DownloadItemModelData object for |download|. Returns NULL if
   // there's no model data.
   static const DownloadItemModelData* Get(const DownloadItem* download);
@@ -72,7 +75,6 @@
 
  private:
   DownloadItemModelData();
-  ~DownloadItemModelData() override {}
 
   static const char kKey[];
 };
@@ -94,7 +96,7 @@
   if (data == NULL) {
     data = new DownloadItemModelData();
     data->should_show_in_shelf_ = !download->IsTransient();
-    download->SetUserData(kKey, data);
+    download->SetUserData(kKey, base::WrapUnique(data));
   }
   return data;
 }
diff --git a/chrome/browser/download/download_path_reservation_tracker.cc b/chrome/browser/download/download_path_reservation_tracker.cc
index 2c74a39..c3373d5 100644
--- a/chrome/browser/download/download_path_reservation_tracker.cc
+++ b/chrome/browser/download/download_path_reservation_tracker.cc
@@ -15,6 +15,7 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -62,10 +63,9 @@
                              public base::SupportsUserData::Data {
  public:
   explicit DownloadItemObserver(DownloadItem* download_item);
-
- private:
   ~DownloadItemObserver() override;
 
+ private:
   // DownloadItem::Observer
   void OnDownloadUpdated(DownloadItem* download) override;
   void OnDownloadDestroyed(DownloadItem* download) override;
@@ -338,7 +338,7 @@
       last_target_path_(download_item->GetTargetFilePath()) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   download_item_->AddObserver(this);
-  download_item_->SetUserData(&kUserDataKey, this);
+  download_item_->SetUserData(&kUserDataKey, base::WrapUnique(this));
 }
 
 DownloadItemObserver::~DownloadItemObserver() {
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index f6e285e..eaf1a52b 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -39,7 +39,7 @@
   }
 
   explicit WasInProgressData(content::DownloadItem* item) {
-    item->SetUserData(kKey, this);
+    item->SetUserData(kKey, base::WrapUnique(this));
   }
 
  private:
diff --git a/chrome/browser/download/download_status_updater_mac.mm b/chrome/browser/download/download_status_updater_mac.mm
index 574553b6..ad8a30ec 100644
--- a/chrome/browser/download/download_status_updater_mac.mm
+++ b/chrome/browser/download/download_status_updater_mac.mm
@@ -7,6 +7,7 @@
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/mac/sdk_forward_declarations.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/supports_user_data.h"
 #import "chrome/browser/ui/cocoa/dock_icon.h"
@@ -161,8 +162,9 @@
 
   [progress publish];
 
-  download->SetUserData(&kCrNSProgressUserDataKey,
-                        new CrNSProgressUserData(progress, destination_path));
+  download->SetUserData(
+      &kCrNSProgressUserDataKey,
+      base::MakeUnique<CrNSProgressUserData>(progress, destination_path));
 }
 
 void UpdateNSProgress(content::DownloadItem* download,
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 458b7189..08346501 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2574,6 +2574,15 @@
     "Disable video tracks when the video is played in the background to "
     "optimize performance.";
 
+//  New remote playback pipeline experiment strings.
+
+const char kNewRemotePlaybackPipelineName[] =
+    "Enable the new remote playback pipeline.";
+
+const char kNewRemotePlaybackPipelineDescription[] =
+    "Enable the new pipeline for playing media element remotely via "
+    "RemotePlayback API or native controls.";
+
 //  Video fullscreen with orientation lock experiment strings.
 
 const char kVideoFullscreenOrientationLockName[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 8cc1b352..5671d48 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2797,6 +2797,14 @@
 // Description of the flag for enabling optimizing background video playback.
 extern const char kBackgroundVideoTrackOptimizationDescription[];
 
+//  New remote playback pipeline experiment strings.
+
+// Name of the flag for enabling the new remote playback pipeline.
+extern const char kNewRemotePlaybackPipelineName[];
+
+// Description of the flag for enabling the new remote playback pipeline.
+extern const char kNewRemotePlaybackPipelineDescription[];
+
 //  Video fullscreen with orientation lock experiment strings.
 
 // Name of the flag for enabling orientation lock for fullscreen video playback.
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 6a17b32..3ee151f 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -15,6 +15,7 @@
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/debug/crash_logging.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/i18n/rtl.h"
 #include "base/json/json_writer.h"
@@ -1083,6 +1084,8 @@
   settings->SetHideDownloadUI(prefs.hide_download_ui);
   WebRuntimeFeatures::EnableBackgroundVideoTrackOptimization(
       prefs.background_video_track_optimization_enabled);
+  WebRuntimeFeatures::EnableNewRemotePlaybackPipeline(
+      base::FeatureList::IsEnabled(media::kNewRemotePlaybackPipeline));
 
   settings->SetPresentationReceiver(prefs.presentation_receiver);
 
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index ad3fb89..6911c91 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -196,6 +196,10 @@
 const base::Feature kMemoryPressureBasedSourceBufferGC{
     "MemoryPressureBasedSourceBufferGC", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Use the new Remote Playback / media flinging pipeline.
+const base::Feature kNewRemotePlaybackPipeline{
+    "NewRemotePlaybackPipeline", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Use shared block-based buffering for media.
 const base::Feature kUseNewMediaCache{"use-new-media-cache",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index edf1dc88..f84fe52 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -105,6 +105,7 @@
 MEDIA_EXPORT extern const base::Feature kBackgroundVideoTrackOptimization;
 MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization;
 MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC;
+MEDIA_EXPORT extern const base::Feature kNewRemotePlaybackPipeline;
 
 #if defined(OS_ANDROID)
 MEDIA_EXPORT extern const base::Feature kAndroidMediaPlayerRenderer;
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index cd40248..056da05 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -17066,10 +17066,10 @@
 crbug.com/591099 media/color-profile-video-seek.html [ Failure ]
 crbug.com/591099 media/color-profile-video-seek-object-fit.html [ Failure ]
 crbug.com/591099 media/constructors.html [ Crash ]
-crbug.com/591099 media/controls-cast-button.html [ Crash ]
-crbug.com/591099 media/controls-cast-button-narrow.html [ Crash ]
-crbug.com/591099 media/controls-cast-do-not-fade-out.html [ Crash ]
-crbug.com/591099 media/controls-cast-overlay-slow-fade.html [ Crash ]
+crbug.com/591099 media/controls/controls-cast-button.html [ Crash ]
+crbug.com/591099 media/controls/controls-cast-button-narrow.html [ Crash ]
+crbug.com/591099 media/controls/controls-cast-do-not-fade-out.html [ Crash ]
+crbug.com/591099 media/controls/controls-cast-overlay-slow-fade.html [ Crash ]
 crbug.com/591099 media/controls/closed-captions-dynamic-update.html [ Crash ]
 crbug.com/591099 media/controls/closed-captions-on-off.html [ Crash ]
 crbug.com/591099 media/controls/closed-captions-single-track.html [ Crash ]
@@ -17078,7 +17078,7 @@
 crbug.com/591099 media/controls/download-button-displays-with-preload-none.html [ Crash ]
 crbug.com/591099 media/controls-drag-timebar.html [ Crash ]
 crbug.com/591099 media/controls/overflow-fully-hidden.html [ Crash ]
-crbug.com/591099 media/controls-overlay-cast-button.html [ Crash ]
+crbug.com/591099 media/controls/controls-overlay-cast-button.html [ Crash ]
 crbug.com/591099 media/controls/overlay-play-button-document-move.html [ Crash ]
 crbug.com/591099 media/controls/overlay-play-button-narrow.html [ Crash ]
 crbug.com/591099 media/controls-right-click-on-timebar.html [ Crash ]
@@ -17249,15 +17249,15 @@
 crbug.com/591099 media/video-controls-overflow-menu-closed-captions-button.html [ Crash ]
 crbug.com/591099 media/video-controls-overflow-menu-closed-captions-list-hide-on-click-outside.html [ Crash ]
 crbug.com/591099 media/video-controls-overflow-menu-fullscreen-button.html [ Timeout ]
-crbug.com/591099 media/video-controls-overflow-menu-hide-on-click.html [ Crash ]
-crbug.com/591099 media/video-controls-overflow-menu-hide-on-click-outside.html [ Crash ]
-crbug.com/591099 media/video-controls-overflow-menu-hide-on-click-panel.html [ Crash ]
-crbug.com/591099 media/video-controls-overflow-menu-hide-on-resize.html [ Crash ]
+crbug.com/591099 media/controls/video-controls-overflow-menu-hide-on-click.html [ Crash ]
+crbug.com/591099 media/controls/video-controls-overflow-menu-hide-on-click-outside.html [ Crash ]
+crbug.com/591099 media/controls/video-controls-overflow-menu-hide-on-click-panel.html [ Crash ]
+crbug.com/591099 media/controls/video-controls-overflow-menu-hide-on-resize.html [ Crash ]
 crbug.com/591099 media/video-controls-overflow-menu-last-button-visible.html [ Crash ]
 crbug.com/591099 media/video-controls-overflow-menu-mute-button.html [ Crash ]
 crbug.com/591099 media/video-controls-overflow-menu-play-button.html [ Crash ]
-crbug.com/591099 media/video-controls-overflow-menu-text.html [ Crash ]
-crbug.com/591099 media/video-controls-overflow-menu-visibility.html [ Crash ]
+crbug.com/591099 media/controls/video-controls-overflow-menu-text.html [ Crash ]
+crbug.com/591099 media/controls/video-controls-overflow-menu-visibility.html [ Crash ]
 crbug.com/591099 media/video-controls-show-on-focus.html [ Crash ]
 crbug.com/591099 media/video-controls-start-selection.html [ Failure ]
 crbug.com/591099 media/video-controls-toggling.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index ddf3f1a2..7c3f168 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -65,7 +65,8 @@
 crbug.com/24182 jquery/traversing.html [ Slow ]
 crbug.com/24182 media/track/track-cues-cuechange.html [ Slow ]
 crbug.com/24182 media/track/track-cues-enter-exit.html [ Slow ]
-crbug.com/24182 media/controls-cast-do-not-fade-out.html [ Slow ]
+crbug.com/24182 media/controls/controls-cast-do-not-fade-out.html [ Slow ]
+crbug.com/24182 virtual/new-remote-playback-pipeline/media/controls/controls-cast-do-not-fade-out.html [ Slow ]
 crbug.com/24182 svg/filters/big-sized-filter.svg [ Slow ]
 crbug.com/24182 tables/mozilla/other/slashlogo.html [ Slow ]
 crbug.com/24182 virtual/gpu/fast/canvas/canvas-blend-image.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 84d27c30..64e2678 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2273,7 +2273,6 @@
 crbug.com/487344 media/media-controls-clone.html [ Failure ]
 crbug.com/487344 media/media-document-audio-repaint.html [ Failure ]
 crbug.com/487344 media/video-controls-rendering.html [ Failure ]
-crbug.com/487344 media/video-controls-with-cast-rendering.html [ Failure ]
 crbug.com/487344 media/video-display-toggle.html [ Failure ]
 crbug.com/487344 media/video-empty-source.html [ Failure ]
 crbug.com/487344 media/video-no-audio.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 52c8cc84..c87aff3b 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -522,5 +522,15 @@
     "prefix": "experimental-canvas-features",
     "base": "fast/canvas-experimental",
     "args": ["--enable-experimental-canvas-features"]
+  },
+  {
+    "prefix": "new-remote-playback-pipeline",
+    "base": "media/remoteplayback",
+    "args": ["--enable-features=NewRemotePlaybackPipeline"]
+  },
+  {
+    "prefix": "new-remote-playback-pipeline",
+    "base": "media/controls",
+    "args": ["--enable-features=NewRemotePlaybackPipeline"]
   }
 ]
diff --git a/third_party/WebKit/LayoutTests/media/controls-cast-button-narrow.html b/third_party/WebKit/LayoutTests/media/controls/controls-cast-button-narrow.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/media/controls-cast-button-narrow.html
rename to third_party/WebKit/LayoutTests/media/controls/controls-cast-button-narrow.html
index a496748..34cd5310 100644
--- a/third_party/WebKit/LayoutTests/media/controls-cast-button-narrow.html
+++ b/third_party/WebKit/LayoutTests/media/controls/controls-cast-button-narrow.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <title>media controls cast button</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-file.js"></script>
-<script src="media-controls.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-file.js"></script>
+<script src="../media-controls.js"></script>
 <video width="100" height="200" controls></video>
 <script>
 async_test(function(t) {
     var video = document.querySelector("video");
-    video.src = findMediaFile("video", "content/test");
+    video.src = findMediaFile("video", "../content/test");
 
     video.onloadedmetadata = t.step_func(function() {
         // Pretend we have a cast device
diff --git a/third_party/WebKit/LayoutTests/media/controls-cast-button.html b/third_party/WebKit/LayoutTests/media/controls/controls-cast-button.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/media/controls-cast-button.html
rename to third_party/WebKit/LayoutTests/media/controls/controls-cast-button.html
index 87814c66..e3c8a1c 100644
--- a/third_party/WebKit/LayoutTests/media/controls-cast-button.html
+++ b/third_party/WebKit/LayoutTests/media/controls/controls-cast-button.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <title>media controls cast button</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-file.js"></script>
-<script src="media-controls.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-file.js"></script>
+<script src="../media-controls.js"></script>
 <video controls width="500"></video>
 <script>
 async_test(function(t) {
     var video = document.querySelector("video");
-    video.src = findMediaFile("video", "content/test");
+    video.src = findMediaFile("video", "../content/test");
 
     video.onloadedmetadata = t.step_func_done(function() {
         // Should not have a cast button by default
diff --git a/third_party/WebKit/LayoutTests/media/controls-cast-do-not-fade-out.html b/third_party/WebKit/LayoutTests/media/controls/controls-cast-do-not-fade-out.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/media/controls-cast-do-not-fade-out.html
rename to third_party/WebKit/LayoutTests/media/controls/controls-cast-do-not-fade-out.html
index 6d608be..ffdcd72 100644
--- a/third_party/WebKit/LayoutTests/media/controls-cast-do-not-fade-out.html
+++ b/third_party/WebKit/LayoutTests/media/controls/controls-cast-do-not-fade-out.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <title>This tests that controls do not fade out when the video is playing remotely.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-file.js"></script>
-<script src="media-controls.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-file.js"></script>
+<script src="../media-controls.js"></script>
 <video controls loop></video>
 <script>
 async_test(function(t) {
     var video = document.querySelector("video");
-    video.src = findMediaFile("video", "content/test");
+    video.src = findMediaFile("video", "../content/test");
 
     video.onplaying = t.step_func(function() {
         internals.mediaPlayerPlayingRemotelyChanged(video, true);
diff --git a/third_party/WebKit/LayoutTests/media/controls-cast-overlay-slow-fade.html b/third_party/WebKit/LayoutTests/media/controls/controls-cast-overlay-slow-fade.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/media/controls-cast-overlay-slow-fade.html
rename to third_party/WebKit/LayoutTests/media/controls/controls-cast-overlay-slow-fade.html
index 2e24c469..f00d299 100644
--- a/third_party/WebKit/LayoutTests/media/controls-cast-overlay-slow-fade.html
+++ b/third_party/WebKit/LayoutTests/media/controls/controls-cast-overlay-slow-fade.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <title>Test that the overlay cast button fades at the right time (neither too soon nor too late).</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-file.js"></script>
-<script src="media-controls.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-file.js"></script>
+<script src="../media-controls.js"></script>
 <video loop></video>
 <script>
 async_test(function(t) {
@@ -11,16 +11,16 @@
     // and no more than that plus the fadeout time. Allow 500ms margin at either side.
     var hideTimeoutLowerBound = controlsMouseMovementTimeoutMs - 500;
     var hideTimeoutUpperBound = controlsMouseMovementTimeoutMs + controlsFadeOutDurationMs + 500;
-    
+
     var video = document.querySelector("video");
-    video.src = findMediaFile("video", "content/test");
-    
+    video.src = findMediaFile("video", "../content/test");
+
     video.onplaying = t.step_func(function() {
         setTimeout(t.step_func(function() {
             // Cast button should be visible
             assert_true(isCastButtonVisible(), "button should exist");
         }), hideTimeoutLowerBound);
-        
+
         setTimeout(t.step_func_done(function() {
             // Cast button should be gone
             assert_false(isCastButtonVisible(), "button should not exist");
diff --git a/third_party/WebKit/LayoutTests/media/controls-overlay-cast-button.html b/third_party/WebKit/LayoutTests/media/controls/controls-overlay-cast-button.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/media/controls-overlay-cast-button.html
rename to third_party/WebKit/LayoutTests/media/controls/controls-overlay-cast-button.html
index 6847192..ca96085 100644
--- a/third_party/WebKit/LayoutTests/media/controls-overlay-cast-button.html
+++ b/third_party/WebKit/LayoutTests/media/controls/controls-overlay-cast-button.html
@@ -1,14 +1,14 @@
 <!DOCTYPE html>
 <title>media controls cast button</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-file.js"></script>
-<script src="media-controls.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-file.js"></script>
+<script src="../media-controls.js"></script>
 <video></video>
 <script>
 async_test(function(t) {
     var video = document.querySelector("video");
-    video.src = findMediaFile("video", "content/test");
+    video.src = findMediaFile("video", "../content/test");
 
     video.onloadedmetadata = t.step_func_done(function() {
         // Should not have a cast button by default
diff --git a/third_party/WebKit/LayoutTests/media/controls/overflow-fully-hidden.html b/third_party/WebKit/LayoutTests/media/controls/overflow-fully-hidden.html
index e7a2e965..454a7bd 100644
--- a/third_party/WebKit/LayoutTests/media/controls/overflow-fully-hidden.html
+++ b/third_party/WebKit/LayoutTests/media/controls/overflow-fully-hidden.html
@@ -27,7 +27,7 @@
 test(_ => {
   var videos = document.querySelectorAll('video');
   for (var video, i = 0; video = videos[i]; ++i) {
-    video.src = findMediaFile('video', 'content/test');
+    video.src = findMediaFile('video', '../content/test');
   }
 
   var forceLayout = document.body.offsetHeight;
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-appears-when-expected.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-appears-when-expected.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-appears-when-expected.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-appears-when-expected.html
index c7cc650..23bae03 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-appears-when-expected.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-appears-when-expected.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <title>Overflow menu appears at the right time.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -13,7 +13,7 @@
 async_test(function(t) {
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   // At this width, the mute and cast button don't fit. Since we have
   // two elements that don't fit, the overflow menu should be visible.
   video.setAttribute("width", "240");
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click-outside.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click-outside.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click-outside.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click-outside.html
index 24d5cbb..9e4c3c5 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click-outside.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click-outside.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <title>Ensure overflow menu buttons are visible when expected.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -13,7 +13,7 @@
 async_test(function(t) {
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   video.setAttribute("width", "60");
   // Add captions
   var track = video.addTextTrack("captions");
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click-panel.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click-panel.html
similarity index 80%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click-panel.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click-panel.html
index 241962a..c0f83b12 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click-panel.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click-panel.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <title>Ensure overflow menu buttons are visible when expected.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -13,7 +13,7 @@
 async_test(function(t) {
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   video.setAttribute("width", "200");
   // Add captions
   var track = video.addTextTrack("captions");
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click.html
index a1e7dd6..d6e5a1d 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-click.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-click.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <title>Ensure overflow menu buttons are visible when expected.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -13,7 +13,7 @@
 async_test(function(t) {
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   video.setAttribute("width", "60");
   // Add captions
   var track = video.addTextTrack("captions");
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-resize.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-resize.html
similarity index 81%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-resize.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-resize.html
index e3c6b13..f892a7e 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-hide-on-resize.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-hide-on-resize.html
@@ -6,11 +6,11 @@
     height: 1000px;
   }
 </style>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -22,7 +22,7 @@
 
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   video.setAttribute("width", "60");
   // Add captions
   var track = video.addTextTrack("captions");
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-text.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-text.html
similarity index 75%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-text.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-text.html
index 9ea0cd2..e6297088 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-text.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-text.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <title>Overflow menu displays the correct text.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -13,7 +13,7 @@
 async_test(function(t) {
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   // Add captions
   var track = video.addTextTrack("captions");
   // Pretend we have a cast device
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-visibility.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-visibility.html
similarity index 82%
rename from third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-visibility.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-visibility.html
index 0c19c30..09326a9 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-overflow-menu-visibility.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-overflow-menu-visibility.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <title>Ensure overflow menu buttons are visible when expected.</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="media-controls.js"></script>
-<script src="media-file.js"></script>
-<script src="overflow-menu.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<script src="../media-file.js"></script>
+<script src="../overflow-menu.js"></script>
 
 <!--Padding ensures the overflow menu is visible for the tests. -->
 <body style="padding-top: 200px; padding-left: 100px">
@@ -13,7 +13,7 @@
 async_test(function(t) {
   // Set up video
   var video = document.querySelector("video");
-  video.src = findMediaFile("video", "content/test");
+  video.src = findMediaFile("video", "../content/test");
   video.setAttribute("width", "60");
   // Add captions
   var track = video.addTextTrack("captions");
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-with-cast-rendering.html b/third_party/WebKit/LayoutTests/media/controls/video-controls-with-cast-rendering.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/media/video-controls-with-cast-rendering.html
rename to third_party/WebKit/LayoutTests/media/controls/video-controls-with-cast-rendering.html
index bbce17ba..42233d4 100644
--- a/third_party/WebKit/LayoutTests/media/video-controls-with-cast-rendering.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-controls-with-cast-rendering.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <script src="media-file.js"></script>
-  <script src="video-paint-test.js"></script>
+  <script src="../media-file.js"></script>
+  <script src="../video-paint-test.js"></script>
 </head>
 <body>
   <p>Test controls rendering with cast button.</p>
@@ -18,7 +18,7 @@
   <script>
     if (window.internals)
         window.internals.settings.setMockScrollbarsEnabled(true);
-        
+
     var videos = document.getElementsByTagName('video');
     waitForMultipleEvents("canplaythrough", videos.length, function() {
         for (var i = 0; i < videos.length; ++i) {
@@ -35,7 +35,7 @@
                 testRunner.notifyDone();
         });
     });
-    setSrcByTagName('video', findMediaFile('video', 'content/test'));
+    setSrcByTagName('video', findMediaFile('video', '../content/test'));
   </script>
 </body>
 </html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-overlay-cast-covering.html b/third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-covering.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/media/video-overlay-cast-covering.html
rename to third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-covering.html
index ddfa8bb..2031db59 100644
--- a/third_party/WebKit/LayoutTests/media/video-overlay-cast-covering.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-covering.html
@@ -2,9 +2,9 @@
 <html>
     <head>
         <title>Hiding the cast overlay button</title>
-        <script src="media-controls.js"></script>
-        <script src="../resources/testharness.js"></script>
-        <script src="../resources/testharnessreport.js"></script>
+        <script src="../media-controls.js"></script>
+        <script src="../../resources/testharness.js"></script>
+        <script src="../../resources/testharnessreport.js"></script>
         <style>
         body { background-color: gray; }
         .video-group { position: absolute; }
@@ -17,12 +17,12 @@
     </head>
     <body onload="async_test(testOverlayVisibility)">
         <div id="v1" class="video-group">
-            <video src="resources/test-positive-start-time.webm"
+            <video src="../resources/test-positive-start-time.webm"
                    class="should-not-have-overlay-btn"></video>
             <div class="overlay"></div>
         </div>
         <div id="v2" class="video-group">
-            <video src="resources/test-positive-start-time.webm"
+            <video src="../resources/test-positive-start-time.webm"
                    class="should-have-overlay-btn"></video>
         </div>
         <script>
diff --git a/third_party/WebKit/LayoutTests/media/video-overlay-cast-dark-rendering.html b/third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-dark-rendering.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/media/video-overlay-cast-dark-rendering.html
rename to third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-dark-rendering.html
index 5509114..adb6744 100644
--- a/third_party/WebKit/LayoutTests/media/video-overlay-cast-dark-rendering.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-dark-rendering.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <script src="media-file.js"></script>
-  <script src="video-paint-test.js"></script>
+  <script src="../media-file.js"></script>
+  <script src="../video-paint-test.js"></script>
 </head>
 <body>
   <p>Test overlay cast button rendering on dark background.</p>
@@ -18,7 +18,7 @@
   <script>
     if (window.internals)
         window.internals.settings.setMockScrollbarsEnabled(true);
-        
+
     var videos = document.getElementsByTagName('video');
     waitForMultipleEvents("canplaythrough", videos.length, function() {
         for (var i = 0; i < videos.length; ++i) {
@@ -35,7 +35,7 @@
                 testRunner.notifyDone();
         });
     });
-    setSrcByTagName('video', findMediaFile('video', 'content/test'));
+    setSrcByTagName('video', findMediaFile('video', '../content/test'));
   </script>
 </body>
 </html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-overlay-cast-light-rendering.html b/third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-light-rendering.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/media/video-overlay-cast-light-rendering.html
rename to third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-light-rendering.html
index dce3d60..57d06bd 100644
--- a/third_party/WebKit/LayoutTests/media/video-overlay-cast-light-rendering.html
+++ b/third_party/WebKit/LayoutTests/media/controls/video-overlay-cast-light-rendering.html
@@ -1,8 +1,8 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <script src="media-file.js"></script>
-  <script src="video-paint-test.js"></script>
+  <script src="../media-file.js"></script>
+  <script src="../video-paint-test.js"></script>
 </head>
 <body>
   <p>Test overlay cast button rendering on light background.</p>
@@ -18,7 +18,7 @@
   <script>
     if (window.internals)
         window.internals.settings.setMockScrollbarsEnabled(true);
-        
+
     var videos = document.getElementsByTagName('video');
     waitForMultipleEvents("canplaythrough", videos.length, function() {
         for (var i = 0; i < videos.length; ++i) {
@@ -35,7 +35,7 @@
                 testRunner.notifyDone();
         });
     });
-    setSrcByTagName('video', findMediaFile('video', 'content/counting'));
+    setSrcByTagName('video', findMediaFile('video', '../content/counting'));
   </script>
 </body>
 </html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
new file mode 100644
index 0000000..6f1b9b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt
new file mode 100644
index 0000000..57e32b07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -0,0 +1,91 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 252x19
+          text run at (0,0) width 252: "Test controls rendering with cast button."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,260) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,260) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,505) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,505) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutButton {INPUT} at (256,0) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-dark-rendering-expected.png
new file mode 100644
index 0000000..21c7372e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-dark-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-dark-rendering-expected.txt
new file mode 100644
index 0000000..9d10244
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-dark-rendering-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 348x19
+          text run at (0,0) width 348: "Test overlay cast button rendering on dark background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,305) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,550) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-light-rendering-expected.png
new file mode 100644
index 0000000..c9c8a287
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-light-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-light-rendering-expected.txt
new file mode 100644
index 0000000..96d0290
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-overlay-cast-light-rendering-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 874
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x620 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutBlockFlow {HTML} at (0,0) size 785x620
+    LayoutBlockFlow {BODY} at (8,16) size 769x596
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 348x19
+          text run at (0,0) width 348: "Test overlay cast button rendering on light background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x293
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,329) size 769x267
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,596) size 769x0
+layer at (8,52) size 352x288
+  LayoutVideo {VIDEO} at (0,0) size 352x288
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo {VIDEO} at (0,0) size 320x261.81
+layer at (8,52) size 352x288
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x288
+    LayoutBlockFlow {DIV} at (0,256) size 352x32
+layer at (8,52) size 352x246
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x246
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,345) size 320x220
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
+layer at (16,353) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,612) size 320x261.81
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,612) size 320x220 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
new file mode 100644
index 0000000..6f1b9b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
new file mode 100644
index 0000000..57e32b07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -0,0 +1,91 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 252x19
+          text run at (0,0) width 252: "Test controls rendering with cast button."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,260) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,260) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,505) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,505) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutButton {INPUT} at (256,0) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
new file mode 100644
index 0000000..21c7372e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt
new file mode 100644
index 0000000..9d10244
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 348x19
+          text run at (0,0) width 348: "Test overlay cast button rendering on dark background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,305) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,550) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
new file mode 100644
index 0000000..c9c8a287
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt
new file mode 100644
index 0000000..96d0290
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 874
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x620 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutBlockFlow {HTML} at (0,0) size 785x620
+    LayoutBlockFlow {BODY} at (8,16) size 769x596
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 348x19
+          text run at (0,0) width 348: "Test overlay cast button rendering on light background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x293
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,329) size 769x267
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,596) size 769x0
+layer at (8,52) size 352x288
+  LayoutVideo {VIDEO} at (0,0) size 352x288
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo {VIDEO} at (0,0) size 320x261.81
+layer at (8,52) size 352x288
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x288
+    LayoutBlockFlow {DIV} at (0,256) size 352x32
+layer at (8,52) size 352x246
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x246
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,345) size 320x220
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
+layer at (16,353) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,612) size 320x261.81
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,612) size 320x220 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png
new file mode 100644
index 0000000..68a1145d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt
new file mode 100644
index 0000000..657f77fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -0,0 +1,91 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 778
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x546
+  LayoutBlockFlow {HTML} at (0,0) size 785x546
+    LayoutBlockFlow {BODY} at (8,16) size 769x522
+      LayoutBlockFlow {P} at (0,0) size 769x18
+        LayoutText {#text} at (0,0) size 258x18
+          text run at (0,0) width 258: "Test controls rendering with cast button."
+      LayoutBlockFlow {DIV} at (0,34) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,278) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,522) size 769x0
+layer at (8,50) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,294) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,50) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,50) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,258) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
+        LayoutText {#text} at (0,9) size 24x14
+          text run at (0,9) width 24: "0:00"
+    LayoutSlider {INPUT} at (73.36,15) size 71.64x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,258) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,294) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,294) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,502) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
+        LayoutText {#text} at (0,9) size 24x14
+          text run at (0,9) width 24: "0:00"
+    LayoutSlider {INPUT} at (73.36,15) size 71.64x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,502) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,538) size 320x240
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,538) size 320x198 backgroundClip at (8,538) size 320x62 clip at (8,538) size 320x62
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,746) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
+        LayoutText {#text} at (0,9) size 24x14
+          text run at (0,9) width 24: "0:00"
+    LayoutSlider {INPUT} at (73.36,15) size 71.64x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,746) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutButton {INPUT} at (256,0) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png
new file mode 100644
index 0000000..b9d3d61
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.txt
new file mode 100644
index 0000000..5c02a1f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 778
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x546
+  LayoutBlockFlow {HTML} at (0,0) size 785x546
+    LayoutBlockFlow {BODY} at (8,16) size 769x522
+      LayoutBlockFlow {P} at (0,0) size 769x18
+        LayoutText {#text} at (0,0) size 354x18
+          text run at (0,0) width 354: "Test overlay cast button rendering on dark background."
+      LayoutBlockFlow {DIV} at (0,34) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,278) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,522) size 769x0
+layer at (8,50) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,294) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,50) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,50) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,58) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,294) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,294) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,302) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,538) size 320x240
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,538) size 320x198 backgroundClip at (8,538) size 320x62 clip at (8,538) size 320x62
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,546) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png
new file mode 100644
index 0000000..e92135e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.txt
new file mode 100644
index 0000000..5e0517e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 870
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x616 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutBlockFlow {HTML} at (0,0) size 785x616
+    LayoutBlockFlow {BODY} at (8,16) size 769x592
+      LayoutBlockFlow {P} at (0,0) size 769x18
+        LayoutText {#text} at (0,0) size 355x18
+          text run at (0,0) width 355: "Test overlay cast button rendering on light background."
+      LayoutBlockFlow {DIV} at (0,34) size 769x292
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,326) size 769x266
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,592) size 769x0
+layer at (8,50) size 352x288
+  LayoutVideo {VIDEO} at (0,0) size 352x288
+layer at (8,342) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo {VIDEO} at (0,0) size 320x261.81
+layer at (8,50) size 352x288
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x288
+    LayoutBlockFlow {DIV} at (0,256) size 352x32
+layer at (8,50) size 352x246
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x246
+layer at (16,58) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,342) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,342) size 320x220
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
+layer at (16,350) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,608) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,608) size 320x261.81
+layer at (8,608) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,608) size 320x220 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
new file mode 100644
index 0000000..68a1145d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
new file mode 100644
index 0000000..657f77fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -0,0 +1,91 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 778
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x546
+  LayoutBlockFlow {HTML} at (0,0) size 785x546
+    LayoutBlockFlow {BODY} at (8,16) size 769x522
+      LayoutBlockFlow {P} at (0,0) size 769x18
+        LayoutText {#text} at (0,0) size 258x18
+          text run at (0,0) width 258: "Test controls rendering with cast button."
+      LayoutBlockFlow {DIV} at (0,34) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,278) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,522) size 769x0
+layer at (8,50) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,294) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,50) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,50) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,258) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
+        LayoutText {#text} at (0,9) size 24x14
+          text run at (0,9) width 24: "0:00"
+    LayoutSlider {INPUT} at (73.36,15) size 71.64x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,258) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,294) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,294) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,502) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
+        LayoutText {#text} at (0,9) size 24x14
+          text run at (0,9) width 24: "0:00"
+    LayoutSlider {INPUT} at (73.36,15) size 71.64x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,502) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,538) size 320x240
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,538) size 320x198 backgroundClip at (8,538) size 320x62 clip at (8,538) size 320x62
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,746) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
+        LayoutText {#text} at (0,9) size 24x14
+          text run at (0,9) width 24: "0:00"
+    LayoutSlider {INPUT} at (73.36,15) size 71.64x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,746) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutButton {INPUT} at (256,0) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
new file mode 100644
index 0000000..b9d3d61
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt
new file mode 100644
index 0000000..5c02a1f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 778
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x546
+  LayoutBlockFlow {HTML} at (0,0) size 785x546
+    LayoutBlockFlow {BODY} at (8,16) size 769x522
+      LayoutBlockFlow {P} at (0,0) size 769x18
+        LayoutText {#text} at (0,0) size 354x18
+          text run at (0,0) width 354: "Test overlay cast button rendering on dark background."
+      LayoutBlockFlow {DIV} at (0,34) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,278) size 769x244
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,522) size 769x0
+layer at (8,50) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,294) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,50) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,50) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,58) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,294) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,294) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,302) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,538) size 320x240
+layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,538) size 320x198 backgroundClip at (8,538) size 320x62 clip at (8,538) size 320x62
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,546) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
new file mode 100644
index 0000000..e92135e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt
new file mode 100644
index 0000000..5e0517e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 870
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x616 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutBlockFlow {HTML} at (0,0) size 785x616
+    LayoutBlockFlow {BODY} at (8,16) size 769x592
+      LayoutBlockFlow {P} at (0,0) size 769x18
+        LayoutText {#text} at (0,0) size 355x18
+          text run at (0,0) width 355: "Test overlay cast button rendering on light background."
+      LayoutBlockFlow {DIV} at (0,34) size 769x292
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,326) size 769x266
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,592) size 769x0
+layer at (8,50) size 352x288
+  LayoutVideo {VIDEO} at (0,0) size 352x288
+layer at (8,342) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo {VIDEO} at (0,0) size 320x261.81
+layer at (8,50) size 352x288
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x288
+    LayoutBlockFlow {DIV} at (0,256) size 352x32
+layer at (8,50) size 352x246
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x246
+layer at (16,58) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,342) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,342) size 320x220
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
+layer at (16,350) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,608) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,608) size 320x261.81
+layer at (8,608) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,608) size 320x220 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png
new file mode 100644
index 0000000..d712dfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt
new file mode 100644
index 0000000..f443612f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -0,0 +1,91 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 240x19
+          text run at (0,0) width 240: "Test controls rendering with cast button."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,260) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,260) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,505) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,505) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutButton {INPUT} at (256,0) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-dark-rendering-expected.png
new file mode 100644
index 0000000..53c148f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-dark-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-dark-rendering-expected.txt
new file mode 100644
index 0000000..226a9c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-dark-rendering-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 334x19
+          text run at (0,0) width 334: "Test overlay cast button rendering on dark background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,305) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,550) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-light-rendering-expected.png
new file mode 100644
index 0000000..643b449a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-light-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-light-rendering-expected.txt
new file mode 100644
index 0000000..37f190a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-overlay-cast-light-rendering-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 874
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x620 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutBlockFlow {HTML} at (0,0) size 785x620
+    LayoutBlockFlow {BODY} at (8,16) size 769x596
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 330x19
+          text run at (0,0) width 330: "Test overlay cast button rendering on light background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x293
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,329) size 769x267
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,596) size 769x0
+layer at (8,52) size 352x288
+  LayoutVideo {VIDEO} at (0,0) size 352x288
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo {VIDEO} at (0,0) size 320x261.81
+layer at (8,52) size 352x288
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x288
+    LayoutBlockFlow {DIV} at (0,256) size 352x32
+layer at (8,52) size 352x246
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x246
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,345) size 320x220
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
+layer at (16,353) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,612) size 320x261.81
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,612) size 320x220 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
new file mode 100644
index 0000000..d712dfd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
new file mode 100644
index 0000000..f443612f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -0,0 +1,91 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 240x19
+          text run at (0,0) width 240: "Test controls rendering with cast button."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,260) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,260) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,505) size 320x32 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,505) size 32x32
+  LayoutButton {INPUT} at (256,0) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
+    LayoutButton {INPUT} at (0,0) size 32x32
+    LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
+      LayoutBlockFlow (anonymous) at (0,0) size 24x32
+        LayoutText {#text} at (0,8) size 24x15
+          text run at (0,8) width 24: "0:00"
+    LayoutSlider {INPUT} at (74,15) size 71x2
+      LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
+    LayoutButton {INPUT} at (163,0) size 32x32
+    LayoutSlider {INPUT} at (213,15) size 25x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
+    LayoutButton {INPUT} at (288,0) size 32x32
+layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutButton {INPUT} at (256,0) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
new file mode 100644
index 0000000..53c148f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt
new file mode 100644
index 0000000..226a9c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.txt
@@ -0,0 +1,40 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 782
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x550
+  LayoutBlockFlow {HTML} at (0,0) size 785x550
+    LayoutBlockFlow {BODY} at (8,16) size 769x526
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 334x19
+          text run at (0,0) width 334: "Test overlay cast button rendering on dark background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,281) size 769x245
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,526) size 769x0
+layer at (8,52) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,297) size 320x240
+  LayoutVideo {VIDEO} at (0,0) size 320x240
+layer at (8,52) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,52) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,297) size 320x240
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,297) size 320x198
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,305) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
+layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
+    LayoutBlockFlow {DIV} at (0,208) size 320x32
+layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
+layer at (16,550) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
new file mode 100644
index 0000000..643b449a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt
new file mode 100644
index 0000000..37f190a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.txt
@@ -0,0 +1,38 @@
+layer at (0,0) size 800x600 clip at (0,0) size 785x600 scrollHeight 874
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 785x620 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutBlockFlow {HTML} at (0,0) size 785x620
+    LayoutBlockFlow {BODY} at (8,16) size 769x596
+      LayoutBlockFlow {P} at (0,0) size 769x20
+        LayoutText {#text} at (0,0) size 330x19
+          text run at (0,0) width 330: "Test overlay cast button rendering on light background."
+      LayoutBlockFlow {DIV} at (0,36) size 769x293
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,329) size 769x267
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,596) size 769x0
+layer at (8,52) size 352x288
+  LayoutVideo {VIDEO} at (0,0) size 352x288
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo {VIDEO} at (0,0) size 320x261.81
+layer at (8,52) size 352x288
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x288
+    LayoutBlockFlow {DIV} at (0,256) size 352x32
+layer at (8,52) size 352x246
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 352x246
+layer at (16,60) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,345) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,345) size 320x220
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
+layer at (16,353) size 32x32
+  LayoutButton (positioned) {INPUT} at (8,8) size 32x32
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutVideo (positioned) {VIDEO} at (8,612) size 320x261.81
+layer at (8,612) size 320x262 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x261.81
+    LayoutBlockFlow {DIV} at (0,229.81) size 320x32
+layer at (8,612) size 320x220 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
+  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x219.81
diff --git a/third_party/WebKit/LayoutTests/virtual/new-remote-playback-pipeline/media/controls/README.txt b/third_party/WebKit/LayoutTests/virtual/new-remote-playback-pipeline/media/controls/README.txt
new file mode 100644
index 0000000..64e0f3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/new-remote-playback-pipeline/media/controls/README.txt
@@ -0,0 +1,2 @@
+The new-remote-playback-pipeline enables the new remote playback pipeline to run
+the existing native controls tests against the new pipeline.
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/virtual/new-remote-playback-pipeline/media/remoteplayback/README.txt b/third_party/WebKit/LayoutTests/virtual/new-remote-playback-pipeline/media/remoteplayback/README.txt
new file mode 100644
index 0000000..ac8010b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/new-remote-playback-pipeline/media/remoteplayback/README.txt
@@ -0,0 +1,2 @@
+The new-remote-playback-pipeline enables the new remote playback pipeline to run
+the existing remote playback tests against the new pipeline.
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 42d58c9..65f77c1e 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -646,11 +646,6 @@
         web_media_player_->RequestRemotePlaybackDisabled(
             !params.new_value.IsNull());
       }
-      // TODO(mlamouri): there is no direct API to expose if
-      // disableRemotePLayback attribute has changed. It will require a direct
-      // access to MediaControls for the moment.
-      if (GetMediaControls())
-        GetMediaControls()->OnDisableRemotePlaybackAttributeChanged();
     }
   } else {
     HTMLElement::ParseAttribute(params);
@@ -3159,18 +3154,10 @@
     WebRemotePlaybackAvailability availability) {
   if (RemotePlaybackClient())
     RemotePlaybackClient()->AvailabilityChanged(availability);
-
-  // TODO(mlamouri): the RemotePlayback object should be used in order to
-  // register to watch availability but the object is in modules/ and core/ has
-  // no access to it. It will have to be done when the media controls move to
-  // modules/.
-  if (GetMediaControls())
-    GetMediaControls()->OnRemotePlaybackAvailabilityChanged();
 }
 
 bool HTMLMediaElement::HasRemoteRoutes() const {
-  // TODO(mlamouri): this is only used for controls related code. It shouldn't
-  // live in HTMLMediaElement.
+  // TODO(mlamouri): used by MediaControlsPainter; should be refactored out.
   return RemotePlaybackClient() &&
          RemotePlaybackClient()->RemotePlaybackAvailable();
 }
@@ -3179,24 +3166,12 @@
   playing_remotely_ = true;
   if (RemotePlaybackClient())
     RemotePlaybackClient()->StateChanged(WebRemotePlaybackState::kConnecting);
-
-  // TODO(mlamouri): the RemotePlayback object should be used in order to listen
-  // for events but the object is in modules/ and core/ has no access to it. It
-  // will have to be done when the media controls move to modules/.
-  if (GetMediaControls())
-    GetMediaControls()->OnRemotePlaybackConnecting();
 }
 
 void HTMLMediaElement::DisconnectedFromRemoteDevice() {
   playing_remotely_ = false;
   if (RemotePlaybackClient())
     RemotePlaybackClient()->StateChanged(WebRemotePlaybackState::kDisconnected);
-
-  // TODO(mlamouri): the RemotePlayback object should be used in order to listen
-  // for events but the object is in modules/ and core/ has no access to it. It
-  // will have to be done when the media controls move to modules/.
-  if (GetMediaControls())
-    GetMediaControls()->OnRemotePlaybackDisconnected();
 }
 
 void HTMLMediaElement::CancelledRemotePlaybackRequest() {
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp
index f5317b7..fe4d41e 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElementEventListenersTest.cpp
@@ -96,6 +96,8 @@
     EXPECT_TRUE(persistent_video->HasEventListeners());
   }
 
+  testing::RunPendingTasks();
+
   ThreadState::Current()->CollectAllGarbage();
 
   // They have been GC'd.
@@ -123,6 +125,8 @@
   EXPECT_TRUE(GetDocument().HasEventListeners());
   EXPECT_TRUE(Video()->HasEventListeners());
 
+  testing::RunPendingTasks();
+
   ThreadState::Current()->CollectAllGarbage();
 
   EXPECT_NE(Video(), nullptr);
diff --git a/third_party/WebKit/Source/core/html/media/MediaControls.h b/third_party/WebKit/Source/core/html/media/MediaControls.h
index 8d5600c..e86fd0ae 100644
--- a/third_party/WebKit/Source/core/html/media/MediaControls.h
+++ b/third_party/WebKit/Source/core/html/media/MediaControls.h
@@ -47,16 +47,6 @@
   // be notified on the TextTrack object. See https://crbug.com/669977
   virtual void OnTrackElementFailedToLoad() = 0;
 
-  // TODO(mlamouri): the following methods will be able to become private when
-  // the controls have moved to modules/ and have access to RemotePlayback.
-  virtual void OnRemotePlaybackAvailabilityChanged() = 0;
-  virtual void OnRemotePlaybackConnecting() = 0;
-  virtual void OnRemotePlaybackDisconnected() = 0;
-
-  // TODO(mlamouri): this method is needed in order to notify the controls that
-  // the attribute have changed.
-  virtual void OnDisableRemotePlaybackAttributeChanged() = 0;
-
   // TODO(mlamouri): this method should be moved away from the interface to
   // become an implementation detail.
   virtual void NetworkStateChanged() = 0;
diff --git a/third_party/WebKit/Source/modules/media_controls/DEPS b/third_party/WebKit/Source/modules/media_controls/DEPS
index bd25717f..3f4890f 100644
--- a/third_party/WebKit/Source/modules/media_controls/DEPS
+++ b/third_party/WebKit/Source/modules/media_controls/DEPS
@@ -2,4 +2,5 @@
   "-modules",
   "+modules/ModulesExport.h",
   "+modules/media_controls",
+  "+modules/remoteplayback",
 ]
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
index a85e906..4a56a9f 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -29,6 +29,10 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ClientRect.h"
 #include "core/dom/Fullscreen.h"
+#include "core/dom/MutationCallback.h"
+#include "core/dom/MutationObserver.h"
+#include "core/dom/MutationObserverInit.h"
+#include "core/dom/MutationRecord.h"
 #include "core/dom/ResizeObserver.h"
 #include "core/dom/ResizeObserverCallback.h"
 #include "core/dom/ResizeObserverEntry.h"
@@ -64,6 +68,8 @@
 #include "modules/media_controls/elements/MediaControlTimelineElement.h"
 #include "modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.h"
 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h"
+#include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h"
+#include "modules/remoteplayback/RemotePlayback.h"
 #include "platform/EventDispatchForbiddenScope.h"
 
 namespace blink {
@@ -133,7 +139,9 @@
     return false;
   }
 
-  return media_element.HasRemoteRoutes();
+  RemotePlayback* remote =
+      HTMLMediaElementRemotePlayback::remote(media_element);
+  return remote && remote->RemotePlaybackAvailable();
 }
 
 bool PreferHiddenVolumeControls(const Document& document) {
@@ -194,6 +202,57 @@
   Member<MediaControlsImpl> controls_;
 };
 
+// Observes changes to the HTMLMediaElement attributes that affect controls.
+// Currently only observes the disableRemotePlayback attribute.
+class MediaControlsImpl::MediaElementMutationCallback
+    : public MutationCallback {
+ public:
+  explicit MediaElementMutationCallback(MediaControlsImpl* controls)
+      : controls_(controls) {
+    observer_ = MutationObserver::Create(this);
+    Vector<String> filter;
+    filter.push_back(HTMLNames::disableremoteplaybackAttr.ToString());
+    MutationObserverInit init;
+    init.setAttributeOldValue(true);
+    init.setAttributes(true);
+    init.setAttributeFilter(filter);
+    observer_->observe(&controls_->MediaElement(), init, ASSERT_NO_EXCEPTION);
+  }
+
+  DEFINE_INLINE_VIRTUAL_TRACE() {
+    visitor->Trace(controls_);
+    visitor->Trace(observer_);
+    MutationCallback::Trace(visitor);
+  }
+
+  void Disconnect() { observer_->disconnect(); }
+
+ private:
+  void Call(const HeapVector<Member<MutationRecord>>& records,
+            MutationObserver*) override {
+    for (const auto& record : records) {
+      if (record->type() != "attributes")
+        continue;
+
+      const Element& element = *ToElement(record->target());
+      if (record->oldValue() == element.getAttribute(record->attributeName()))
+        continue;
+
+      DCHECK_EQ(HTMLNames::disableremoteplaybackAttr.ToString(),
+                record->attributeName());
+      controls_->RefreshCastButtonVisibility();
+      return;
+    }
+  }
+
+  ExecutionContext* GetExecutionContext() const override {
+    return &controls_->GetDocument();
+  }
+
+  Member<MediaControlsImpl> controls_;
+  Member<MutationObserver> observer_;
+};
+
 MediaControls* MediaControlsImpl::Factory::Create(
     HTMLMediaElement& media_element,
     ShadowRoot& shadow_root) {
@@ -430,6 +489,9 @@
     resize_observer_->observe(&html_media_element);
   }
 
+  if (!element_mutation_callback_)
+    element_mutation_callback_ = new MediaElementMutationCallback(this);
+
   return HTMLDivElement::InsertedInto(root);
 }
 
@@ -447,6 +509,11 @@
     rotate_to_fullscreen_delegate_->Detach();
 
   resize_observer_.Clear();
+
+  if (element_mutation_callback_) {
+    element_mutation_callback_->Disconnect();
+    element_mutation_callback_.Clear();
+  }
 }
 
 void MediaControlsImpl::Reset() {
@@ -532,12 +599,16 @@
 bool MediaControlsImpl::ShouldHideMediaControls(unsigned behavior_flags) const {
   // Never hide for a media element without visual representation.
   if (!MediaElement().IsHTMLVideoElement() || !MediaElement().HasVideo() ||
-      MediaElement().IsPlayingRemotely() ||
       toHTMLVideoElement(MediaElement()).GetMediaRemotingStatus() ==
           HTMLVideoElement::MediaRemotingStatus::kStarted) {
     return false;
   }
 
+  RemotePlayback* remote =
+      HTMLMediaElementRemotePlayback::remote(MediaElement());
+  if (remote && remote->GetState() != WebRemotePlaybackState::kDisconnected)
+    return false;
+
   // Keep the controls visible as long as the timer is running.
   const bool ignore_wait_for_timer = behavior_flags & kIgnoreWaitForTimer;
   if (!ignore_wait_for_timer && keep_showing_until_timer_fires_)
@@ -677,8 +748,9 @@
 
 void MediaControlsImpl::ShowOverlayCastButtonIfNeeded() {
   if (MediaElement().ShouldShowControls() ||
-      !ShouldShowCastButton(MediaElement()))
+      !ShouldShowCastButton(MediaElement())) {
     return;
+  }
 
   overlay_cast_button_->TryShowOverlay();
   ResetHideMediaControlsTimer();
@@ -692,14 +764,9 @@
   Fullscreen::ExitFullscreen(GetDocument());
 }
 
-void MediaControlsImpl::StartedCasting() {
-  cast_button_->SetIsPlayingRemotely(true);
-  overlay_cast_button_->SetIsPlayingRemotely(true);
-}
-
-void MediaControlsImpl::StoppedCasting() {
-  cast_button_->SetIsPlayingRemotely(false);
-  overlay_cast_button_->SetIsPlayingRemotely(false);
+void MediaControlsImpl::RemotePlaybackStateChanged() {
+  cast_button_->UpdateDisplayType();
+  overlay_cast_button_->UpdateDisplayType();
 }
 
 void MediaControlsImpl::DefaultEventHandler(Event* event) {
@@ -1123,6 +1190,7 @@
 }
 
 DEFINE_TRACE(MediaControlsImpl) {
+  visitor->Trace(element_mutation_callback_);
   visitor->Trace(resize_observer_);
   visitor->Trace(panel_);
   visitor->Trace(overlay_play_button_);
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
index e842e4ae..d4800e4 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.h
@@ -85,18 +85,6 @@
   // HTMLTrackElement failed to load because there is no web exposed way to
   // be notified on the TextTrack object. See https://crbug.com/669977
   void OnTrackElementFailedToLoad() override { OnTextTracksAddedOrRemoved(); }
-  // TODO(mlamouri): the following methods will be able to become private when
-  // the controls have to modules/ and have access to RemotePlayback.
-  void OnRemotePlaybackAvailabilityChanged() override {
-    RefreshCastButtonVisibility();
-  }
-  void OnRemotePlaybackConnecting() override { StartedCasting(); }
-  void OnRemotePlaybackDisconnected() override { StoppedCasting(); }
-  // TODO(mlamouri): this method is needed in order to notify the controls that
-  // the attribute have changed.
-  void OnDisableRemotePlaybackAttributeChanged() override {
-    RefreshCastButtonVisibility();
-  }
   // Notify us that the media element's network state has changed.
   void NetworkStateChanged() override;
   LayoutObject* PanelLayoutObject() override;
@@ -153,6 +141,7 @@
   // Need to be members of MediaControls for private member access.
   class BatchedControlUpdate;
   class MediaControlsResizeObserverCallback;
+  class MediaElementMutationCallback;
 
   static MediaControlsImpl* Create(HTMLMediaElement&, ShadowRoot&);
 
@@ -201,8 +190,7 @@
   bool ContainsRelatedTarget(Event*);
 
   // Internal cast related methods.
-  void StartedCasting();
-  void StoppedCasting();
+  void RemotePlaybackStateChanged();
   void RefreshCastButtonVisibility();
   void RefreshCastButtonVisibilityWithoutUpdate();
 
@@ -259,6 +247,10 @@
   // necessary.
   Member<ResizeObserver> resize_observer_;
 
+  // Watches the media element for attribute changes and updates media controls
+  // as necessary.
+  Member<MediaElementMutationCallback> element_mutation_callback_;
+
   TaskRunnerTimer<MediaControlsImpl> element_size_changed_timer_;
   IntSize size_;
 
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
index 7e9c97be..cfa659a 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
@@ -25,6 +25,8 @@
 #include "modules/media_controls/elements/MediaControlDownloadButtonElement.h"
 #include "modules/media_controls/elements/MediaControlTimelineElement.h"
 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h"
+#include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h"
+#include "modules/remoteplayback/RemotePlayback.h"
 #include "platform/heap/Handle.h"
 #include "platform/testing/EmptyWebMediaPlayer.h"
 #include "platform/testing/HistogramTester.h"
@@ -60,23 +62,6 @@
   WebTimeRanges seekable_;
 };
 
-class MockWebRemotePlaybackClient : public WebRemotePlaybackClient {
- public:
-  void StateChanged(WebRemotePlaybackState) override {}
-  void AvailabilityChanged(
-      WebRemotePlaybackAvailability availability) override {
-    availability_ = availability;
-  }
-  void PromptCancelled() override {}
-  bool RemotePlaybackAvailable() const override {
-    return availability_ == WebRemotePlaybackAvailability::kDeviceAvailable;
-  }
-
- private:
-  WebRemotePlaybackAvailability availability_ =
-      WebRemotePlaybackAvailability::kUnknown;
-};
-
 class MockLayoutObject : public LayoutObject {
  public:
   MockLayoutObject(Node* node) : LayoutObject(node) {}
@@ -100,16 +85,9 @@
   }
 
   WebRemotePlaybackClient* CreateWebRemotePlaybackClient(
-      HTMLMediaElement&) override {
-    if (!remote_playback_client_) {
-      remote_playback_client_ =
-          WTF::WrapUnique(new MockWebRemotePlaybackClient);
-    }
-    return remote_playback_client_.get();
+      HTMLMediaElement& element) override {
+    return HTMLMediaElementRemotePlayback::remote(element);
   }
-
- private:
-  std::unique_ptr<MockWebRemotePlaybackClient> remote_playback_client_;
 };
 
 Element* GetElementByShadowPseudoId(Node& root_node,
@@ -228,6 +206,10 @@
   void MouseMoveTo(WebFloatPoint pos);
   void MouseUpAt(WebFloatPoint pos);
 
+  bool HasAvailabilityCallbacks(RemotePlayback* remote_playback) {
+    return !remote_playback->availability_callbacks_.IsEmpty();
+  }
+
  private:
   std::unique_ptr<DummyPageHolder> page_holder_;
   Persistent<MediaControlsImpl> media_controls_;
@@ -349,10 +331,12 @@
 
   MediaControls().MediaElement().SetBooleanAttribute(
       HTMLNames::disableremoteplaybackAttr, true);
+  testing::RunPendingTasks();
   ASSERT_FALSE(IsElementVisible(*cast_button));
 
   MediaControls().MediaElement().SetBooleanAttribute(
       HTMLNames::disableremoteplaybackAttr, false);
+  testing::RunPendingTasks();
   ASSERT_TRUE(IsElementVisible(*cast_button));
 }
 
@@ -376,10 +360,12 @@
 
   MediaControls().MediaElement().SetBooleanAttribute(
       HTMLNames::disableremoteplaybackAttr, true);
+  testing::RunPendingTasks();
   ASSERT_FALSE(IsElementVisible(*cast_overlay_button));
 
   MediaControls().MediaElement().SetBooleanAttribute(
       HTMLNames::disableremoteplaybackAttr, false);
+  testing::RunPendingTasks();
   ASSERT_TRUE(IsElementVisible(*cast_overlay_button));
 }
 
@@ -847,4 +833,61 @@
   EXPECT_FALSE(IsElementVisible(*panel));
 }
 
+TEST_F(MediaControlsImplTest,
+       RemovingFromDocumentRemovesListenersAndCallbacks) {
+  auto page_holder = DummyPageHolder::Create();
+
+  HTMLMediaElement* element =
+      HTMLVideoElement::Create(page_holder->GetDocument());
+  element->SetBooleanAttribute(HTMLNames::controlsAttr, true);
+  page_holder->GetDocument().body()->AppendChild(element);
+
+  RemotePlayback* remote_playback =
+      HTMLMediaElementRemotePlayback::remote(*element);
+
+  EXPECT_TRUE(remote_playback->HasEventListeners());
+  EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback));
+
+  WeakPersistent<HTMLMediaElement> weak_persistent_video = element;
+  {
+    Persistent<HTMLMediaElement> persistent_video = element;
+    page_holder->GetDocument().body()->setInnerHTML("");
+
+    // When removed from the document, the event listeners should have been
+    // dropped.
+    EXPECT_FALSE(remote_playback->HasEventListeners());
+    EXPECT_FALSE(HasAvailabilityCallbacks(remote_playback));
+  }
+
+  testing::RunPendingTasks();
+
+  ThreadState::Current()->CollectAllGarbage();
+
+  // It has been GC'd.
+  EXPECT_EQ(nullptr, weak_persistent_video);
+}
+
+TEST_F(MediaControlsImplTest,
+       ReInsertingInDocumentRestoresListenersAndCallbacks) {
+  auto page_holder = DummyPageHolder::Create();
+
+  HTMLMediaElement* element =
+      HTMLVideoElement::Create(page_holder->GetDocument());
+  element->SetBooleanAttribute(HTMLNames::controlsAttr, true);
+  page_holder->GetDocument().body()->AppendChild(element);
+
+  RemotePlayback* remote_playback =
+      HTMLMediaElementRemotePlayback::remote(*element);
+
+  // This should be a no-op. We keep a reference on the media element to avoid
+  // an unexpected GC.
+  {
+    Persistent<HTMLMediaElement> video_holder = element;
+    page_holder->GetDocument().body()->RemoveChild(element);
+    page_holder->GetDocument().body()->AppendChild(video_holder.Get());
+    EXPECT_TRUE(remote_playback->HasEventListeners());
+    EXPECT_TRUE(HasAvailabilityCallbacks(remote_playback));
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.cpp
index 97bbd28d..fe3bdc4 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.cpp
@@ -8,6 +8,9 @@
 #include "core/html/HTMLMediaElement.h"
 #include "core/html/track/TextTrackList.h"
 #include "modules/media_controls/MediaControlsImpl.h"
+#include "modules/remoteplayback/AvailabilityCallbackWrapper.h"
+#include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h"
+#include "modules/remoteplayback/RemotePlayback.h"
 
 namespace blink {
 
@@ -51,6 +54,23 @@
     media_controls_->PanelElement()->addEventListener(EventTypeNames::keypress,
                                                       this, false);
   }
+
+  RemotePlayback* remote = GetRemotePlayback();
+  if (remote) {
+    remote->addEventListener(EventTypeNames::connect, this);
+    remote->addEventListener(EventTypeNames::connecting, this);
+    remote->addEventListener(EventTypeNames::disconnect, this);
+
+    // TODO(avayvod, mlamouri): Attach can be called twice. See
+    // https://crbug.com/713275.
+    if (remote_playback_availability_callback_id_ == -1) {
+      remote_playback_availability_callback_id_ =
+          remote->WatchAvailabilityInternal(new AvailabilityCallbackWrapper(
+              WTF::Bind(&MediaControlsMediaEventListener::
+                            OnRemotePlaybackAvailabilityChanged,
+                        WrapPersistent(this))));
+    }
+  }
 }
 
 void MediaControlsMediaEventListener::Detach() {
@@ -68,6 +88,21 @@
     media_controls_->PanelElement()->removeEventListener(
         EventTypeNames::keypress, this, false);
   }
+
+  RemotePlayback* remote = GetRemotePlayback();
+  if (remote) {
+    remote->removeEventListener(EventTypeNames::connect, this);
+    remote->removeEventListener(EventTypeNames::connecting, this);
+    remote->removeEventListener(EventTypeNames::disconnect, this);
+
+    // TODO(avayvod): apparently Detach() can be called without a previous
+    // Attach() call. See https://crbug.com/713275 for more details.
+    if (remote_playback_availability_callback_id_ != -1) {
+      remote->CancelWatchAvailabilityInternal(
+          remote_playback_availability_callback_id_);
+      remote_playback_availability_callback_id_ = -1;
+    }
+  }
 }
 
 bool MediaControlsMediaEventListener::operator==(
@@ -79,6 +114,10 @@
   return media_controls_->MediaElement();
 }
 
+RemotePlayback* MediaControlsMediaEventListener::GetRemotePlayback() {
+  return HTMLMediaElementRemotePlayback::remote(GetMediaElement());
+}
+
 void MediaControlsMediaEventListener::handleEvent(
     ExecutionContext* execution_context,
     Event* event) {
@@ -147,9 +186,21 @@
     return;
   }
 
+  // RemotePlayback state change events.
+  if (event->type() == EventTypeNames::connect ||
+      event->type() == EventTypeNames::connecting ||
+      event->type() == EventTypeNames::disconnect) {
+    media_controls_->RemotePlaybackStateChanged();
+    return;
+  }
+
   NOTREACHED();
 }
 
+void MediaControlsMediaEventListener::OnRemotePlaybackAvailabilityChanged() {
+  media_controls_->RefreshCastButtonVisibility();
+}
+
 DEFINE_TRACE(MediaControlsMediaEventListener) {
   EventListener::Trace(visitor);
   visitor->Trace(media_controls_);
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.h b/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.h
index 56e1810..530d746 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.h
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsMediaEventListener.h
@@ -11,6 +11,7 @@
 
 class HTMLMediaElement;
 class MediaControlsImpl;
+class RemotePlayback;
 
 class MediaControlsMediaEventListener final : public EventListener {
  public:
@@ -31,10 +32,14 @@
 
  private:
   HTMLMediaElement& GetMediaElement();
+  RemotePlayback* GetRemotePlayback();
 
   void handleEvent(ExecutionContext*, Event*) override;
 
+  void OnRemotePlaybackAvailabilityChanged();
+
   Member<MediaControlsImpl> media_controls_;
+  int remote_playback_availability_callback_id_ = -1;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
index 448fc43..279d449 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
@@ -10,6 +10,8 @@
 #include "core/html/HTMLMediaElement.h"
 #include "modules/media_controls/MediaControlsImpl.h"
 #include "modules/media_controls/elements/MediaControlElementsHelper.h"
+#include "modules/remoteplayback/HTMLMediaElementRemotePlayback.h"
+#include "modules/remoteplayback/RemotePlayback.h"
 #include "platform/Histogram.h"
 #include "public/platform/Platform.h"
 
@@ -42,7 +44,7 @@
 
   if (is_overlay_button_)
     RecordMetrics(CastOverlayMetrics::kCreated);
-  SetIsPlayingRemotely(false);
+  UpdateDisplayType();
 }
 
 void MediaControlCastButtonElement::TryShowOverlay() {
@@ -61,9 +63,8 @@
   }
 }
 
-void MediaControlCastButtonElement::SetIsPlayingRemotely(
-    bool is_playing_remotely) {
-  if (is_playing_remotely) {
+void MediaControlCastButtonElement::UpdateDisplayType() {
+  if (IsPlayingRemotely()) {
     if (is_overlay_button_) {
       SetDisplayType(kMediaOverlayCastOnButton);
     } else {
@@ -85,7 +86,7 @@
 
 WebLocalizedString::Name
 MediaControlCastButtonElement::GetOverflowStringName() {
-  if (MediaElement().IsPlayingRemotely())
+  if (IsPlayingRemotely())
     return WebLocalizedString::kOverflowMenuStopCast;
   return WebLocalizedString::kOverflowMenuCast;
 }
@@ -108,11 +109,10 @@
       click_use_counted_ = true;
       RecordMetrics(CastOverlayMetrics::kClicked);
     }
-    if (MediaElement().IsPlayingRemotely()) {
-      MediaElement().RequestRemotePlaybackControl();
-    } else {
-      MediaElement().RequestRemotePlayback();
-    }
+    RemotePlayback* remote =
+        HTMLMediaElementRemotePlayback::remote(MediaElement());
+    if (remote)
+      remote->PromptInternal();
   }
   MediaControlInputElement::DefaultEventHandler(event);
 }
@@ -129,4 +129,10 @@
   overlay_histogram.Count(static_cast<int>(metric));
 }
 
+bool MediaControlCastButtonElement::IsPlayingRemotely() const {
+  RemotePlayback* remote =
+      HTMLMediaElementRemotePlayback::remote(MediaElement());
+  return remote && remote->GetState() != WebRemotePlaybackState::kDisconnected;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.h
index c640a8e..0d29cff 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.h
@@ -20,7 +20,9 @@
   // This MUST be called for cast button elements that are overlay elements.
   void TryShowOverlay();
 
-  void SetIsPlayingRemotely(bool);
+  // TODO(avayvod): replace with the button listening to the state change
+  // events.
+  void UpdateDisplayType();
 
   // MediaControlInputElement overrides.
   bool WillRespondToMouseClickEvents() override;
@@ -42,6 +44,8 @@
 
   void RecordMetrics(CastOverlayMetrics);
 
+  bool IsPlayingRemotely() const;
+
   bool is_overlay_button_;
 
   // UMA related boolean. They are used to prevent counting something twice
diff --git a/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
new file mode 100644
index 0000000..0c387a7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.cpp
@@ -0,0 +1,39 @@
+// 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 "modules/remoteplayback/AvailabilityCallbackWrapper.h"
+
+#include "bindings/modules/v8/RemotePlaybackAvailabilityCallback.h"
+#include "modules/remoteplayback/RemotePlayback.h"
+
+namespace blink {
+
+AvailabilityCallbackWrapper::AvailabilityCallbackWrapper(
+    RemotePlaybackAvailabilityCallback* callback)
+    : bindings_cb_(this, callback) {}
+
+AvailabilityCallbackWrapper::AvailabilityCallbackWrapper(
+    std::unique_ptr<WTF::Closure> callback)
+    : bindings_cb_(nullptr, nullptr), internal_cb_(std::move(callback)) {}
+
+void AvailabilityCallbackWrapper::Run(RemotePlayback* remote_playback,
+                                      bool new_availability) {
+  if (internal_cb_) {
+    DCHECK(!bindings_cb_);
+    (*internal_cb_.get())();
+    return;
+  }
+
+  bindings_cb_->call(remote_playback, new_availability);
+}
+
+DEFINE_TRACE(AvailabilityCallbackWrapper) {
+  visitor->Trace(bindings_cb_);
+}
+
+DEFINE_TRACE_WRAPPERS(AvailabilityCallbackWrapper) {
+  visitor->TraceWrappers(bindings_cb_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.h b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.h
new file mode 100644
index 0000000..efc039a
--- /dev/null
+++ b/third_party/WebKit/Source/modules/remoteplayback/AvailabilityCallbackWrapper.h
@@ -0,0 +1,46 @@
+// 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 AvailabilityCallbackWrapper_h
+#define AvailabilityCallbackWrapper_h
+
+#include <memory>
+
+#include "bindings/core/v8/ScriptWrappable.h"
+#include "bindings/core/v8/TraceWrapperMember.h"
+#include "platform/heap/GarbageCollected.h"
+#include "platform/wtf/Compiler.h"
+#include "platform/wtf/Functional.h"
+
+namespace blink {
+
+class RemotePlaybackAvailabilityCallback;
+class RemotePlayback;
+
+// Wraps either a WTF::Closure or RemotePlaybackAvailabilityCallback object
+// to be kept in the RemotePlayback's |availability_callbacks_| map.
+class AvailabilityCallbackWrapper final
+    : public GarbageCollectedFinalized<AvailabilityCallbackWrapper>,
+      public TraceWrapperBase {
+  WTF_MAKE_NONCOPYABLE(AvailabilityCallbackWrapper);
+
+ public:
+  explicit AvailabilityCallbackWrapper(RemotePlaybackAvailabilityCallback*);
+  explicit AvailabilityCallbackWrapper(std::unique_ptr<WTF::Closure>);
+  ~AvailabilityCallbackWrapper() = default;
+
+  void Run(RemotePlayback*, bool new_availability);
+
+  DECLARE_VIRTUAL_TRACE();
+  DECLARE_VIRTUAL_TRACE_WRAPPERS();
+
+ private:
+  // Only one of these callbacks must be set.
+  TraceWrapperMember<RemotePlaybackAvailabilityCallback> bindings_cb_;
+  std::unique_ptr<WTF::Closure> internal_cb_;
+};
+
+}  // namespace blink
+
+#endif  // AvailabilityCallbackWrapper_h
diff --git a/third_party/WebKit/Source/modules/remoteplayback/BUILD.gn b/third_party/WebKit/Source/modules/remoteplayback/BUILD.gn
index 9b66379..0de5988f 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/BUILD.gn
+++ b/third_party/WebKit/Source/modules/remoteplayback/BUILD.gn
@@ -6,6 +6,8 @@
 
 blink_modules_sources("remoteplayback") {
   sources = [
+    "AvailabilityCallbackWrapper.cpp",
+    "AvailabilityCallbackWrapper.h",
     "HTMLMediaElementRemotePlayback.cpp",
     "HTMLMediaElementRemotePlayback.h",
     "RemotePlayback.cpp",
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
index ef8247b2..69d9cf4 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
@@ -14,6 +14,7 @@
 #include "core/html/HTMLMediaElement.h"
 #include "core/probe/CoreProbes.h"
 #include "modules/EventTargetModules.h"
+#include "modules/remoteplayback/AvailabilityCallbackWrapper.h"
 #include "platform/MemoryCoordinator.h"
 #include "platform/UserGestureIndicator.h"
 
@@ -86,28 +87,7 @@
     return promise;
   }
 
-  int id;
-  do {
-    id = GetExecutionContext()->CircularSequentialID();
-  } while (
-      !availability_callbacks_
-           .insert(id, TraceWrapperMember<RemotePlaybackAvailabilityCallback>(
-                           this, callback))
-           .is_new_entry);
-
-  // Report the current availability via the callback.
-  // TODO(yuryu): Wrapping notifyInitialAvailability with WTF::Closure as
-  // InspectorInstrumentation requires a globally unique pointer to track tasks.
-  // We can remove the wrapper if InspectorInstrumentation returns a task id.
-  std::unique_ptr<WTF::Closure> task = WTF::Bind(
-      &RemotePlayback::NotifyInitialAvailability, WrapPersistent(this), id);
-  probe::AsyncTaskScheduled(GetExecutionContext(), "watchAvailabilityCallback",
-                            task.get());
-  TaskRunnerHelper::Get(TaskType::kMediaElementEvent, GetExecutionContext())
-      ->PostTask(BLINK_FROM_HERE,
-                 WTF::Bind(RunNotifyInitialAvailabilityTask,
-                           WrapPersistent(GetExecutionContext()),
-                           WTF::Passed(std::move(task))));
+  int id = WatchAvailabilityInternal(new AvailabilityCallbackWrapper(callback));
 
   // TODO(avayvod): Currently the availability is tracked for each media element
   // as soon as it's created, we probably want to limit that to when the
@@ -130,15 +110,12 @@
     return promise;
   }
 
-  auto iter = availability_callbacks_.find(id);
-  if (iter == availability_callbacks_.end()) {
+  if (!CancelWatchAvailabilityInternal(id)) {
     resolver->Reject(DOMException::Create(
         kNotFoundError, "A callback with the given id is not found."));
     return promise;
   }
 
-  availability_callbacks_.erase(iter);
-
   resolver->Resolve();
   return promise;
 }
@@ -200,13 +177,8 @@
     return promise;
   }
 
-  if (state_ == WebRemotePlaybackState::kDisconnected) {
-    prompt_promise_resolver_ = resolver;
-    media_element_->RequestRemotePlayback();
-  } else {
-    prompt_promise_resolver_ = resolver;
-    media_element_->RequestRemotePlaybackControl();
-  }
+  prompt_promise_resolver_ = resolver;
+  PromptInternal();
 
   return promise;
 }
@@ -220,13 +192,54 @@
          prompt_promise_resolver_;
 }
 
+void RemotePlayback::PromptInternal() {
+  if (state_ == WebRemotePlaybackState::kDisconnected)
+    media_element_->RequestRemotePlayback();
+  else
+    media_element_->RequestRemotePlaybackControl();
+}
+
+int RemotePlayback::WatchAvailabilityInternal(
+    AvailabilityCallbackWrapper* callback) {
+  int id;
+  do {
+    id = GetExecutionContext()->CircularSequentialID();
+  } while (!availability_callbacks_
+                .insert(id, TraceWrapperMember<AvailabilityCallbackWrapper>(
+                                this, callback))
+                .is_new_entry);
+
+  // Report the current availability via the callback.
+  // TODO(yuryu): Wrapping notifyInitialAvailability with WTF::Closure as
+  // InspectorInstrumentation requires a globally unique pointer to track tasks.
+  // We can remove the wrapper if InspectorInstrumentation returns a task id.
+  std::unique_ptr<WTF::Closure> task = WTF::Bind(
+      &RemotePlayback::NotifyInitialAvailability, WrapPersistent(this), id);
+  probe::AsyncTaskScheduled(GetExecutionContext(), "watchAvailabilityCallback",
+                            task.get());
+  TaskRunnerHelper::Get(TaskType::kMediaElementEvent, GetExecutionContext())
+      ->PostTask(BLINK_FROM_HERE,
+                 WTF::Bind(RunNotifyInitialAvailabilityTask,
+                           WrapPersistent(GetExecutionContext()),
+                           WTF::Passed(std::move(task))));
+  return id;
+}
+
+bool RemotePlayback::CancelWatchAvailabilityInternal(int id) {
+  auto iter = availability_callbacks_.find(id);
+  if (iter == availability_callbacks_.end())
+    return false;
+  availability_callbacks_.erase(iter);
+  return true;
+}
+
 void RemotePlayback::NotifyInitialAvailability(int callback_id) {
   // May not find the callback if the website cancels it fast enough.
   auto iter = availability_callbacks_.find(callback_id);
   if (iter == availability_callbacks_.end())
     return;
 
-  iter->value->call(this, RemotePlaybackAvailable());
+  iter->value->Run(this, RemotePlaybackAvailable());
 }
 
 void RemotePlayback::StateChanged(WebRemotePlaybackState state) {
@@ -278,7 +291,7 @@
     return;
 
   for (auto& callback : availability_callbacks_.Values())
-    callback->call(this, new_availability);
+    callback->Run(this, new_availability);
 }
 
 void RemotePlayback::PromptCancelled() {
@@ -315,9 +328,8 @@
 }
 
 DEFINE_TRACE_WRAPPERS(RemotePlayback) {
-  for (auto callback : availability_callbacks_.Values()) {
+  for (auto callback : availability_callbacks_.Values())
     visitor->TraceWrappers(callback);
-  }
   EventTargetWithInlineData::TraceWrappers(visitor);
 }
 
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
index 4b32800..7daca70 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
@@ -21,6 +21,7 @@
 
 namespace blink {
 
+class AvailabilityCallbackWrapper;
 class HTMLMediaElement;
 class RemotePlaybackAvailabilityCallback;
 class ScriptPromiseResolver;
@@ -63,6 +64,21 @@
 
   String state() const;
 
+  // The implementation of prompt(). Used by the native remote playback button.
+  void PromptInternal();
+
+  // The implementation of watchAvailability() and cancelWatchAvailability().
+  int WatchAvailabilityInternal(AvailabilityCallbackWrapper*);
+  bool CancelWatchAvailabilityInternal(int id);
+
+  WebRemotePlaybackState GetState() const { return state_; }
+
+  // WebRemotePlaybackClient implementation.
+  void StateChanged(WebRemotePlaybackState) override;
+  void AvailabilityChanged(WebRemotePlaybackAvailability) override;
+  void PromptCancelled() override;
+  bool RemotePlaybackAvailable() const override;
+
   // ScriptWrappable implementation.
   bool HasPendingActivity() const final;
 
@@ -76,6 +92,7 @@
  private:
   friend class V8RemotePlayback;
   friend class RemotePlaybackTest;
+  friend class MediaControlsImplTest;
 
   explicit RemotePlayback(HTMLMediaElement&);
 
@@ -83,15 +100,9 @@
   // Need a void() method to post it as a task.
   void NotifyInitialAvailability(int callback_id);
 
-  // WebRemotePlaybackClient implementation.
-  void StateChanged(WebRemotePlaybackState) override;
-  void AvailabilityChanged(WebRemotePlaybackAvailability) override;
-  void PromptCancelled() override;
-  bool RemotePlaybackAvailable() const override;
-
   WebRemotePlaybackState state_;
   WebRemotePlaybackAvailability availability_;
-  HeapHashMap<int, TraceWrapperMember<RemotePlaybackAvailabilityCallback>>
+  HeapHashMap<int, TraceWrapperMember<AvailabilityCallbackWrapper>>
       availability_callbacks_;
   Member<HTMLMediaElement> media_element_;
   Member<ScriptPromiseResolver> prompt_promise_resolver_;
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 36761aef..2823ceb 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -659,6 +659,10 @@
       name: "NetworkInformation",
       status: "stable",
     },
+    // Not a web exposed feature, enabled from the command line.
+    {
+      name: "NewRemotePlaybackPipeline",
+    },
     {
       name: "NotificationBadge",
       status: "stable",
@@ -999,7 +1003,7 @@
     {
       name: "WebAssemblyStreaming",
       status: "experimental",
-    }, 
+    },
     {
       name: "WebAuth",
       status: "experimental",
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
index 820bcb8e..b8b860da 100644
--- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -388,6 +388,10 @@
   RuntimeEnabledFeatures::setBackgroundVideoTrackOptimizationEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableNewRemotePlaybackPipeline(bool enable) {
+  RuntimeEnabledFeatures::setNewRemotePlaybackPipelineEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnableRemotePlaybackAPI(bool enable) {
   RuntimeEnabledFeatures::setRemotePlaybackEnabled(enable);
 }
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h
index 7271f4f..c697d90a 100644
--- a/third_party/WebKit/public/web/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -146,6 +146,7 @@
   BLINK_EXPORT static void EnableCanvas2dDynamicRenderingModeSwitching(bool);
   BLINK_EXPORT static void EnableSendBeaconThrowForBlobWithNonSimpleType(bool);
   BLINK_EXPORT static void EnableBackgroundVideoTrackOptimization(bool);
+  BLINK_EXPORT static void EnableNewRemotePlaybackPipeline(bool);
   BLINK_EXPORT static void EnableVideoFullscreenOrientationLock(bool);
   BLINK_EXPORT static void EnableVideoRotateToFullscreen(bool);
   BLINK_EXPORT static void EnableVideoFullscreenDetection(bool);
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 943e801..e14472e3 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -103349,6 +103349,7 @@
   <int value="-1798337879" label="enable-md-downloads"/>
   <int value="-1797739460" label="brotli-encoding:disabled"/>
   <int value="-1790227231" label="show-autofill-signatures"/>
+  <int value="-1784788154" label="NewRemotePlaybackPipeline:disabled"/>
   <int value="-1772172557" label="enable-osk-overscroll"/>
   <int value="-1767470652" label="out-of-process-pdf"/>
   <int value="-1751928267" label="disable-icon-ntp"/>
@@ -103665,6 +103666,7 @@
   <int value="-536289234" label="ssl-interstitial-v2-colorful"/>
   <int value="-535208779" label="enable-native-cups"/>
   <int value="-531810064" label="saveas-menu-label"/>
+  <int value="-531651776" label="NewRemotePlaybackPipeline:enabled"/>
   <int value="-528927088" label="AutofillCreditCardPopupLayout:disabled"/>
   <int value="-528149352" label="WebRtcUseEchoCanceller3:enabled"/>
   <int value="-519960638" label="enable-site-engagement-service"/>